diff --git a/DEPS b/DEPS
index e953138..d8e7776 100644
--- a/DEPS
+++ b/DEPS
@@ -194,11 +194,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': '7b4e43c52211f81843db2a9774e00c2a68774184',
+  'skia_revision': '6ec66b9d3863eb9b3d78246eb29119abe7775e41',
   # 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': '1e6fdb1b4e40b2e3d75d9ffae4dd13c9daa7b3ab',
+  'v8_revision': '8221db0d87ca9ffa6ccd81ab38f2ad0a19c51e00',
   # 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.
@@ -206,15 +206,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '465a912582bbe291786b0e009c81973ba46649a4',
+  'angle_revision': 'b8583bcc95fcde8c8204d3bab32a29a3db9ddc79',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '3121585acce20f5cc2074088563e3c1a076b8e48',
+  'swiftshader_revision': '8866a85cf02db536b9dbc07be496826eb7197fd2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'afd27509974add1b4e4a962be0a30583b1735dfe',
+  'pdfium_revision': '5a61ad5add2496ef935137d36ab0d82463da1d0e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -245,7 +245,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': 'a4434747558d872c55e55ce428019a8e15d222dc',
+  'freetype_revision': '3bb512bc9f621e1329927292d9ee7ba764549cae',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
@@ -257,7 +257,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': '5f3007bf80a7c889413ce90203810968e81241c4',
+  'catapult_revision': '9ef36d0c0fe8213efd4c8019aeac87182eac6972',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -265,7 +265,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '1b2c52bbfa5e8bdba70b8b2069ab1a615594d87f',
+  'devtools_frontend_revision': '85757b5481aff2945ca9f45c791ca1ef31b7ff13',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -301,7 +301,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '2c1ff230c26d67655e5b0ef27ca3c4371d7d5b3e',
+  'spv_tools_revision': 'bd2a9ea85210d3bb474bc5adb9ff4b0bb536b4fc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -313,11 +313,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': 'ffa19309ad086d9252f2c4562519c624b80d9ea7',
+  'shaderc_revision': '9eb2d25b67f159bcf88ad4e41beac81f5ae1fa91',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'db34c78910773b9a5b092bf53bf5232582f1310e',
+  'dawn_revision': '9585c468a280736de56851dda8bb01c47fc217de',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -352,7 +352,7 @@
   # revisions.
 
   # GN CIPD package version.
-  'gn_version': 'git_revision:b6203d186bff6b39ac25af6c1e80e1d3f96c949a',
+  'gn_version': 'git_revision:d585128cdaf3e6ff7bfd58641965e60c12618eb1',
 
   # Also, if you change these, update buildtools/DEPS too. Also update the
   # libc++ svn_revision in //buildtools/deps_revisions.gni.
@@ -856,7 +856,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '2cb780492f6027ade2729cc6503087e714ee17e7',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'bee7cd569a4f8e6a07a8ea94eeaeb9d17871e2e1',
       'condition': 'checkout_linux',
   },
 
@@ -876,7 +876,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '49735e227c7e1ae863f40e3502bb1bc76fd610f7',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '81923d6d2cc6d3b6fdb9a6c98d50d209576ebf5b',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1220,7 +1220,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '1783b3bd55acbe28e323a0c3db456fad62e7b566',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '3039024ba5b48681603706e86b0a8603d41b173a',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1323,7 +1323,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'B467c9t23JiW_6XGqhvHvtEKWSkrPS2xG_gho_gbAI4C',
+              'version': 'vvymFSkKtWKWNmfz0PL_0H8MD8V40P--A9aUfxfpF6QC',
           },
       ],
       'condition': 'checkout_android',
@@ -1448,7 +1448,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'afd1dcbde0407f4b104cad73ea82dead822d7e70',
+    Var('webrtc_git') + '/src.git' + '@' + '8fe932a5a3686ec21b8c6d5b0efcdc21d253f7a0',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 600c70a..2c11665 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -2354,6 +2354,7 @@
   local_scope = {}
   global_scope = {
       'Var': _VarImpl(local_scope).Lookup,
+      'Str': str,
   }
   exec contents in global_scope, local_scope
   return local_scope
@@ -3670,14 +3671,22 @@
     import os
 
     old_pydeps_data = self._LoadFile(pydeps_path).splitlines()
-    cmd = old_pydeps_data[1][1:].strip()
+    if old_pydeps_data:
+      cmd = old_pydeps_data[1][1:].strip()
+      old_contents = old_pydeps_data[2:]
+    else:
+      # A default cmd that should work in most cases (as long as pydeps filename
+      # matches the script name) so that PRESUBMIT.py does not crash if pydeps
+      # file is empty/new.
+      cmd = 'build/print_python_deps.py {} --root={} --output={}'.format(
+          pydeps_path[:-4], os.path.dirname(pydeps_path), pydeps_path)
+      old_contents = []
     env = dict(os.environ)
     env['PYTHONDONTWRITEBYTECODE'] = '1'
     new_pydeps_data = self._input_api.subprocess.check_output(
         cmd + ' --output ""', shell=True, env=env)
-    old_contents = old_pydeps_data[2:]
     new_contents = new_pydeps_data.splitlines()[2:]
-    if old_pydeps_data[2:] != new_pydeps_data.splitlines()[2:]:
+    if old_contents != new_contents:
       return cmd, '\n'.join(difflib.context_diff(old_contents, new_contents))
 
 
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc
index c3066a3..ae975a0d 100644
--- a/ash/app_list/views/apps_grid_view_unittest.cc
+++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "ash/app_list/app_list_metrics.h"
 #include "ash/app_list/model/app_list_folder_item.h"
@@ -1956,6 +1957,8 @@
   DISALLOW_COPY_AND_ASSIGN(AppsGridGapTest);
 };
 
+INSTANTIATE_TEST_SUITE_P(All, AppsGridGapTest, testing::Bool());
+
 TEST_P(AppsGridGapTest, MoveAnItemToNewEmptyPage) {
   const int kApps = 2;
   model_->PopulateApps(kApps);
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 8f91895e..8cbc7e4 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -31,6 +31,7 @@
 #include "ash/media/media_controller_impl.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
+#include "ash/public/cpp/login_accelerators.h"
 #include "ash/public/cpp/login_types.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shelf/shelf.h"
@@ -2098,25 +2099,29 @@
 }
 
 void LockContentsView::RegisterAccelerators() {
-  // Applies on login and lock:
-  accel_map_[ui::Accelerator(ui::VKEY_V, ui::EF_ALT_DOWN)] =
-      AcceleratorAction::kToggleSystemInfo;
-
-  // Login-only accelerators:
-  if (screen_type_ == LockScreen::ScreenType::kLogin) {
-    accel_map_[ui::Accelerator(ui::VKEY_I,
-                               ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)] =
-        AcceleratorAction::kShowFeedback;
-
+  for (size_t i = 0; i < kLoginAcceleratorDataLength; ++i) {
+    if (!kLoginAcceleratorData[i].global)
+      continue;
+    if ((screen_type_ == LockScreen::ScreenType::kLogin) &&
+        !(kLoginAcceleratorData[i].scope & kScopeLogin)) {
+      continue;
+    }
+    if ((screen_type_ == LockScreen::ScreenType::kLock) &&
+        !(kLoginAcceleratorData[i].scope & kScopeLock)) {
+      continue;
+    }
     // Show reset conflicts with rotate screen when --ash-dev-shortcuts is
     // passed. Favor --ash-dev-shortcuts since that is explicitly added.
-    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+    if (kLoginAcceleratorData[i].action ==
+            LoginAcceleratorAction::kShowResetScreen &&
+        base::CommandLine::ForCurrentProcess()->HasSwitch(
             switches::kAshDeveloperShortcuts)) {
-      accel_map_[ui::Accelerator(ui::VKEY_R, ui::EF_CONTROL_DOWN |
-                                                 ui::EF_SHIFT_DOWN |
-                                                 ui::EF_ALT_DOWN)] =
-          AcceleratorAction::kShowResetScreen;
+      continue;
     }
+
+    accel_map_[ui::Accelerator(kLoginAcceleratorData[i].keycode,
+                               kLoginAcceleratorData[i].modifiers)] =
+        kLoginAcceleratorData[i].action;
   }
 
   // Register the accelerators.
@@ -2126,15 +2131,15 @@
     controller->Register({item.first}, this);
 }
 
-void LockContentsView::PerformAction(AcceleratorAction action) {
+void LockContentsView::PerformAction(LoginAcceleratorAction action) {
   switch (action) {
-    case AcceleratorAction::kToggleSystemInfo:
+    case LoginAcceleratorAction::kToggleSystemInfo:
       ToggleSystemInfo();
       break;
-    case AcceleratorAction::kShowFeedback:
+    case LoginAcceleratorAction::kShowFeedback:
       Shell::Get()->login_screen_controller()->ShowFeedback();
       break;
-    case AcceleratorAction::kShowResetScreen:
+    case LoginAcceleratorAction::kShowResetScreen:
       Shell::Get()->login_screen_controller()->ShowResetScreen();
       break;
     default:
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 3887c60..6197c00 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -20,6 +20,7 @@
 #include "ash/login/ui/login_tooltip_view.h"
 #include "ash/login/ui/non_accessible_view.h"
 #include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
+#include "ash/public/cpp/login_accelerators.h"
 #include "ash/public/cpp/login_types.h"
 #include "ash/public/cpp/system_tray_focus_observer.h"
 #include "base/callback_forward.h"
@@ -118,12 +119,6 @@
     kExclusivePublicAccountExpandedView,
   };
 
-  enum class AcceleratorAction {
-    kToggleSystemInfo,
-    kShowFeedback,
-    kShowResetScreen,
-  };
-
   // Number of login attempts before a login dialog is shown. For example, if
   // this value is 4 then the user can submit their password 4 times, and on the
   // 4th bad attempt the login dialog is shown. This only applies to the login
@@ -392,7 +387,7 @@
   void RegisterAccelerators();
 
   // Performs the specified accelerator action.
-  void PerformAction(AcceleratorAction action);
+  void PerformAction(LoginAcceleratorAction action);
 
   // Check whether the view should display the system information based on all
   // factors including policy settings, channel and Alt-V accelerator.
@@ -487,7 +482,7 @@
   bool keyboard_shown_ = false;
 
   // Accelerators handled by login screen.
-  std::map<ui::Accelerator, AcceleratorAction> accel_map_;
+  std::map<ui::Accelerator, LoginAcceleratorAction> accel_map_;
 
   // Notifies Chrome when user activity is detected on the login screen so that
   // the auto-login timer can be reset.
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 5f88e1d..e1882c5e 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -154,6 +154,8 @@
     "locale_update_controller.h",
     "lock_screen_widget_factory.cc",
     "lock_screen_widget_factory.h",
+    "login_accelerators.cc",
+    "login_accelerators.h",
     "login_constants.h",
     "login_screen.cc",
     "login_screen.h",
diff --git a/ash/public/cpp/login_accelerators.cc b/ash/public/cpp/login_accelerators.cc
new file mode 100644
index 0000000..c65442b
--- /dev/null
+++ b/ash/public/cpp/login_accelerators.cc
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/public/cpp/login_accelerators.h"
+
+#include "base/stl_util.h"
+
+namespace ash {
+
+// clang-format off
+const LoginAcceleratorData kLoginAcceleratorData[] = {
+    {
+        kToggleSystemInfo,
+        ui::VKEY_V, ui::EF_ALT_DOWN,
+        true, kScopeOobe | kScopeLogin | kScopeLock,
+    }, {
+        kShowFeedback,
+        ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
+        true, kScopeOobe | kScopeLogin,
+    }, {
+        kShowResetScreen,
+        ui::VKEY_R, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN,
+        true, kScopeOobe | kScopeLogin,
+    }, {
+       kAppLaunchBailout,
+       ui::VKEY_S, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+       false, kScopeOobe | kScopeLogin,
+    }, {
+       kAppLaunchNetworkConfig,
+       ui::VKEY_N, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+       false, kScopeOobe | kScopeLogin,
+    }, {
+       kCancelScreenAction,
+       ui::VKEY_ESCAPE, ui::EF_NONE,
+       false, kScopeOobe | kScopeLogin,
+    }, {
+       kStartEnrollment,
+       ui::VKEY_E, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+       false, kScopeOobe,
+    }, {
+       kStartDemoMode,
+       ui::VKEY_D, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+       false, kScopeOobe,
+    }, {
+       kEnableDebugging,
+       ui::VKEY_X, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN,
+       false, kScopeOobe,
+    }, {
+       kEditDeviceRequisition,
+       ui::VKEY_D, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN,
+       false, kScopeOobe,
+    }, {
+       kDeviceRequisitionRemora,
+       ui::VKEY_H, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+       false, kScopeOobe,
+    }, {
+       kEnableConsumerKiosk,
+       ui::VKEY_K, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN,
+       false, kScopeOobe,
+    },
+};
+// clang-format on
+
+const size_t kLoginAcceleratorDataLength = base::size(kLoginAcceleratorData);
+
+}  // namespace ash
diff --git a/ash/public/cpp/login_accelerators.h b/ash/public/cpp/login_accelerators.h
new file mode 100644
index 0000000..350bd04
--- /dev/null
+++ b/ash/public/cpp/login_accelerators.h
@@ -0,0 +1,61 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_PUBLIC_CPP_LOGIN_ACCELERATORS_H_
+#define ASH_PUBLIC_CPP_LOGIN_ACCELERATORS_H_
+
+#include <stddef.h>
+
+#include "ash/public/cpp/ash_public_export.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/keyboard_codes.h"
+
+namespace ash {
+
+// Accelerator actions specific for out-of-box flow, login and lock screens.
+
+// Flags that define in which contexts accelerator should be enabled.
+enum LoginActionScope {
+  // Available during out-of-box flow.
+  kScopeOobe = 1 << 0,
+  // Available on the login screen.
+  kScopeLogin = 1 << 1,
+  // Available on the lock screen.
+  kScopeLock = 1 << 2,
+};
+
+enum LoginAcceleratorAction {
+  kToggleSystemInfo,
+  kShowFeedback,
+  kShowResetScreen,
+  kAppLaunchBailout,
+  kAppLaunchNetworkConfig,
+  kCancelScreenAction,
+  kStartEnrollment,
+  kEnableConsumerKiosk,
+  kEnableDebugging,
+  kEditDeviceRequisition,
+  kDeviceRequisitionRemora,
+  kStartDemoMode,
+};
+
+struct LoginAcceleratorData {
+  LoginAcceleratorAction action;
+  ui::KeyboardCode keycode;
+  // Combination of ui::EventFlags.
+  int modifiers;
+  // Defines if accelerator will be registered in AcceleratorController (|true|)
+  // or only for login/lock dialog view (|false|).
+  bool global;
+  // Combination of LoginActionScope flags.
+  int scope;
+};
+
+// Accelerators handled by OOBE / Login components.
+ASH_PUBLIC_EXPORT extern const LoginAcceleratorData kLoginAcceleratorData[];
+ASH_PUBLIC_EXPORT extern const size_t kLoginAcceleratorDataLength;
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_LOGIN_ACCELERATORS_H_
diff --git a/base/BUILD.gn b/base/BUILD.gn
index dc6641c..40aa06e 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3686,8 +3686,6 @@
       "test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java",
       "test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java",
       "test/android/javatests/src/org/chromium/base/test/BundleTestRule.java",
-      "test/android/javatests/src/org/chromium/base/test/DestroyActivitiesRule.java",
-      "test/android/javatests/src/org/chromium/base/test/LifetimeAssertRule.java",
       "test/android/javatests/src/org/chromium/base/test/LoadNative.java",
       "test/android/javatests/src/org/chromium/base/test/ReachedCodeProfiler.java",
       "test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java",
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
index a28e96b..47fd5c25 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -12,7 +12,13 @@
 
 base::ThreadSafePartitionRoot& Allocator() {
   static base::NoDestructor<base::ThreadSafePartitionRoot> allocator;
-  allocator->Init();
+  allocator->Init(true /* enable_tag_pointers */);
+  return *allocator;
+}
+
+base::ThreadSafePartitionRoot& AlignedAllocator() {
+  static base::NoDestructor<base::ThreadSafePartitionRoot> allocator;
+  allocator->Init(false /* enable_tag_pointers */);
   return *allocator;
 }
 
@@ -33,7 +39,7 @@
                         size_t alignment,
                         size_t size,
                         void* context) {
-  return Allocator().AlignedAlloc(alignment, size);
+  return AlignedAllocator().AlignedAlloc(alignment, size);
 }
 
 void* PartitionRealloc(const AllocatorDispatch*,
@@ -44,14 +50,14 @@
 }
 
 void PartitionFree(const AllocatorDispatch*, void* address, void* context) {
-  Allocator().Free(address);
+  base::ThreadSafePartitionRoot::Free(address);
 }
 
 size_t PartitionGetSizeEstimate(const AllocatorDispatch*,
                                 void* address,
                                 void* context) {
   // TODO(lizeb): Returns incorrect values for aligned allocations.
-  return base::PartitionAllocGetSize<base::internal::ThreadSafe>(address);
+  return base::ThreadSafePartitionRoot::GetSizeFromPointer(address);
 }
 
 }  // namespace
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index 664d1e5..69a3e97 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -192,7 +192,7 @@
 }
 
 template <bool thread_safe>
-void PartitionRoot<thread_safe>::InitSlowPath() {
+void PartitionRoot<thread_safe>::InitSlowPath(bool enable_tag_pointers) {
   ScopedGuard guard{lock_};
 
   if (initialized.load(std::memory_order_relaxed))
@@ -204,6 +204,8 @@
     internal::PartitionAddressSpace::Init();
 #endif
 
+  tag_pointers = enable_tag_pointers;
+
   // We mark the sentinel bucket/page as free to make sure it is skipped by our
   // logic to find a new active page.
   //
@@ -302,8 +304,7 @@
     size_t raw_size) {
   PA_DCHECK(page->bucket->is_direct_mapped());
 
-  raw_size = internal::PartitionSizeAdjustAdd(raw_size);
-
+  raw_size = internal::PartitionSizeAdjustAdd(tag_pointers, raw_size);
   // Note that the new size might be a bucketed size; this function is called
   // whenever we're reallocating a direct mapped allocation.
   size_t new_size = Bucket::get_direct_map_size(raw_size);
@@ -388,8 +389,8 @@
         &actual_old_size, ptr);
   }
   if (LIKELY(!overridden)) {
-    auto* page =
-        Page::FromPointer(internal::PartitionPointerAdjustSubtract(ptr));
+    auto* page = Page::FromPointer(
+        internal::PartitionPointerAdjustSubtract(tag_pointers, ptr));
     bool success = false;
     {
       internal::ScopedGuard<thread_safe> guard{lock_};
@@ -412,7 +413,7 @@
     }
 
     const size_t actual_new_size = ActualSize(new_size);
-    actual_old_size = PartitionAllocGetSize<thread_safe>(ptr);
+    actual_old_size = GetSize(ptr);
 
     // TODO: note that tcmalloc will "ignore" a downsizing realloc() unless the
     // new size is a significant percentage smaller. We could do the same if we
@@ -421,7 +422,8 @@
       // Trying to allocate a block of size |new_size| would give us a block of
       // the same size as the one we've already got, so re-use the allocation
       // after updating statistics (and cookies, if present).
-      size_t new_raw_size = internal::PartitionSizeAdjustAdd(new_size);
+      size_t new_raw_size =
+          internal::PartitionSizeAdjustAdd(tag_pointers, new_size);
       page->set_raw_size(new_raw_size);
 #if DCHECK_IS_ON()
       // Write a new trailing cookie when it is possible to keep track of
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h
index c92851f..0ceb4a73 100644
--- a/base/allocator/partition_allocator/partition_alloc.h
+++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -167,26 +167,30 @@
 
 namespace internal {
 
-ALWAYS_INLINE void* PartitionPointerAdjustSubtract(void* ptr) {
-  ptr = PartitionTagPointerAdjustSubtract(ptr);
+ALWAYS_INLINE void* PartitionPointerAdjustSubtract(bool use_tag, void* ptr) {
+  if (use_tag)
+    ptr = PartitionTagPointerAdjustSubtract(ptr);
   ptr = PartitionCookiePointerAdjustSubtract(ptr);
   return ptr;
 }
 
-ALWAYS_INLINE void* PartitionPointerAdjustAdd(void* ptr) {
-  ptr = PartitionTagPointerAdjustAdd(ptr);
+ALWAYS_INLINE void* PartitionPointerAdjustAdd(bool use_tag, void* ptr) {
+  if (use_tag)
+    ptr = PartitionTagPointerAdjustAdd(ptr);
   ptr = PartitionCookiePointerAdjustAdd(ptr);
   return ptr;
 }
 
-ALWAYS_INLINE size_t PartitionSizeAdjustAdd(size_t size) {
-  size = PartitionTagSizeAdjustAdd(size);
+ALWAYS_INLINE size_t PartitionSizeAdjustAdd(bool use_tag, size_t size) {
+  if (use_tag)
+    size = PartitionTagSizeAdjustAdd(size);
   size = PartitionCookieSizeAdjustAdd(size);
   return size;
 }
 
-ALWAYS_INLINE size_t PartitionSizeAdjustSubtract(size_t size) {
-  size = PartitionTagSizeAdjustSubtract(size);
+ALWAYS_INLINE size_t PartitionSizeAdjustSubtract(bool use_tag, size_t size) {
+  if (use_tag)
+    size = PartitionTagSizeAdjustSubtract(size);
   size = PartitionCookieSizeAdjustSubtract(size);
   return size;
 }
@@ -384,14 +388,16 @@
   using ScopedGuard = internal::ScopedGuard<thread_safe>;
 
   internal::MaybeSpinLock<thread_safe> lock_;
-  size_t total_size_of_committed_pages = 0;
-  size_t total_size_of_super_pages = 0;
-  size_t total_size_of_direct_mapped_pages = 0;
   // Invariant: total_size_of_committed_pages <=
   //                total_size_of_super_pages +
   //                total_size_of_direct_mapped_pages.
-  unsigned num_buckets = 0;
-  unsigned max_allocation = 0;
+  size_t total_size_of_committed_pages = 0;
+  size_t total_size_of_super_pages = 0;
+  size_t total_size_of_direct_mapped_pages = 0;
+  // TODO(bartekn): Consider kPartitionTagSize/0 instead of true/false, so that
+  // we can just add or subtract the size instead of having an if branch on the
+  // hot paths.
+  bool tag_pointers;
   // Atomic as initialization can be concurrent.
   std::atomic<bool> initialized = {};
   char* next_super_page = nullptr;
@@ -429,11 +435,11 @@
   //
   // Moving it a layer lower couples PartitionRoot and PartitionBucket, but
   // preserves the layering of the includes.
-  ALWAYS_INLINE void Init() {
+  ALWAYS_INLINE void Init(bool enable_tag_pointers) {
     if (LIKELY(initialized.load(std::memory_order_relaxed)))
       return;
 
-    InitSlowPath();
+    InitSlowPath(enable_tag_pointers);
   }
 
   ALWAYS_INLINE static bool IsValidPage(Page* page);
@@ -472,8 +478,10 @@
                               void* ptr,
                               size_t new_size,
                               const char* type_name);
-  ALWAYS_INLINE void Free(void* ptr);
+  ALWAYS_INLINE static void Free(void* ptr);
 
+  ALWAYS_INLINE static size_t GetSizeFromPointer(void* ptr);
+  ALWAYS_INLINE size_t GetSize(void* ptr) const;
   ALWAYS_INLINE size_t ActualSize(size_t size);
 
   // Frees memory from this partition, if possible, by decommitting pages.
@@ -487,7 +495,7 @@
   internal::PartitionBucket<thread_safe>* SizeToBucket(size_t size) const;
 
  private:
-  void InitSlowPath();
+  void InitSlowPath(bool enable_tagged_pointers);
   ALWAYS_INLINE void* AllocFromBucket(Bucket* bucket, int flags, size_t size)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
   bool ReallocDirectMappedInPlace(internal::PartitionPage<thread_safe>* page,
@@ -550,9 +558,9 @@
   // Note, empty space occurs if the slot size is larger than needed to
   // accommodate the request.
   size_t size_with_no_extras =
-      internal::PartitionSizeAdjustSubtract(new_slot_size);
+      internal::PartitionSizeAdjustSubtract(tag_pointers, new_slot_size);
   // The value given to the application is just after the tag and cookie.
-  ret = internal::PartitionPointerAdjustAdd(ret);
+  ret = internal::PartitionPointerAdjustAdd(tag_pointers, ret);
 
 #if DCHECK_IS_ON() && !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
   // Surround the region with 2 cookies.
@@ -571,20 +579,21 @@
     memset(ret, 0, size_with_no_extras);
   }
 
-  // TODO(tasak): initialize tag randomly. Temporarily use
-  // kTagTemporaryInitialValue to initialize the tag.
-  internal::PartitionTagSetValue(ret, internal::kTagTemporaryInitialValue);
+  if (tag_pointers) {
+    // TODO(tasak): initialize tag randomly. Temporarily use
+    // kTagTemporaryInitialValue to initialize the tag.
+    internal::PartitionTagSetValue(ret, internal::kTagTemporaryInitialValue);
+  }
 
   return ret;
 }
 
+// static
 template <bool thread_safe>
 ALWAYS_INLINE void PartitionRoot<thread_safe>::Free(void* ptr) {
 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
   free(ptr);
 #else
-  PA_DCHECK(initialized);
-
   if (UNLIKELY(!ptr))
     return;
 
@@ -593,16 +602,19 @@
     if (PartitionAllocHooks::FreeOverrideHookIfEnabled(ptr))
       return;
   }
-
-  // TODO(tasak): clear partition tag. Temporarily set the tag to be 0.
-  internal::PartitionTagSetValue(ptr, 0);
-  ptr = internal::PartitionPointerAdjustSubtract(ptr);
-  Page* page = Page::FromPointer(ptr);
+  // No check as the pointer hasn't been adjusted yet.
+  Page* page = Page::FromPointerNoAlignmentCheck(ptr);
   // TODO(palmer): See if we can afford to make this a CHECK.
   PA_DCHECK(IsValidPage(page));
+  auto* root = PartitionRoot<thread_safe>::FromPage(page);
+  if (root->tag_pointers) {
+    // TODO(tasak): clear partition tag. Temporarily set the tag to be 0.
+    internal::PartitionTagSetValue(ptr, 0);
+  }
+  ptr = internal::PartitionPointerAdjustSubtract(root->tag_pointers, ptr);
   internal::DeferredUnmap deferred_unmap;
   {
-    ScopedGuard guard{lock_};
+    ScopedGuard guard{root->lock_};
     deferred_unmap = page->Free(ptr);
   }
   deferred_unmap.Run();
@@ -677,14 +689,6 @@
 #endif
 }
 
-ALWAYS_INLINE bool PartitionAllocSupportsGetSize() {
-#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
-  return false;
-#else
-  return true;
-#endif
-}
-
 namespace internal {
 // Gets the PartitionPage object for the first partition page of the slot span
 // that contains |ptr|. It's used with intention to do obtain the slot size.
@@ -695,7 +699,6 @@
 PartitionAllocGetPageForSize(void* ptr) {
   // No need to lock here. Only |ptr| being freed by another thread could
   // cause trouble, and the caller is responsible for that not happening.
-  PA_DCHECK(PartitionAllocSupportsGetSize());
   auto* page =
       internal::PartitionPage<thread_safe>::FromPointerNoAlignmentCheck(ptr);
   // This PA_DCHECK has been temporarily commented out, because CheckedPtr2Impl
@@ -709,15 +712,24 @@
 }
 }  // namespace internal
 
+// static
+template <bool thread_safe>
+ALWAYS_INLINE size_t PartitionRoot<thread_safe>::GetSizeFromPointer(void* ptr) {
+  Page* page = Page::FromPointerNoAlignmentCheck(ptr);
+  auto* root = PartitionRoot<thread_safe>::FromPage(page);
+  return root->GetSize(ptr);
+}
+
 // Gets the size of the allocated slot that contains |ptr|, adjusted for cookie
 // (if any).
 // CAUTION! For direct-mapped allocation, |ptr| has to be within the first
 // partition page.
 template <bool thread_safe>
-ALWAYS_INLINE size_t PartitionAllocGetSize(void* ptr) {
-  ptr = internal::PartitionPointerAdjustSubtract(ptr);
+ALWAYS_INLINE size_t PartitionRoot<thread_safe>::GetSize(void* ptr) const {
+  ptr = internal::PartitionPointerAdjustSubtract(tag_pointers, ptr);
   auto* page = internal::PartitionAllocGetPageForSize<thread_safe>(ptr);
-  size_t size = internal::PartitionSizeAdjustSubtract(page->bucket->slot_size);
+  size_t size = internal::PartitionSizeAdjustSubtract(tag_pointers,
+                                                      page->bucket->slot_size);
   return size;
 }
 
@@ -728,7 +740,12 @@
 template <bool thread_safe>
 ALWAYS_INLINE size_t PartitionAllocGetSlotOffset(void* ptr) {
   PA_DCHECK(IsManagedByPartitionAllocNormalBuckets(ptr));
-  ptr = internal::PartitionPointerAdjustSubtract(ptr);
+  // The only allocations that don't use tag are allocated outside of GigaCage,
+  // hence we'd never get here in the use_tag=false case.
+  // TODO(bartekn): Add a DCHECK(page->root->tag_pointers) to assert this, once
+  // we figure out the thread-safety variant mismatch problem (see the comment
+  // in PartitionAllocGetPageForSize for the problem description).
+  ptr = internal::PartitionPointerAdjustSubtract(true /* use_tag */, ptr);
   auto* page = internal::PartitionAllocGetPageForSize<thread_safe>(ptr);
   size_t slot_size = page->bucket->slot_size;
 
@@ -787,7 +804,7 @@
     }
   }
   size_t requested_size = size;
-  size = internal::PartitionSizeAdjustAdd(size);
+  size = internal::PartitionSizeAdjustAdd(tag_pointers, size);
 #if ENABLE_TAG_FOR_CHECKED_PTR2
   PA_CHECK(size >= requested_size);
 #endif
@@ -809,6 +826,10 @@
 template <bool thread_safe>
 ALWAYS_INLINE void* PartitionRoot<thread_safe>::AlignedAlloc(size_t alignment,
                                                              size_t size) {
+  // Aligned allocation support relies on the natural alignment guarantees of
+  // PartitionAlloc. Since cookies and tags are layered on top of
+  // PartitionAlloc, they change the guarantees. As a consequence, forbid both.
+  PA_DCHECK(!tag_pointers);
 #if ENABLE_PARTITION_ALLOC_COOKIES
   CHECK(false) << "Aligned allocations do not work with cookies";
   return nullptr;
@@ -865,7 +886,7 @@
   return size;
 #else
   PA_DCHECK(PartitionRoot<thread_safe>::initialized);
-  size = internal::PartitionSizeAdjustAdd(size);
+  size = internal::PartitionSizeAdjustAdd(tag_pointers, size);
   auto* bucket = SizeToBucket(size);
   if (LIKELY(!bucket->is_direct_mapped())) {
     size = bucket->slot_size;
@@ -874,7 +895,7 @@
   } else {
     size = Bucket::get_direct_map_size(size);
   }
-  size = internal::PartitionSizeAdjustSubtract(size);
+  size = internal::PartitionSizeAdjustSubtract(tag_pointers, size);
   return size;
 #endif
 }
@@ -889,7 +910,7 @@
   }
 
   void init() {
-    partition_root_.Init();
+    partition_root_.Init(true);
     PartitionAllocMemoryReclaimer::Instance()->RegisterPartition(
         &partition_root_);
   }
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 8d30802..1ddbf408 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -179,9 +179,9 @@
       void* ptr = allocator.root()->Alloc(size, type_name);
       EXPECT_TRUE(ptr);
       if (!i)
-        first = PartitionPointerAdjustSubtract(ptr);
+        first = PartitionPointerAdjustSubtract(true, ptr);
       else if (i == num_slots - 1)
-        last = PartitionPointerAdjustSubtract(ptr);
+        last = PartitionPointerAdjustSubtract(true, ptr);
     }
     EXPECT_EQ(PartitionRoot<ThreadSafe>::Page::FromPointer(first),
               PartitionRoot<ThreadSafe>::Page::FromPointer(last));
@@ -202,7 +202,7 @@
     for (size_t i = 0; i < kMaxFreeableSpans; ++i) {
       void* ptr = allocator.root()->Alloc(size, type_name);
       auto* page = PartitionRoot<base::internal::ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr));
+          PartitionPointerAdjustSubtract(true, ptr));
       auto* bucket = page->bucket;
       EXPECT_EQ(1, bucket->active_pages_head->num_allocated_slots);
       allocator.root()->Free(ptr);
@@ -736,7 +736,7 @@
   // Should be freeable at this point.
   PartitionRoot<ThreadSafe>::Page* page =
       PartitionRoot<ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr));
+          PartitionPointerAdjustSubtract(true, ptr));
   EXPECT_NE(-1, page->empty_cache_index);
   allocator.root()->Free(ptr2);
 
@@ -755,10 +755,10 @@
   EXPECT_TRUE(ptr4);
 
   page = PartitionPage<base::internal::ThreadSafe>::FromPointer(
-      PartitionPointerAdjustSubtract(ptr));
+      PartitionPointerAdjustSubtract(true, ptr));
   PartitionRoot<ThreadSafe>::Page* page2 =
       PartitionRoot<ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr3));
+          PartitionPointerAdjustSubtract(true, ptr3));
   EXPECT_NE(page, page2);
 
   allocator.root()->Free(ptr);
@@ -816,14 +816,12 @@
   void* ptr;
   size_t requested_size, actual_size, predicted_size;
 
-  EXPECT_TRUE(PartitionAllocSupportsGetSize());
-
   // Allocate something small.
   requested_size = 511 - kExtraAllocSize;
   predicted_size = allocator.root()->ActualSize(requested_size);
   ptr = allocator.root()->Alloc(requested_size, type_name);
   EXPECT_TRUE(ptr);
-  actual_size = PartitionAllocGetSize<ThreadSafe>(ptr);
+  actual_size = allocator.root()->GetSize(ptr);
   EXPECT_EQ(predicted_size, actual_size);
   EXPECT_LT(requested_size, actual_size);
 #if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
@@ -849,7 +847,7 @@
   predicted_size = allocator.root()->ActualSize(requested_size);
   ptr = allocator.root()->Alloc(requested_size, type_name);
   EXPECT_TRUE(ptr);
-  actual_size = PartitionAllocGetSize<ThreadSafe>(ptr);
+  actual_size = allocator.root()->GetSize(ptr);
   EXPECT_EQ(predicted_size, actual_size);
   EXPECT_EQ(requested_size, actual_size);
 #if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
@@ -876,7 +874,7 @@
   predicted_size = allocator.root()->ActualSize(requested_size);
   ptr = allocator.root()->Alloc(requested_size, type_name);
   EXPECT_TRUE(ptr);
-  actual_size = PartitionAllocGetSize<ThreadSafe>(ptr);
+  actual_size = allocator.root()->GetSize(ptr);
   EXPECT_EQ(predicted_size, actual_size);
   EXPECT_EQ(requested_size + kSystemPageSize, actual_size);
 #if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
@@ -902,7 +900,7 @@
     predicted_size = allocator.root()->ActualSize(requested_size);
     ptr = allocator.root()->Alloc(requested_size, type_name);
     EXPECT_TRUE(ptr);
-    actual_size = PartitionAllocGetSize<ThreadSafe>(ptr);
+    actual_size = allocator.root()->GetSize(ptr);
     EXPECT_EQ(predicted_size, actual_size);
     EXPECT_LT(requested_size, actual_size);
     // Unlike above, don't test for PartitionAllocGetSlotOffset. Such large
@@ -938,7 +936,7 @@
   for (size_t i = 0; i < num_slots; ++i) {
     char* ptr = static_cast<char*>(ptrs[i]);
     for (size_t offset = 0; offset < requested_size; offset += 13) {
-      EXPECT_EQ(PartitionAllocGetSize<ThreadSafe>(ptr), requested_size);
+      EXPECT_EQ(allocator.root()->GetSize(ptr), requested_size);
       EXPECT_EQ(PartitionAllocGetSlotOffset<ThreadSafe>(ptr + offset), offset);
       // TODO(bartekn): Remove when CheckedPtr2Impl no longer calls mismatched
       // vartiant.
@@ -957,11 +955,11 @@
   memset(ptr, 'A', kTestAllocSize);
   PartitionRoot<ThreadSafe>::Page* page =
       PartitionRoot<ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr));
+          PartitionPointerAdjustSubtract(true, ptr));
   // realloc(ptr, 0) should be equivalent to free().
   void* ptr2 = allocator.root()->Realloc(ptr, 0, type_name);
   EXPECT_EQ(nullptr, ptr2);
-  EXPECT_EQ(PartitionPointerAdjustSubtract(ptr), page->freelist_head);
+  EXPECT_EQ(PartitionPointerAdjustSubtract(true, ptr), page->freelist_head);
 
   // Test that growing an allocation with realloc() copies everything from the
   // old allocation.
@@ -994,19 +992,17 @@
   // Test that shrinking a direct mapped allocation happens in-place.
   size = kGenericMaxBucketed + 16 * kSystemPageSize;
   ptr = allocator.root()->Alloc(size, type_name);
-  size_t actual_size = PartitionAllocGetSize<ThreadSafe>(ptr);
+  size_t actual_size = allocator.root()->GetSize(ptr);
   ptr2 = allocator.root()->Realloc(
       ptr, kGenericMaxBucketed + 8 * kSystemPageSize, type_name);
   EXPECT_EQ(ptr, ptr2);
-  EXPECT_EQ(actual_size - 8 * kSystemPageSize,
-            PartitionAllocGetSize<ThreadSafe>(ptr2));
+  EXPECT_EQ(actual_size - 8 * kSystemPageSize, allocator.root()->GetSize(ptr2));
 
   // Test that a previously in-place shrunk direct mapped allocation can be
   // expanded up again within its original size.
   ptr = allocator.root()->Realloc(ptr2, size - kSystemPageSize, type_name);
   EXPECT_EQ(ptr2, ptr);
-  EXPECT_EQ(actual_size - kSystemPageSize,
-            PartitionAllocGetSize<ThreadSafe>(ptr));
+  EXPECT_EQ(actual_size - kSystemPageSize, allocator.root()->GetSize(ptr));
 
   // Test that a direct mapped allocation is performed not in-place when the
   // new size is small enough.
@@ -1029,7 +1025,7 @@
 
   PartitionRoot<ThreadSafe>::Page* page =
       PartitionRoot<ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr));
+          PartitionPointerAdjustSubtract(true, ptr));
   size_t total_slots =
       (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) /
       (big_size + kExtraAllocSize);
@@ -1064,7 +1060,7 @@
 
   PartitionRoot<ThreadSafe>::Page* page2 =
       PartitionRoot<ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr5));
+          PartitionPointerAdjustSubtract(true, ptr5));
   EXPECT_EQ(1, page2->num_allocated_slots);
 
   // Churn things a little whilst there's a partial page freelist.
@@ -1093,7 +1089,7 @@
   ptr = allocator.root()->Alloc(medium_size, type_name);
   EXPECT_TRUE(ptr);
   page = PartitionRoot<ThreadSafe>::Page::FromPointer(
-      PartitionPointerAdjustSubtract(ptr));
+      PartitionPointerAdjustSubtract(true, ptr));
   EXPECT_EQ(1, page->num_allocated_slots);
   total_slots =
       (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) /
@@ -1112,7 +1108,7 @@
   ptr = allocator.root()->Alloc(small_size, type_name);
   EXPECT_TRUE(ptr);
   page = PartitionRoot<ThreadSafe>::Page::FromPointer(
-      PartitionPointerAdjustSubtract(ptr));
+      PartitionPointerAdjustSubtract(true, ptr));
   EXPECT_EQ(1, page->num_allocated_slots);
   total_slots =
       (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) /
@@ -1132,7 +1128,7 @@
   ptr = allocator.root()->Alloc(very_small_size, type_name);
   EXPECT_TRUE(ptr);
   page = PartitionRoot<ThreadSafe>::Page::FromPointer(
-      PartitionPointerAdjustSubtract(ptr));
+      PartitionPointerAdjustSubtract(true, ptr));
   EXPECT_EQ(1, page->num_allocated_slots);
   total_slots =
       (page->bucket->num_system_pages_per_slot_span * kSystemPageSize) /
@@ -1152,7 +1148,7 @@
   ptr = allocator.root()->Alloc(page_and_a_half_size, type_name);
   EXPECT_TRUE(ptr);
   page = PartitionRoot<ThreadSafe>::Page::FromPointer(
-      PartitionPointerAdjustSubtract(ptr));
+      PartitionPointerAdjustSubtract(true, ptr));
   EXPECT_EQ(1, page->num_allocated_slots);
   EXPECT_TRUE(page->freelist_head);
   total_slots =
@@ -1166,7 +1162,7 @@
   ptr = allocator.root()->Alloc(pageSize, type_name);
   EXPECT_TRUE(ptr);
   page = PartitionRoot<ThreadSafe>::Page::FromPointer(
-      PartitionPointerAdjustSubtract(ptr));
+      PartitionPointerAdjustSubtract(true, ptr));
   EXPECT_EQ(1, page->num_allocated_slots);
   EXPECT_TRUE(page->freelist_head);
   total_slots =
@@ -1190,7 +1186,7 @@
   EXPECT_NE(page2, bucket->active_pages_head);
   PartitionRoot<ThreadSafe>::Page* page =
       PartitionRoot<ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr));
+          PartitionPointerAdjustSubtract(true, ptr));
   EXPECT_EQ(1, page->num_allocated_slots);
 
   // Work out a pointer into page2 and free it; and then page1 and free it.
@@ -1341,7 +1337,7 @@
   EXPECT_TRUE(ptr);
   PartitionRoot<ThreadSafe>::Page* page =
       PartitionRoot<ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr));
+          PartitionPointerAdjustSubtract(true, ptr));
   EXPECT_EQ(nullptr, bucket->empty_pages_head);
   EXPECT_EQ(1, page->num_allocated_slots);
   size_t expected_committed_size = kPartitionPageSize;
@@ -1393,10 +1389,10 @@
 
   PartitionPage<base::internal::ThreadSafe>* page =
       PartitionPage<base::internal::ThreadSafe>::FromPointer(
-          PartitionPointerAdjustSubtract(ptr));
+          PartitionPointerAdjustSubtract(true, ptr));
   PartitionPage<base::internal::ThreadSafe>* page2 =
       PartitionPage<base::internal::ThreadSafe>::FromPointer(
-          PartitionPointerAdjustSubtract(ptr2));
+          PartitionPointerAdjustSubtract(true, ptr2));
   PartitionBucket<base::internal::ThreadSafe>* bucket = page->bucket;
 
   EXPECT_EQ(nullptr, bucket->empty_pages_head);
@@ -1909,13 +1905,13 @@
 
   PartitionPage<base::internal::ThreadSafe>* page1 =
       PartitionPage<base::internal::ThreadSafe>::FromPointer(
-          PartitionPointerAdjustSubtract(ptr1));
+          PartitionPointerAdjustSubtract(true, ptr1));
   PartitionPage<base::internal::ThreadSafe>* page2 =
       PartitionPage<base::internal::ThreadSafe>::FromPointer(
-          PartitionPointerAdjustSubtract(ptr3));
+          PartitionPointerAdjustSubtract(true, ptr3));
   PartitionPage<base::internal::ThreadSafe>* page3 =
       PartitionPage<base::internal::ThreadSafe>::FromPointer(
-          PartitionPointerAdjustSubtract(ptr6));
+          PartitionPointerAdjustSubtract(true, ptr6));
   EXPECT_NE(page1, page2);
   EXPECT_NE(page2, page3);
   PartitionBucket<base::internal::ThreadSafe>* bucket = page1->bucket;
@@ -1957,7 +1953,7 @@
     allocator.root()->Free(ptr2);
     PartitionPage<base::internal::ThreadSafe>* page =
         PartitionPage<base::internal::ThreadSafe>::FromPointer(
-            PartitionPointerAdjustSubtract(ptr1));
+            PartitionPointerAdjustSubtract(true, ptr1));
     EXPECT_EQ(2u, page->num_unprovisioned_slots);
     {
       MockPartitionStatsDumper dumper;
@@ -2149,7 +2145,7 @@
     ptr1[kSystemPageSize * 3] = 'A';
     PartitionPage<base::internal::ThreadSafe>* page =
         PartitionPage<base::internal::ThreadSafe>::FromPointer(
-            PartitionPointerAdjustSubtract(ptr1));
+            PartitionPointerAdjustSubtract(true, ptr1));
     allocator.root()->Free(ptr2);
     allocator.root()->Free(ptr4);
     allocator.root()->Free(ptr1);
@@ -2215,7 +2211,7 @@
     ptr1[kSystemPageSize * 3] = 'A';
     PartitionPage<base::internal::ThreadSafe>* page =
         PartitionPage<base::internal::ThreadSafe>::FromPointer(
-            PartitionPointerAdjustSubtract(ptr1));
+            PartitionPointerAdjustSubtract(true, ptr1));
     allocator.root()->Free(ptr4);
     allocator.root()->Free(ptr3);
     EXPECT_EQ(0u, page->num_unprovisioned_slots);
@@ -2436,7 +2432,7 @@
     EXPECT_EQ(reinterpret_cast<uintptr_t>(ptr3) % fundamental_alignment,
               static_cast<uintptr_t>(0));
 
-    EXPECT_EQ(PartitionAllocGetSize<ThreadSafe>(ptr) % fundamental_alignment,
+    EXPECT_EQ(allocator.root()->GetSize(ptr) % fundamental_alignment,
               static_cast<uintptr_t>(0));
 
     allocator.root()->Free(ptr);
@@ -2474,7 +2470,7 @@
 
   PartitionRoot<ThreadSafe>::Page* page =
       PartitionRoot<ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr1));
+          PartitionPointerAdjustSubtract(true, ptr1));
   EXPECT_TRUE(page);
 
   char* char_ptr1 = reinterpret_cast<char*>(ptr1);
@@ -2532,7 +2528,7 @@
 
   PartitionRoot<ThreadSafe>::Page* page =
       PartitionRoot<ThreadSafe>::Page::FromPointer(
-          PartitionPointerAdjustSubtract(ptr1));
+          PartitionPointerAdjustSubtract(true, ptr1));
   EXPECT_TRUE(page);
 
   constexpr PartitionTag kTag1 = 0xBADA;
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index f73a43e..85cf31bb 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -47,7 +47,9 @@
   map_size &= kPageAllocationGranularityBaseMask;
 
   char* ptr = nullptr;
-  if (IsPartitionAllocGigaCageEnabled()) {
+  // Allocate outside of GigaCage if tags aren't used. CheckedPtr uses
+  // a GigaCage check to determine the tag existence.
+  if (root->tag_pointers && IsPartitionAllocGigaCageEnabled()) {
 #if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
     ptr = internal::AddressPoolManager::GetInstance()->Alloc(GetDirectMapPool(),
                                                              map_size);
@@ -245,7 +247,9 @@
   // architectures.
   char* requested_address = root->next_super_page;
   char* super_page = nullptr;
-  if (IsPartitionAllocGigaCageEnabled()) {
+  // Allocate outside of GigaCage if tags aren't used. CheckedPtr uses
+  // a GigaCage check to determine the tag existence.
+  if (root->tag_pointers && IsPartitionAllocGigaCageEnabled()) {
 #if defined(ARCH_CPU_64_BITS) && !defined(OS_NACL)
     super_page = AddressPoolManager::GetInstance()->Alloc(GetNormalBucketPool(),
                                                           kSuperPageSize);
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index accc9068..9bd83d8a 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -27,6 +27,7 @@
 struct DeferredUnmap {
   void* ptr = nullptr;
   size_t size = 0;
+
   // In most cases there is no page to unmap and ptr == nullptr. This function
   // is inlined to avoid the overhead of a function call in the common case.
   ALWAYS_INLINE void Run();
@@ -239,7 +240,8 @@
 template <bool thread_safe>
 ALWAYS_INLINE DeferredUnmap PartitionPage<thread_safe>::Free(void* ptr) {
 #if DCHECK_IS_ON()
-  PartitionRoot<thread_safe>::FromPage(this)->lock_.AssertAcquired();
+  auto* root = PartitionRoot<thread_safe>::FromPage(this);
+  root->lock_.AssertAcquired();
 
   size_t slot_size = bucket->slot_size;
   const size_t raw_size = get_raw_size();
@@ -248,7 +250,8 @@
   }
 
   // If these asserts fire, you probably corrupted memory.
-  PartitionCookieCheckValue(reinterpret_cast<char*>(ptr) + kPartitionTagSize);
+  PartitionCookieCheckValue(reinterpret_cast<char*>(ptr) +
+                            (root->tag_pointers ? kPartitionTagSize : 0));
   PartitionCookieCheckValue(reinterpret_cast<char*>(ptr) + slot_size -
                             kCookieSize);
 
diff --git a/base/android/proguard/chromium_apk.flags b/base/android/proguard/chromium_apk.flags
index 5d3c676..189bcb4 100644
--- a/base/android/proguard/chromium_apk.flags
+++ b/base/android/proguard/chromium_apk.flags
@@ -4,12 +4,15 @@
 
 # Contains flags that we'd like all Chromium .apks to use.
 
-# Not needed for Android and saves a bit of processing time.
--dontpreverify
-
 # Keep line number information, useful for stack traces.
 -keepattributes SourceFile,LineNumberTable
 
+# Enable protobuf-related optimizations.
+-shrinkunusedprotofields
+
+# Allowing Proguard to change modifiers.
+-allowaccessmodification
+
 # Keep all CREATOR fields within Parcelable that are kept.
 -keepclassmembers class * implements android.os.Parcelable {
   public static *** CREATOR;
@@ -70,24 +73,6 @@
   static boolean isLoggable(...);
 }
 
-# The following chart was created on July 20, 2016, to decide on 3 optimization
-# passes for Chrome.
-# optimization passes | time | .dex size | dirty memory per process
-# -----------------------------------------------------------------
-#          1          | 0:48 |  5805676  |         488972
-#          2          | 1:07 |  5777376  |         487092
-#          3          | 1:24 |  5772192  |         486596
-#          4          | 1:42 |  5771124  |         486484
-#          5          | 1:56 |  5770504  |         486432
--optimizationpasses 3
-
-# Horizontal class merging marginally increases dex size (as of Mar 2018).
--optimizations !class/merging/horizontal
-
-# Allowing Proguard to change modifiers. This change shrinks the .dex size by
-# ~1%, and reduces the method count by ~4%.
--allowaccessmodification
-
 # Workaround for crbug/1002847. Methods of BaseGmsClient are incorrectly
 # removed even though they are required for the derived class GmsClient
 # to correctly implement Api$Client.
@@ -98,8 +83,3 @@
   public int getMinApkVersion();
   public boolean requiresSignIn();
 }
-
-# Protobuf java lite runtime uses reflection
--keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite {
-  <fields>;
-}
diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc
index 5774ee9..b340582 100644
--- a/base/debug/stack_trace_unittest.cc
+++ b/base/debug/stack_trace_unittest.cc
@@ -88,8 +88,9 @@
 
   // Expect a demangled symbol.
   // Note that Windows Release builds omit the function parameters from the
-  // demangled stack output, otherwise this could be "testing::Test::Run()".
-  EXPECT_TRUE(backtrace_message.find("testing::Test::Run") != std::string::npos)
+  // demangled stack output, otherwise this could be "testing::UnitTest::Run()".
+  EXPECT_TRUE(backtrace_message.find("testing::UnitTest::Run") !=
+              std::string::npos)
       << "Expected a demangled symbol in backtrace:\n"
       << backtrace_message;
 
diff --git a/base/feature_list.cc b/base/feature_list.cc
index 3b8636c..770c7bd 100644
--- a/base/feature_list.cc
+++ b/base/feature_list.cc
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/base_switches.h"
 #include "base/debug/alias.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -16,6 +17,7 @@
 #include "base/pickle.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 
 namespace base {
@@ -88,6 +90,82 @@
   return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
 }
 
+// Splits |first| into two parts by the |separator| where the first part will be
+// returned updated in |first| and the second part will be returned as |second|.
+// This function returns false if there is more than one |separator| in |first|.
+// If there is no |separator| presented in |first|, this function will not
+// modify |first| and |second|. It's used for splitting the |enable_features|
+// flag into feature name, field trial name and feature parameters.
+bool SplitIntoTwo(const std::string& separator,
+                  StringPiece* first,
+                  std::string* second) {
+  std::vector<StringPiece> parts =
+      SplitStringPiece(*first, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  if (parts.size() == 2) {
+    *second = parts[1].as_string();
+  } else if (parts.size() > 2) {
+    DLOG(ERROR) << "Only one '" << separator
+                << "' is allowed but got: " << first->as_string();
+    return false;
+  }
+  *first = parts[0];
+  return true;
+}
+
+// Checks and parses the |enable_features| flag and sets
+// |parsed_enable_features| to be a comma-separated list of features,
+// |force_fieldtrials| to be a comma-separated list of field trials that each
+// feature want to associate with and |force_fieldtrial_params| to be the field
+// trial parameters for each field trial.
+// Returns true if |enable_features| is parsable, otherwise false.
+bool ParseEnableFeatures(const std::string& enable_features,
+                         std::string* parsed_enable_features,
+                         std::string* force_fieldtrials,
+                         std::string* force_fieldtrial_params) {
+  std::vector<std::string> enable_features_list;
+  std::vector<std::string> force_fieldtrials_list;
+  std::vector<std::string> force_fieldtrial_params_list;
+  for (auto& enable_feature :
+       FeatureList::SplitFeatureListString(enable_features)) {
+    // First, check whether ":" is present. If true, feature parameters were
+    // set for this feature.
+    std::string feature_params;
+    if (!SplitIntoTwo(":", &enable_feature, &feature_params))
+      return false;
+    // Then, check whether "." is present. If true, a group was specified for
+    // this feature.
+    std::string group;
+    if (!SplitIntoTwo(".", &enable_feature, &group))
+      return false;
+    // Finally, check whether "<" is present. If true, a study was specified for
+    // this feature.
+    std::string study;
+    if (!SplitIntoTwo("<", &enable_feature, &study))
+      return false;
+
+    const std::string feature_name = enable_feature.as_string();
+    // If feature params were set but group and study weren't, associate the
+    // feature and its feature params to a synthetic field trial as the
+    // feature params only make sense when it's combined with a field trial.
+    if (!feature_params.empty()) {
+      study = study.empty() ? "Study" + feature_name : study;
+      group = group.empty() ? "Group" + feature_name : group;
+      force_fieldtrials_list.push_back(study + "/" + group);
+      force_fieldtrial_params_list.push_back(study + "." + group + ":" +
+                                             feature_params);
+    }
+    enable_features_list.push_back(
+        study.empty() ? feature_name : (feature_name + "<" + study));
+  }
+
+  *parsed_enable_features = JoinString(enable_features_list, ",");
+  // Field trial separator is currently a slash. See
+  // |kPersistentStringSeparator| in base/metrics/field_trial.cc.
+  *force_fieldtrials = JoinString(force_fieldtrials_list, "/");
+  *force_fieldtrial_params = JoinString(force_fieldtrial_params_list, ",");
+  return true;
+}
+
 }  // namespace
 
 #if defined(DCHECK_IS_CONFIGURABLE)
@@ -129,6 +207,37 @@
   initialized_from_command_line_ = true;
 }
 
+void FeatureList::InitializeFromCommandLineWithFeatureParams(
+    const std::string& enable_features,
+    const std::string& disable_features,
+    FieldTrialParamsDecodeStringFunc decode_data_func) {
+  DCHECK(!initialized_);
+
+  std::string parsed_enable_features;
+  std::string force_fieldtrials;
+  std::string force_fieldtrial_params;
+  bool parse_enable_features_result =
+      ParseEnableFeatures(enable_features, &parsed_enable_features,
+                          &force_fieldtrials, &force_fieldtrial_params);
+  DCHECK(parse_enable_features_result) << StringPrintf(
+      "The --%s list is unparsable or invalid, please check the format.",
+      ::switches::kEnableFeatures);
+  bool associate_params_result = AssociateFieldTrialParamsFromString(
+      force_fieldtrial_params, decode_data_func);
+  DCHECK(associate_params_result) << StringPrintf(
+      "The field trial parameters part of the --%s list is invalid. Make sure "
+      "you %%-encode the following characters in param values: %%:/.,",
+      ::switches::kEnableFeatures);
+
+  bool create_trials_result =
+      FieldTrialList::CreateTrialsFromString(force_fieldtrials);
+  DCHECK(create_trials_result)
+      << StringPrintf("Invalid field trials are specified in --%s.",
+                      ::switches::kEnableFeatures);
+
+  InitializeFromCommandLine(parsed_enable_features, disable_features);
+}
+
 void FeatureList::InitializeFromSharedMemory(
     PersistentMemoryAllocator* allocator) {
   DCHECK(!initialized_);
@@ -352,6 +461,11 @@
   g_feature_list_instance = instance.release();
 }
 
+// static
+std::string FeatureList::NoOpDecodeFunc(const std::string& str) {
+  return str;
+}
+
 void FeatureList::FinalizeInitialization() {
   DCHECK(!initialized_);
   // Store the field trial list pointer for DCHECKing.
diff --git a/base/feature_list.h b/base/feature_list.h
index f46b30d..4da25b42 100644
--- a/base/feature_list.h
+++ b/base/feature_list.h
@@ -14,6 +14,7 @@
 #include "base/base_export.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/persistent_memory_allocator.h"
 #include "base/strings/string_piece.h"
 #include "base/synchronization/lock.h"
@@ -140,6 +141,32 @@
   void InitializeFromCommandLine(const std::string& enable_features,
                                  const std::string& disable_features);
 
+  // Initializes feature overrides via command-line flags |enable_features| and
+  // |disable_features|, each of which is a comma-separated list of features to
+  // enable or disable, respectively. This function also allows users to set
+  // feature's field trial params via |enable_features|. |decode_data_func|
+  // allows specifying a custom decoding function. Must only be invoked during
+  // the initialization phase (before FinalizeInitialization() has been called).
+  //
+  // If a feature appears on both lists, then it will be disabled. If
+  // a list entry has the format "FeatureName<TrialName" then this
+  // initialization will also associate the feature state override with the
+  // named field trial, if it exists. If a list entry has the format
+  // "FeatureName:k1/v1/k2/v2", "FeatureName<TrailName:k1/v1/k2/v2" or
+  // "FeatureName<TrailName.GroupName:k1/v1/k2/v2" then this initialization will
+  // also associate the feature state override with the named field trial and
+  // its params. If the feature params part is provided but trial and/or group
+  // isn't, this initialization will also create a synthetic trial, named
+  // "Study" followed by the feature name, i.e. "StudyFeature", and group, named
+  // "Group" followed by the feature name, i.e. "GroupFeature", for the params.
+  // If a feature name is prefixed with the '*' character, it will be created
+  // with OVERRIDE_USE_DEFAULT - which is useful for associating with a trial
+  // while using the default state.
+  void InitializeFromCommandLineWithFeatureParams(
+      const std::string& enable_features,
+      const std::string& disable_features,
+      FieldTrialParamsDecodeStringFunc decode_data_func);
+
   // Initializes feature overrides through the field trial allocator, which
   // we're using to store the feature names, their override state, and the name
   // of the associated field trial.
@@ -252,6 +279,10 @@
   // to support base::test::ScopedFeatureList helper class.
   static void RestoreInstanceForTesting(std::unique_ptr<FeatureList> instance);
 
+  // TODO(crbug.com/1068052): Port the UnescapeValue function and cleanup this.
+  // A no-op function that takes a string and returns it.
+  static std::string NoOpDecodeFunc(const std::string& str);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity);
   FRIEND_TEST_ALL_PREFIXES(FeatureListTest,
diff --git a/base/feature_list_unittest.cc b/base/feature_list_unittest.cc
index 3b0dc1c..c2eb464 100644
--- a/base/feature_list_unittest.cc
+++ b/base/feature_list_unittest.cc
@@ -101,6 +101,38 @@
   }
 }
 
+TEST_F(FeatureListTest, InitializeFromCommandLineWithFeatureParams) {
+  struct {
+    const std::string enable_features;
+    const std::string expected_field_trial_created;
+    const std::map<std::string, std::string> expected_feature_params;
+  } test_cases[] = {
+      {"Feature:x/100/y/test", "StudyFeature", {{"x", "100"}, {"y", "test"}}},
+      {"Feature<Trial1:x/200/y/123", "Trial1", {{"x", "200"}, {"y", "123"}}},
+      {"Feature<Trial2.Group2:x/test/y/uma/z/ukm",
+       "Trial2",
+       {{"x", "test"}, {"y", "uma"}, {"z", "ukm"}}},
+  };
+
+  const Feature kFeature = {"Feature", FEATURE_DISABLED_BY_DEFAULT};
+  for (const auto& test_case : test_cases) {
+    SCOPED_TRACE(test_case.enable_features);
+
+    auto feature_list = std::make_unique<FeatureList>();
+    feature_list->InitializeFromCommandLineWithFeatureParams(
+        test_case.enable_features, "", &FeatureList::NoOpDecodeFunc);
+    test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitWithFeatureList(std::move(feature_list));
+
+    EXPECT_TRUE(FeatureList::IsEnabled(kFeature));
+    EXPECT_TRUE(
+        FieldTrialList::IsTrialActive(test_case.expected_field_trial_created));
+    std::map<std::string, std::string> actualParams;
+    EXPECT_TRUE(GetFieldTrialParamsByFeature(kFeature, &actualParams));
+    EXPECT_EQ(test_case.expected_feature_params, actualParams);
+  }
+}
+
 TEST_F(FeatureListTest, CheckFeatureIdentity) {
   // Tests that CheckFeatureIdentity() correctly detects when two different
   // structs with the same feature name are passed to it.
diff --git a/base/metrics/field_trial_param_associator.cc b/base/metrics/field_trial_param_associator.cc
index 6360b8c..ea76b79 100644
--- a/base/metrics/field_trial_param_associator.cc
+++ b/base/metrics/field_trial_param_associator.cc
@@ -4,6 +4,7 @@
 
 #include "base/metrics/field_trial_param_associator.h"
 
+#include "base/logging.h"
 #include "base/metrics/field_trial.h"
 
 namespace base {
@@ -21,13 +22,18 @@
     const std::string& trial_name,
     const std::string& group_name,
     const FieldTrialParams& params) {
-  if (FieldTrialList::IsTrialActive(trial_name))
+  if (FieldTrialList::IsTrialActive(trial_name)) {
+    DLOG(ERROR) << "Field trial " << trial_name << " is already active.";
     return false;
+  }
 
   AutoLock scoped_lock(lock_);
   const FieldTrialKey key(trial_name, group_name);
-  if (Contains(field_trial_params_, key))
+  if (Contains(field_trial_params_, key)) {
+    DLOG(ERROR) << "You can't override the existing params for field trial: "
+                << trial_name << "." << group_name;
     return false;
+  }
 
   field_trial_params_[key] = params;
   return true;
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
index bb4a7ad..00a534c 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java
@@ -4,16 +4,22 @@
 
 package org.chromium.base.test;
 
+import android.annotation.TargetApi;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.Application;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.SharedPreferences;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.internal.runner.RunnerArgs;
 import android.support.test.internal.runner.TestExecutor;
@@ -21,16 +27,29 @@
 import android.support.test.internal.runner.TestRequest;
 import android.support.test.internal.runner.TestRequestBuilder;
 import android.support.test.runner.AndroidJUnitRunner;
+import android.support.test.runner.MonitoringInstrumentation.ActivityFinisher;
+import android.text.TextUtils;
+
+import androidx.core.content.ContextCompat;
 
 import dalvik.system.DexFile;
 
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.ApplicationStatus;
 import org.chromium.base.BuildConfig;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.FileUtils;
+import org.chromium.base.LifetimeAssert;
 import org.chromium.base.Log;
 import org.chromium.base.annotations.MainDex;
 import org.chromium.base.multidex.ChromiumMultiDexInstaller;
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.InMemorySharedPreferences;
 import org.chromium.base.test.util.InMemorySharedPreferencesContext;
+import org.chromium.base.test.util.ScalableTimeout;
 
+import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -39,6 +58,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.TimeoutException;
 
 /**
  * A custom AndroidJUnitRunner that supports multidex installer and list out test information.
@@ -78,6 +98,16 @@
     private static final String ARGUMENT_LOG_ONLY = "log";
 
     private static final String TAG = "BaseJUnitRunner";
+
+    private static final int STATUS_CODE_BATCH_FAILURE = 1338;
+
+    // The ID of the bundle value Instrumentation uses to report the crash stack, if the test
+    // crashed.
+    private static final String BUNDLE_STACK_ID = "stack";
+
+    private static final long FINISH_APP_TASKS_TIMEOUT_MS = ScalableTimeout.scaleTimeout(3000L);
+    private static final long FINISH_APP_TASKS_POLL_INTERVAL_MS = 100;
+
     static InMemorySharedPreferencesContext sInMemorySharedPreferencesContext;
 
     @Override
@@ -140,7 +170,7 @@
     @Override
     public void onStart() {
         Bundle arguments = InstrumentationRegistry.getArguments();
-        if (arguments != null && arguments.getString(LIST_ALL_TESTS_FLAG) != null) {
+        if (shouldListTests()) {
             Log.w(TAG,
                     String.format("Runner will list out tests info in JSON without running tests. "
                                     + "Arguments: %s",
@@ -154,6 +184,11 @@
                                         + " crbug.com/754015. Arguments: %s",
                                 arguments.toString()));
             }
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                finishAllAppTasks(getTargetContext());
+            }
+            checkOrDeleteOnDiskSharedPreferences(false);
+            clearDataDirectory(sInMemorySharedPreferencesContext);
             super.onStart();
         }
     }
@@ -246,7 +281,8 @@
         return builder.build();
     }
 
-    static boolean shouldListTests(Bundle arguments) {
+    static boolean shouldListTests() {
+        Bundle arguments = InstrumentationRegistry.getArguments();
         return arguments != null && arguments.getString(LIST_ALL_TESTS_FLAG) != null;
     }
 
@@ -414,4 +450,223 @@
             }
         }
     }
+
+    @Override
+    public void finish(int resultCode, Bundle results) {
+        if (shouldListTests()) {
+            super.finish(resultCode, results);
+            return;
+        }
+
+        try {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                finishAllAppTasks(getTargetContext());
+            }
+            finishAllActivities();
+        } catch (Exception e) {
+            // Ignore any errors finishing Activities so that otherwise passing tests don't fail
+            // during tear down due to framework issues. See crbug.com/653731.
+        }
+
+        try {
+            checkOrDeleteOnDiskSharedPreferences(true);
+
+            // There is a bug on L and below that DestroyActivitiesRule does not cause onStop and
+            // onDestroy. On other versions, DestroyActivitiesRule may still fail flakily. Ignore
+            // lifetime asserts if that is the case.
+            if (!ApplicationStatus.isInitialized()
+                    || ApplicationStatus.isEveryActivityDestroyed()) {
+                LifetimeAssert.assertAllInstancesDestroyedForTesting();
+            }
+        } catch (Exception e) {
+            // It's not possible (as far as I know) to update already reported test results, so we
+            // send another status update have the instrumentation test instance parse it.
+            Bundle b = new Bundle();
+            b.putString(BUNDLE_STACK_ID, Log.getStackTraceString(e));
+            InstrumentationRegistry.getInstrumentation().sendStatus(STATUS_CODE_BATCH_FAILURE, b);
+        }
+
+        // This will end up force stopping the package, so code after this line will not run.
+        super.finish(resultCode, results);
+    }
+
+    // Since we prevent the default runner's behaviour of finishing Activities between tests, don't
+    // finish Activities, don't have the runner wait for them to finish either (as this will add a 2
+    // second timeout to each test).
+    @Override
+    protected void waitForActivitiesToComplete() {}
+
+    // Note that in this class we cannot use ThreadUtils to post tasks as some tests initialize the
+    // browser in ways that cause tasks posted through PostTask to not run. This function should be
+    // used instead.
+    @Override
+    public void runOnMainSync(Runnable runner) {
+        if (runner.getClass() == ActivityFinisher.class) {
+            // This is a gross hack.
+            // Without migrating to the androidx runner, we have no way to prevent
+            // MonitoringInstrumentation from trying to kill our activities, and we rely on
+            // MonitoringInstrumentation for many things like result reporting.
+            // In order to allow batched tests to reuse Activities, drop the ActivityFinisher tasks
+            // without running them.
+            return;
+        }
+        super.runOnMainSync(runner);
+    }
+
+    /** Finishes all tasks Chrome has listed in Android's Overview. */
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    private void finishAllAppTasks(final Context context) {
+        // Close all of the tasks one by one.
+        ActivityManager activityManager =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        for (ActivityManager.AppTask task : activityManager.getAppTasks()) {
+            task.finishAndRemoveTask();
+        }
+        long endTime = SystemClock.uptimeMillis() + FINISH_APP_TASKS_TIMEOUT_MS;
+        while (activityManager.getAppTasks().size() != 0 && SystemClock.uptimeMillis() < endTime) {
+            try {
+                Thread.sleep(FINISH_APP_TASKS_POLL_INTERVAL_MS);
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    private void finishAllActivities() {
+        // This mirrors the default logic of the test runner for finishing Activities when
+        // ApplicationStatus isn't initialized. However, we keep Chromium's logic for finishing
+        // Activities below both because it's worked historically and we don't want to risk breaking
+        // things, and because the ActivityFinisher does some filtering on which Activities it
+        // chooses to finish which could potentially cause issues.
+        if (!ApplicationStatus.isInitialized()) {
+            runOnMainSync(() -> new ActivityFinisher().run());
+            super.waitForActivitiesToComplete();
+            return;
+        }
+        CallbackHelper allDestroyedCalledback = new CallbackHelper();
+        ApplicationStatus.ActivityStateListener activityStateListener =
+                new ApplicationStatus.ActivityStateListener() {
+                    @Override
+                    public void onActivityStateChange(Activity activity, int newState) {
+                        switch (newState) {
+                            case ActivityState.DESTROYED:
+                                if (ApplicationStatus.isEveryActivityDestroyed()) {
+                                    allDestroyedCalledback.notifyCalled();
+                                    ApplicationStatus.unregisterActivityStateListener(this);
+                                }
+                                break;
+                            case ActivityState.CREATED:
+                                if (!activity.isFinishing()) {
+                                    // This is required to ensure we finish any activities created
+                                    // after doing the bulk finish operation below.
+                                    ApiCompatibilityUtils.finishAndRemoveTask(activity);
+                                }
+                                break;
+                        }
+                    }
+                };
+
+        new Handler(Looper.getMainLooper()).post(() -> {
+            if (ApplicationStatus.isEveryActivityDestroyed()) {
+                allDestroyedCalledback.notifyCalled();
+            } else {
+                ApplicationStatus.registerStateListenerForAllActivities(activityStateListener);
+            }
+            for (Activity a : ApplicationStatus.getRunningActivities()) {
+                if (!a.isFinishing()) ApiCompatibilityUtils.finishAndRemoveTask(a);
+            }
+        });
+        try {
+            allDestroyedCalledback.waitForFirst();
+        } catch (TimeoutException e) {
+            // There appears to be a framework bug on K and L where onStop and onDestroy are not
+            // called for a handful of tests. We ignore these exceptions.
+            Log.w(TAG, "Activity failed to be destroyed after a test");
+
+            runOnMainSync(() -> {
+                // Make sure subsequent tests don't have these notifications firing.
+                ApplicationStatus.unregisterActivityStateListener(activityStateListener);
+            });
+        }
+    }
+
+    private static void clearDataDirectory(Context targetContext) {
+        File dataDir = ContextCompat.getDataDir(targetContext);
+        File[] files = dataDir.listFiles();
+        if (files == null) return;
+        for (File file : files) {
+            // Symlink to app's native libraries.
+            if (file.getName().equals("lib")) {
+                continue;
+            }
+            if (file.getName().equals("incremental-install-files")) {
+                continue;
+            }
+            // E.g. Legacy multidex files.
+            if (file.getName().equals("code_cache")) {
+                continue;
+            }
+            // SharedPreferences handled by checkOrDeleteOnDiskSharedPreferences().
+            if (file.getName().equals("shared_prefs")) {
+                continue;
+            }
+            if (file.isDirectory()
+                    && (file.getName().startsWith("app_") || file.getName().equals("cache"))) {
+                // Directories are lazily created by PathUtils only once, and so can be cleared but
+                // not removed.
+                for (File subFile : file.listFiles()) {
+                    if (!FileUtils.recursivelyDeleteFile(subFile, FileUtils.DELETE_ALL)) {
+                        throw new RuntimeException(
+                                "Could not delete file: " + subFile.getAbsolutePath());
+                    }
+                }
+            } else if (!FileUtils.recursivelyDeleteFile(file, FileUtils.DELETE_ALL)) {
+                throw new RuntimeException("Could not delete file: " + file.getAbsolutePath());
+            }
+        }
+    }
+
+    private void checkOrDeleteOnDiskSharedPreferences(boolean check) {
+        File dataDir = ContextCompat.getDataDir(InstrumentationRegistry.getTargetContext());
+        File prefsDir = new File(dataDir, "shared_prefs");
+        File[] files = prefsDir.listFiles();
+        if (files == null) {
+            return;
+        }
+        ArrayList<File> badFiles = new ArrayList<>();
+        for (File f : files) {
+            // Multidex support library prefs need to stay or else multidex extraction will occur
+            // needlessly.
+            // WebView prefs need to stay because webview tests have no (good) way of hooking
+            // SharedPreferences for instantiated WebViews.
+            if (!f.getName().endsWith("multidex.version.xml")
+                    && !f.getName().equals("WebViewChromiumPrefs.xml")) {
+                if (check) {
+                    badFiles.add(f);
+                } else {
+                    f.delete();
+                }
+            }
+        }
+        if (!badFiles.isEmpty()) {
+            String errorMsg = "Found unexpected shared preferences file(s) after test ran.\n"
+                    + "All code should use ContextUtils.getApplicationContext() when accessing "
+                    + "SharedPreferences so that tests are hooked to use InMemorySharedPreferences."
+                    + " This could also mean needing to override getSharedPreferences() on custom "
+                    + "Context subclasses (e.g. ChromeBaseAppCompatActivity does this to make "
+                    + "Preferences screens work).\n\n";
+
+            SharedPreferences testPrefs = ContextUtils.getApplicationContext().getSharedPreferences(
+                    "test", Context.MODE_PRIVATE);
+            if (!(testPrefs instanceof InMemorySharedPreferences)) {
+                errorMsg += String.format(
+                        "ContextUtils.getApplicationContext() was set to type \"%s\", which does "
+                                + "not delegate to InMemorySharedPreferencesContext (this is "
+                                + "likely the issues).\n\n",
+                        ContextUtils.getApplicationContext().getClass().getName());
+            }
+
+            errorMsg += "Files:\n * " + TextUtils.join("\n * ", badFiles);
+            throw new AssertionError(errorMsg);
+        }
+    }
 }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java
index 16456472..0afce55 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java
@@ -15,7 +15,6 @@
 import androidx.annotation.CallSuper;
 
 import org.junit.rules.MethodRule;
-import org.junit.rules.RuleChain;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runner.notification.RunNotifier;
@@ -236,14 +235,7 @@
      */
     @CallSuper
     protected List<TestRule> getDefaultTestRules() {
-        // Order is important here. Outer rule setUp's run first, and tearDown's run last.
-        // Base setUp() should go first to initialize ContextUtils and clear out prefs.
-        // Base's tearDown() should come last since it deletes files.
-        // Activities must be destroyed before lifetimes are checked, so DestroyActivitiesRule()
-        // must come last so that its tearDown() runs before LifetimeAssertRule's.
-        return Collections.singletonList(RuleChain.outerRule(new BaseJUnit4TestRule())
-                                                 .around(new LifetimeAssertRule())
-                                                 .around(new DestroyActivitiesRule()));
+        return Collections.singletonList(new BaseJUnit4TestRule());
     }
 
     /**
@@ -273,8 +265,7 @@
      */
     @Override
     public void run(RunNotifier notifier) {
-        if (BaseChromiumAndroidJUnitRunner.shouldListTests(
-                    InstrumentationRegistry.getArguments())) {
+        if (BaseChromiumAndroidJUnitRunner.shouldListTests()) {
             for (Description child : getDescription().getChildren()) {
                 notifier.fireTestFinished(child);
             }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java
index 86ac31de..d9f3120 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseJUnit4TestRule.java
@@ -4,25 +4,12 @@
 
 package org.chromium.base.test;
 
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.support.test.InstrumentationRegistry;
-import android.text.TextUtils;
-
-import androidx.core.content.ContextCompat;
-
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
-import org.chromium.base.ContextUtils;
-import org.chromium.base.FileUtils;
-import org.chromium.base.test.util.InMemorySharedPreferences;
 import org.chromium.base.test.util.InMemorySharedPreferencesContext;
 
-import java.io.File;
-import java.util.ArrayList;
-
 /**
  * Holds setUp / tearDown logic common to all instrumentation tests.
  */
@@ -32,108 +19,15 @@
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
-                // Don't tests if there are prior on-disk shared prefs lying around.
-                checkOrDeleteOnDiskSharedPreferences(false);
-
                 InMemorySharedPreferencesContext context =
                         BaseChromiumAndroidJUnitRunner.sInMemorySharedPreferencesContext;
                 if (context == null) {
                     throw new IllegalStateException("BaseJUnit4TestRule requires that you use "
                             + "BaseChromiumAndroidJUnitRunner (or a subclass)");
                 }
-                // Reset Application context in case any tests have replaced it.
-                ContextUtils.initApplicationContextForTests(context);
-                // Ensure all tests start with empty (InMemory)SharedPreferences.
-                context.clearSharedPreferences();
-                // Delete any files that leak state between tests.
-                clearDataDirectory(context);
-
                 base.evaluate();
-
-                // Do not use try/finally so that preferences asserts do not mask prior exceptions.
-                checkOrDeleteOnDiskSharedPreferences(true);
             }
         };
     }
 
-    private void checkOrDeleteOnDiskSharedPreferences(boolean check) {
-        File dataDir = ContextCompat.getDataDir(InstrumentationRegistry.getTargetContext());
-        File prefsDir = new File(dataDir, "shared_prefs");
-        File[] files = prefsDir.listFiles();
-        if (files == null) {
-            return;
-        }
-        ArrayList<File> badFiles = new ArrayList<>();
-        for (File f : files) {
-            // Multidex support library prefs need to stay or else multidex extraction will occur
-            // needlessly.
-            // WebView prefs need to stay because webview tests have no (good) way of hooking
-            // SharedPreferences for instantiated WebViews.
-            if (!f.getName().endsWith("multidex.version.xml")
-                    && !f.getName().equals("WebViewChromiumPrefs.xml")) {
-                if (check) {
-                    badFiles.add(f);
-                } else {
-                    f.delete();
-                }
-            }
-        }
-        if (!badFiles.isEmpty()) {
-            String errorMsg = "Found unexpected shared preferences file(s) after test ran.\n"
-                    + "All code should use ContextUtils.getApplicationContext() when accessing "
-                    + "SharedPreferences so that tests are hooked to use InMemorySharedPreferences."
-                    + " This could also mean needing to override getSharedPreferences() on custom "
-                    + "Context subclasses (e.g. ChromeBaseAppCompatActivity does this to make "
-                    + "Preferences screens work).\n\n";
-
-            SharedPreferences testPrefs = ContextUtils.getApplicationContext().getSharedPreferences(
-                    "test", Context.MODE_PRIVATE);
-            if (!(testPrefs instanceof InMemorySharedPreferences)) {
-                errorMsg += String.format(
-                        "ContextUtils.getApplicationContext() was set to type \"%s\", which does "
-                                + "not delegate to InMemorySharedPreferencesContext (this is "
-                                + "likely the issues).\n\n",
-                        ContextUtils.getApplicationContext().getClass().getName());
-            }
-
-            errorMsg += "Files:\n * " + TextUtils.join("\n * ", badFiles);
-            throw new AssertionError(errorMsg);
-        }
-    }
-
-    private static void clearDataDirectory(Context targetContext) {
-        File dataDir = ContextCompat.getDataDir(targetContext);
-        File[] files = dataDir.listFiles();
-        if (files == null) return;
-        for (File file : files) {
-            // Symlink to app's native libraries.
-            if (file.getName().equals("lib")) {
-                continue;
-            }
-            if (file.getName().equals("incremental-install-files")) {
-                continue;
-            }
-            // E.g. Legacy multidex files.
-            if (file.getName().equals("code_cache")) {
-                continue;
-            }
-            // SharedPreferences handled by checkOrDeleteOnDiskSharedPreferences().
-            if (file.getName().equals("shared_prefs")) {
-                continue;
-            }
-            if (file.isDirectory()
-                    && (file.getName().startsWith("app_") || file.getName().equals("cache"))) {
-                // Directories are lazily created by PathUtils only once, and so can be cleared but
-                // not removed.
-                for (File subFile : file.listFiles()) {
-                    if (!FileUtils.recursivelyDeleteFile(subFile, FileUtils.DELETE_ALL)) {
-                        throw new RuntimeException(
-                                "Could not delete file: " + subFile.getAbsolutePath());
-                    }
-                }
-            } else if (!FileUtils.recursivelyDeleteFile(file, FileUtils.DELETE_ALL)) {
-                throw new RuntimeException("Could not delete file: " + file.getAbsolutePath());
-            }
-        }
-    }
 }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/DestroyActivitiesRule.java b/base/test/android/javatests/src/org/chromium/base/test/DestroyActivitiesRule.java
deleted file mode 100644
index 9f4e95f..0000000
--- a/base/test/android/javatests/src/org/chromium/base/test/DestroyActivitiesRule.java
+++ /dev/null
@@ -1,98 +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.
-
-package org.chromium.base.test;
-
-import android.app.Activity;
-
-import org.junit.rules.ExternalResource;
-
-import org.chromium.base.ActivityState;
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.util.CallbackHelper;
-
-import java.util.Collections;
-import java.util.Set;
-import java.util.WeakHashMap;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This is to ensure all calls to onDestroy() are performed before starting the next test.
- * We could probably remove this when crbug.com/932130 is fixed.
- */
-public class DestroyActivitiesRule extends ExternalResource {
-    private static final String TAG = "DestroyActivities";
-    private final Set<Activity> mBlacklistedActivities =
-            Collections.newSetFromMap(new WeakHashMap<>());
-
-    private boolean allActivitiesDestroyedOrBlacklisted() {
-        if (ApplicationStatus.isEveryActivityDestroyed()) {
-            return true;
-        }
-        for (Activity a : ApplicationStatus.getRunningActivities()) {
-            if (!mBlacklistedActivities.contains(a)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void after() {
-        if (!ApplicationStatus.isInitialized()) {
-            return;
-        }
-        CallbackHelper allDestroyedCalledback = new CallbackHelper();
-        ApplicationStatus.ActivityStateListener activityStateListener =
-                new ApplicationStatus.ActivityStateListener() {
-                    @Override
-                    public void onActivityStateChange(Activity activity, int newState) {
-                        switch (newState) {
-                            case ActivityState.DESTROYED:
-                                if (allActivitiesDestroyedOrBlacklisted()) {
-                                    allDestroyedCalledback.notifyCalled();
-                                    ApplicationStatus.unregisterActivityStateListener(this);
-                                }
-                                break;
-                            case ActivityState.CREATED:
-                                if (!activity.isFinishing()) {
-                                    // This is required to ensure we finish any activities created
-                                    // after doing the bulk finish operation below.
-                                    activity.finish();
-                                }
-                                break;
-                        }
-                    }
-                };
-
-        ThreadUtils.runOnUiThread(() -> {
-            if (allActivitiesDestroyedOrBlacklisted()) {
-                allDestroyedCalledback.notifyCalled();
-            } else {
-                ApplicationStatus.registerStateListenerForAllActivities(activityStateListener);
-            }
-            for (Activity a : ApplicationStatus.getRunningActivities()) {
-                if (!a.isFinishing() && !mBlacklistedActivities.contains(a)) {
-                    a.finish();
-                }
-            }
-        });
-        try {
-            allDestroyedCalledback.waitForFirst();
-        } catch (TimeoutException e) {
-            // There appears to be a framework bug on K and L where onStop and onDestroy are not
-            // called for a handful of tests. We ignore these exceptions.
-            Log.w(TAG, "Activity failed to be destroyed after a test");
-
-            ThreadUtils.runOnUiThreadBlocking(() -> {
-                mBlacklistedActivities.addAll(ApplicationStatus.getRunningActivities());
-
-                // Make sure subsequent tests don't have these notifications firing.
-                ApplicationStatus.unregisterActivityStateListener(activityStateListener);
-            });
-        }
-    }
-}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/LifetimeAssertRule.java b/base/test/android/javatests/src/org/chromium/base/test/LifetimeAssertRule.java
deleted file mode 100644
index ff1d4bb6..0000000
--- a/base/test/android/javatests/src/org/chromium/base/test/LifetimeAssertRule.java
+++ /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.
-
-package org.chromium.base.test;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.LifetimeAssert;
-
-/**
- * Ensures that all object instances that use LifetimeAssert are destroyed.
- */
-public class LifetimeAssertRule implements TestRule {
-    @Override
-    public Statement apply(Statement base, Description description) {
-        return new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                base.evaluate();
-                // Do not use try/finally so that lifetime asserts do not mask prior exceptions.
-                maybeAssertLifetime();
-            }
-        };
-    }
-
-    private void maybeAssertLifetime() {
-        // There is a bug on L and below that DestroyActivitiesRule does not cause onStop and
-        // onDestroy. On other versions, DestroyActivitiesRule may still fail flakily. Ignore
-        // lifetime asserts if that is the case.
-        if (ApplicationStatus.isInitialized() && !ApplicationStatus.isEveryActivityDestroyed()) {
-            return;
-        }
-        LifetimeAssert.assertAllInstancesDestroyedForTesting();
-    }
-}
diff --git a/base/test/scoped_feature_list.cc b/base/test/scoped_feature_list.cc
index dd3dd0e..5d03522 100644
--- a/base/test/scoped_feature_list.cc
+++ b/base/test/scoped_feature_list.cc
@@ -179,7 +179,8 @@
     const std::string& enable_features,
     const std::string& disable_features) {
   std::unique_ptr<FeatureList> feature_list(new FeatureList);
-  feature_list->InitializeFromCommandLine(enable_features, disable_features);
+  feature_list->InitializeFromCommandLineWithFeatureParams(
+      enable_features, disable_features, &FeatureList::NoOpDecodeFunc);
   InitWithFeatureList(std::move(feature_list));
 }
 
diff --git a/base/test/scoped_feature_list.h b/base/test/scoped_feature_list.h
index 1d5bc7e..4da82ad 100644
--- a/base/test/scoped_feature_list.h
+++ b/base/test/scoped_feature_list.h
@@ -72,7 +72,9 @@
   // default values, which can hide feature interaction bugs. Please use
   // sparingly.  https://crbug.com/713390
   // Initializes and registers a FeatureList instance with only the given
-  // enabled and disabled features (comma-separated names).
+  // enabled and disabled features (comma-separated names). If feature params
+  // are provided in the |enable_features|, this also associates features to
+  // their params.
   void InitFromCommandLine(const std::string& enable_features,
                            const std::string& disable_features);
 
@@ -139,7 +141,7 @@
 
   bool init_called_ = false;
   std::unique_ptr<FeatureList> original_feature_list_;
-  base::FieldTrialList* original_field_trial_list_;
+  base::FieldTrialList* original_field_trial_list_ = nullptr;
   std::string original_params_;
   std::unique_ptr<base::FieldTrialList> field_trial_list_;
 
diff --git a/base/test/scoped_feature_list_unittest.cc b/base/test/scoped_feature_list_unittest.cc
index 53a7bde..51bb8b34 100644
--- a/base/test/scoped_feature_list_unittest.cc
+++ b/base/test/scoped_feature_list_unittest.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "base/macros.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_params.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -73,6 +74,51 @@
   EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature1));
 }
 
+TEST_F(ScopedFeatureListTest, InitFromCommandLineWithFeatureParams) {
+  const std::map<std::string, std::string> feature_params1 = {{"x", "uma"},
+                                                              {"y", "ukm"}};
+  const std::map<std::string, std::string> feature_params2 = {{"x", "ukm"},
+                                                              {"y", "uma"}};
+
+  test::ScopedFeatureList feature_list1;
+  feature_list1.InitFromCommandLine("TestFeature1<foo.bar:x/uma/y/ukm", "");
+
+  // Check initial state. Field trial and parameters should be set correctly.
+  EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_EQ(1u, active_groups.size());
+  FieldTrial* original_field_trial =
+      FieldTrialList::Find(active_groups[0].trial_name);
+  std::map<std::string, std::string> actualParams;
+  EXPECT_TRUE(GetFieldTrialParamsByFeature(kTestFeature1, &actualParams));
+  EXPECT_EQ(feature_params1, actualParams);
+
+  {
+    // Override feature with existing field trial.
+    test::ScopedFeatureList feature_list2;
+
+    feature_list2.InitAndEnableFeatureWithParameters(kTestFeature1,
+                                                     feature_params2);
+    EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+    EXPECT_NE(original_field_trial, FeatureList::GetFieldTrial(kTestFeature1));
+    actualParams.clear();
+    EXPECT_TRUE(GetFieldTrialParamsByFeature(kTestFeature1, &actualParams));
+    EXPECT_EQ(feature_params2, actualParams);
+    EXPECT_NE(nullptr, FeatureList::GetFieldTrial(kTestFeature1));
+  }
+
+  // Check that initial state is restored.
+  EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+  active_groups.clear();
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_EQ(1u, active_groups.size());
+  EXPECT_EQ(original_field_trial, FeatureList::GetFieldTrial(kTestFeature1));
+  actualParams.clear();
+  EXPECT_TRUE(GetFieldTrialParamsByFeature(kTestFeature1, &actualParams));
+  EXPECT_EQ(feature_params1, actualParams);
+}
+
 TEST_F(ScopedFeatureListTest, EnableWithFeatureParameters) {
   const char kParam1[] = "param_1";
   const char kParam2[] = "param_2";
@@ -202,7 +248,7 @@
   ExpectFeatures("TestFeature1<foo1,TestFeature2", std::string());
   EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
   EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
-  EXPECT_EQ(trial1.get(), FeatureList::GetFieldTrial(kTestFeature1));
+  EXPECT_EQ("foo1", FeatureList::GetFieldTrial(kTestFeature1)->trial_name());
   EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
diff --git a/base/time/time.cc b/base/time/time.cc
index 36f1c5bd..579660d9 100644
--- a/base/time/time.cc
+++ b/base/time/time.cc
@@ -69,27 +69,15 @@
 }
 
 int TimeDelta::InHours() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int>::max();
-  }
-  if (is_min()) {
-    // Preserve min to prevent underflow.
-    return std::numeric_limits<int>::min();
-  }
-  return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
+  // saturated_cast<> is necessary since very large (but still less than
+  // min/max) deltas would result in overflow.
+  return saturated_cast<int>(delta_ / Time::kMicrosecondsPerHour);
 }
 
 int TimeDelta::InMinutes() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int>::max();
-  }
-  if (is_min()) {
-    // Preserve min to prevent underflow.
-    return std::numeric_limits<int>::min();
-  }
-  return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
+  // saturated_cast<> is necessary since very large (but still less than
+  // min/max) deltas would result in overflow.
+  return saturated_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
 }
 
 double TimeDelta::InSecondsF() const {
@@ -170,15 +158,7 @@
 }
 
 int64_t TimeDelta::InNanoseconds() const {
-  if (is_max()) {
-    // Preserve max to prevent overflow.
-    return std::numeric_limits<int64_t>::max();
-  }
-  if (is_min()) {
-    // Preserve min to prevent underflow.
-    return std::numeric_limits<int64_t>::min();
-  }
-  return delta_ * Time::kNanosecondsPerMicrosecond;
+  return base::ClampMul(delta_, Time::kNanosecondsPerMicrosecond);
 }
 
 std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index 0e69472..965bd99 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -1442,6 +1442,27 @@
   EXPECT_EQ(TimeDelta::FromMicroseconds(1001).InMillisecondsRoundedUp(), 2);
 }
 
+// Check that near-min/max values saturate rather than overflow when converted
+// lossily with InXXX() functions.  Only integral hour, minute, and nanosecond
+// conversions are checked, since those are the only cases where the return type
+// is small enough for saturation or overflow to occur.
+TEST(TimeDelta, InXXXOverflow) {
+  constexpr TimeDelta kLargeDelta =
+      TimeDelta::FromMicroseconds(std::numeric_limits<int64_t>::max() - 1);
+  static_assert(!kLargeDelta.is_max(), "");
+  EXPECT_EQ(std::numeric_limits<int>::max(), kLargeDelta.InHours());
+  EXPECT_EQ(std::numeric_limits<int>::max(), kLargeDelta.InMinutes());
+  EXPECT_EQ(std::numeric_limits<int64_t>::max(), kLargeDelta.InNanoseconds());
+
+  constexpr TimeDelta kLargeNegative =
+      TimeDelta::FromMicroseconds(std::numeric_limits<int64_t>::min() + 1);
+  static_assert(!kLargeNegative.is_min(), "");
+  EXPECT_EQ(std::numeric_limits<int>::min(), kLargeNegative.InHours());
+  EXPECT_EQ(std::numeric_limits<int>::min(), kLargeNegative.InMinutes());
+  EXPECT_EQ(std::numeric_limits<int64_t>::min(),
+            kLargeNegative.InNanoseconds());
+}
+
 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
 TEST(TimeDelta, TimeSpecConversion) {
   TimeDelta delta = TimeDelta::FromSeconds(0);
diff --git a/base/win/scoped_safearray.h b/base/win/scoped_safearray.h
index e7f3d7d..1233753a 100644
--- a/base/win/scoped_safearray.h
+++ b/base/win/scoped_safearray.h
@@ -10,6 +10,8 @@
 #include "base/base_export.h"
 #include "base/check_op.h"
 #include "base/macros.h"
+#include "base/optional.h"
+#include "base/win/variant_util.h"
 
 namespace base {
 namespace win {
@@ -19,6 +21,101 @@
 // CComSafeArray offers.
 class BASE_EXPORT ScopedSafearray {
  public:
+  // LockScope<VARTYPE> class for automatically managing the lifetime of a
+  // SAFEARRAY lock, and granting easy access to the underlying data either
+  // through random access or as an iterator.
+  // It is undefined behavior if the underlying SAFEARRAY is destroyed
+  // before the LockScope.
+  // LockScope implements std::iterator_traits as a random access iterator, so
+  // that LockScope is compatible with STL methods that require these traits.
+  template <VARTYPE ElementVartype>
+  class BASE_EXPORT LockScope final {
+   public:
+    // Type declarations to support std::iterator_traits
+    using iterator_category = std::random_access_iterator_tag;
+    using value_type = typename internal::VariantUtil<ElementVartype>::Type;
+    using difference_type = ptrdiff_t;
+    using reference = value_type&;
+    using const_reference = const value_type&;
+    using pointer = value_type*;
+    using const_pointer = const value_type*;
+
+    LockScope()
+        : safearray_(nullptr),
+          vartype_(VT_EMPTY),
+          array_(nullptr),
+          array_size_(0U) {}
+
+    LockScope(LockScope<ElementVartype>&& other)
+        : safearray_(std::exchange(other.safearray_, nullptr)),
+          vartype_(std::exchange(other.vartype_, VT_EMPTY)),
+          array_(std::exchange(other.array_, nullptr)),
+          array_size_(std::exchange(other.array_size_, 0U)) {}
+
+    LockScope<ElementVartype>& operator=(LockScope<ElementVartype>&& other) {
+      DCHECK_NE(this, &other);
+      Reset();
+      safearray_ = std::exchange(other.safearray_, nullptr);
+      vartype_ = std::exchange(other.vartype_, VT_EMPTY);
+      array_ = std::exchange(other.array_, nullptr);
+      array_size_ = std::exchange(other.array_size_, 0U);
+      return *this;
+    }
+
+    ~LockScope() { Reset(); }
+
+    VARTYPE Type() const { return vartype_; }
+
+    size_t size() const { return array_size_; }
+
+    pointer begin() { return array_; }
+    pointer end() { return array_ + array_size_; }
+    const_pointer begin() const { return array_; }
+    const_pointer end() const { return array_ + array_size_; }
+
+    pointer data() { return array_; }
+    const_pointer data() const { return array_; }
+
+    reference operator[](int index) { return at(index); }
+    const_reference operator[](int index) const { return at(index); }
+
+    reference at(size_t index) {
+      DCHECK_NE(array_, nullptr);
+      DCHECK_LT(index, array_size_);
+      return array_[index];
+    }
+    const_reference at(size_t index) const {
+      return const_cast<LockScope<ElementVartype>*>(this)->at(index);
+    }
+
+   private:
+    LockScope(SAFEARRAY* safearray,
+              VARTYPE vartype,
+              pointer array,
+              size_t array_size)
+        : safearray_(safearray),
+          vartype_(vartype),
+          array_(array),
+          array_size_(array_size) {}
+
+    void Reset() {
+      if (safearray_)
+        SafeArrayUnaccessData(safearray_);
+      safearray_ = nullptr;
+      vartype_ = VT_EMPTY;
+      array_ = nullptr;
+      array_size_ = 0U;
+    }
+
+    SAFEARRAY* safearray_;
+    VARTYPE vartype_;
+    pointer array_;
+    size_t array_size_;
+
+    friend class ScopedSafearray;
+    DISALLOW_COPY_AND_ASSIGN(LockScope);
+  };
+
   explicit ScopedSafearray(SAFEARRAY* safearray = nullptr)
       : safearray_(safearray) {}
 
@@ -35,6 +132,29 @@
 
   ~ScopedSafearray() { Destroy(); }
 
+  // Creates a LockScope for accessing the contents of a
+  // single-dimensional SAFEARRAYs.
+  template <VARTYPE ElementVartype>
+  base::Optional<LockScope<ElementVartype>> CreateLockScope() const {
+    if (!safearray_ || SafeArrayGetDim(safearray_) != 1)
+      return base::nullopt;
+
+    VARTYPE vartype;
+    HRESULT hr = SafeArrayGetVartype(safearray_, &vartype);
+    if (FAILED(hr) ||
+        !internal::VariantUtil<ElementVartype>::IsConvertibleTo(vartype)) {
+      return base::nullopt;
+    }
+
+    typename LockScope<ElementVartype>::pointer array = nullptr;
+    hr = SafeArrayAccessData(safearray_, reinterpret_cast<void**>(&array));
+    if (FAILED(hr))
+      return base::nullopt;
+
+    const size_t array_size = GetCount();
+    return LockScope<ElementVartype>(safearray_, vartype, array, array_size);
+  }
+
   void Destroy() {
     if (safearray_) {
       HRESULT hr = SafeArrayDestroy(safearray_);
@@ -69,9 +189,23 @@
     return &safearray_;
   }
 
-  // Returns the internal pointer. Prefer using operator SAFEARRAY*() instead,
-  // as that will automatically convert for function calls expecting a raw
-  // SAFEARRAY*
+  // Returns the number of elements in a dimension of the array.
+  size_t GetCount(UINT dimension = 0) const {
+    DCHECK(safearray_);
+    // Initialize |lower| and |upper| so this method will return zero if either
+    // SafeArrayGetLBound or SafeArrayGetUBound returns failure because they
+    // only write to the output parameter when successful.
+    LONG lower = 0;
+    LONG upper = -1;
+    DCHECK_LT(dimension, SafeArrayGetDim(safearray_));
+    HRESULT hr = SafeArrayGetLBound(safearray_, dimension + 1, &lower);
+    DCHECK(SUCCEEDED(hr));
+    hr = SafeArrayGetUBound(safearray_, dimension + 1, &upper);
+    DCHECK(SUCCEEDED(hr));
+    return (upper - lower + 1);
+  }
+
+  // Returns the internal pointer.
   SAFEARRAY* Get() const { return safearray_; }
 
   // Forbid comparison of ScopedSafearray types.  You should never have the same
diff --git a/base/win/scoped_safearray_unittest.cc b/base/win/scoped_safearray_unittest.cc
index f91e673..006664f 100644
--- a/base/win/scoped_safearray_unittest.cc
+++ b/base/win/scoped_safearray_unittest.cc
@@ -6,12 +6,39 @@
 
 #include <stddef.h>
 
+#include <array>
+#include <vector>
+
 #include "base/stl_util.h"
+#include "base/test/gtest_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
 namespace win {
 
+namespace {
+
+static constexpr std::array<int, 5> kInputValues = {0, 1, 2, 1, 0};
+
+static void PopulateScopedSafearrayOfInts(ScopedSafearray& scoped_safe_array) {
+  // TODO(crbug.com/1082005): Create a safer alternative to SAFEARRAY methods.
+  scoped_safe_array.Reset(SafeArrayCreateVector(
+      /*vartype=*/VT_I4, /*lower_bound=*/2,
+      /*element_count=*/kInputValues.size()));
+  ASSERT_NE(scoped_safe_array.Get(), nullptr);
+  ASSERT_EQ(SafeArrayGetDim(scoped_safe_array.Get()), 1U);
+  ASSERT_EQ(scoped_safe_array.GetCount(), kInputValues.size());
+
+  int* int_array;
+  ASSERT_HRESULT_SUCCEEDED(SafeArrayAccessData(
+      scoped_safe_array.Get(), reinterpret_cast<void**>(&int_array)));
+  for (size_t i = 0; i < kInputValues.size(); ++i)
+    int_array[i] = kInputValues[i];
+  ASSERT_HRESULT_SUCCEEDED(SafeArrayUnaccessData(scoped_safe_array.Get()));
+}
+
+}  // namespace
+
 TEST(ScopedSafearrayTest, ScopedSafearrayMethods) {
   ScopedSafearray empty_safe_array;
   EXPECT_EQ(empty_safe_array.Get(), nullptr);
@@ -62,6 +89,36 @@
   EXPECT_EQ(safe_array_received.Get(), nullptr);
 }
 
+TEST(ScopedSafearrayTest, ScopedSafearrayMoveConstructor) {
+  ScopedSafearray first;
+  PopulateScopedSafearrayOfInts(first);
+  EXPECT_NE(first.Get(), nullptr);
+  EXPECT_EQ(first.GetCount(), kInputValues.size());
+
+  SAFEARRAY* safearray = first.Get();
+  ScopedSafearray second(std::move(first));
+  EXPECT_EQ(first.Get(), nullptr);
+  EXPECT_EQ(second.Get(), safearray);
+}
+
+TEST(ScopedSafearrayTest, ScopedSafearrayMoveAssignOperator) {
+  ScopedSafearray first, second;
+  PopulateScopedSafearrayOfInts(first);
+  EXPECT_NE(first.Get(), nullptr);
+  EXPECT_EQ(first.GetCount(), kInputValues.size());
+
+  SAFEARRAY* safearray = first.Get();
+  second = std::move(first);
+  EXPECT_EQ(first.Get(), nullptr);
+  EXPECT_EQ(second.Get(), safearray);
+
+  // Indirectly move |second| into itself.
+  ScopedSafearray& reference_to_second = second;
+  second = std::move(reference_to_second);
+  EXPECT_EQ(second.GetCount(), kInputValues.size());
+  EXPECT_EQ(second.Get(), safearray);
+}
+
 TEST(ScopedSafearrayTest, ScopedSafearrayCast) {
   SAFEARRAY* safe_array = SafeArrayCreateVector(
       VT_R8 /* element type */, 1 /* lower bound */, 5 /* elements */);
@@ -84,5 +141,122 @@
   EXPECT_EQ(variable_type, VT_R8);
 }
 
+TEST(ScopedSafearrayTest, InitiallyEmpty) {
+  ScopedSafearray empty_safe_array;
+  EXPECT_EQ(empty_safe_array.Get(), nullptr);
+  EXPECT_DCHECK_DEATH(empty_safe_array.GetCount());
+}
+
+TEST(ScopedSafearrayTest, ScopedSafearrayGetCount) {
+  // TODO(crbug.com/1082005): Create a safer alternative to SAFEARRAY methods.
+  ScopedSafearray scoped_safe_array(SafeArrayCreateVector(
+      /*vartype=*/VT_I4, /*lower_bound=*/2, /*element_count=*/5));
+  ASSERT_NE(scoped_safe_array.Get(), nullptr);
+  EXPECT_EQ(SafeArrayGetDim(scoped_safe_array.Get()), 1U);
+
+  LONG lower_bound;
+  EXPECT_HRESULT_SUCCEEDED(
+      SafeArrayGetLBound(scoped_safe_array.Get(), 1, &lower_bound));
+  EXPECT_EQ(lower_bound, 2);
+
+  LONG upper_bound;
+  EXPECT_HRESULT_SUCCEEDED(
+      SafeArrayGetUBound(scoped_safe_array.Get(), 1, &upper_bound));
+  EXPECT_EQ(upper_bound, 6);
+
+  EXPECT_EQ(scoped_safe_array.GetCount(), 5U);
+}
+
+TEST(ScopedSafearrayTest, ScopedSafearrayInitialLockScope) {
+  ScopedSafearray scoped_safe_array;
+  base::Optional<ScopedSafearray::LockScope<VT_I4>> lock_scope =
+      scoped_safe_array.CreateLockScope<VT_I4>();
+  EXPECT_FALSE(lock_scope.has_value());
+}
+
+TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeMoveConstructor) {
+  ScopedSafearray scoped_safe_array;
+  PopulateScopedSafearrayOfInts(scoped_safe_array);
+
+  base::Optional<ScopedSafearray::LockScope<VT_I4>> first =
+      scoped_safe_array.CreateLockScope<VT_I4>();
+  ASSERT_TRUE(first.has_value());
+  EXPECT_EQ(first->Type(), VT_I4);
+  EXPECT_EQ(first->size(), kInputValues.size());
+
+  ScopedSafearray::LockScope<VT_I4> second(std::move(*first));
+  EXPECT_EQ(first->Type(), VT_EMPTY);
+  EXPECT_EQ(first->size(), 0U);
+  EXPECT_EQ(second.Type(), VT_I4);
+  EXPECT_EQ(second.size(), kInputValues.size());
+}
+
+TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeMoveAssignOperator) {
+  ScopedSafearray scoped_safe_array;
+  PopulateScopedSafearrayOfInts(scoped_safe_array);
+
+  base::Optional<ScopedSafearray::LockScope<VT_I4>> first =
+      scoped_safe_array.CreateLockScope<VT_I4>();
+  ASSERT_TRUE(first.has_value());
+  EXPECT_EQ(first->Type(), VT_I4);
+  EXPECT_EQ(first->size(), kInputValues.size());
+
+  ScopedSafearray::LockScope<VT_I4> second;
+  second = std::move(*first);
+  EXPECT_EQ(first->Type(), VT_EMPTY);
+  EXPECT_EQ(first->size(), 0U);
+  EXPECT_EQ(second.Type(), VT_I4);
+  EXPECT_EQ(second.size(), kInputValues.size());
+
+  // Indirectly move |second| into itself.
+  ScopedSafearray::LockScope<VT_I4>& reference_to_second = second;
+  EXPECT_DCHECK_DEATH(second = std::move(reference_to_second));
+}
+
+TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeTypeMismatch) {
+  ScopedSafearray scoped_safe_array;
+  PopulateScopedSafearrayOfInts(scoped_safe_array);
+
+  {
+    base::Optional<ScopedSafearray::LockScope<VT_BSTR>> invalid_lock_scope =
+        scoped_safe_array.CreateLockScope<VT_BSTR>();
+    EXPECT_FALSE(invalid_lock_scope.has_value());
+  }
+
+  {
+    base::Optional<ScopedSafearray::LockScope<VT_UI4>> invalid_lock_scope =
+        scoped_safe_array.CreateLockScope<VT_UI4>();
+    EXPECT_FALSE(invalid_lock_scope.has_value());
+  }
+}
+
+TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeRandomAccess) {
+  ScopedSafearray scoped_safe_array;
+  PopulateScopedSafearrayOfInts(scoped_safe_array);
+
+  base::Optional<ScopedSafearray::LockScope<VT_I4>> lock_scope =
+      scoped_safe_array.CreateLockScope<VT_I4>();
+  ASSERT_TRUE(lock_scope.has_value());
+  EXPECT_EQ(lock_scope->Type(), VT_I4);
+  EXPECT_EQ(lock_scope->size(), kInputValues.size());
+  for (size_t i = 0; i < kInputValues.size(); ++i) {
+    EXPECT_EQ(lock_scope->at(i), kInputValues[i]);
+    EXPECT_EQ((*lock_scope)[i], kInputValues[i]);
+  }
+}
+
+TEST(ScopedSafearrayTest, ScopedSafearrayLockScopeIterator) {
+  ScopedSafearray scoped_safe_array;
+  PopulateScopedSafearrayOfInts(scoped_safe_array);
+
+  base::Optional<ScopedSafearray::LockScope<VT_I4>> lock_scope =
+      scoped_safe_array.CreateLockScope<VT_I4>();
+
+  std::vector<int> unpacked_vector(lock_scope->begin(), lock_scope->end());
+  ASSERT_EQ(unpacked_vector.size(), kInputValues.size());
+  for (size_t i = 0; i < kInputValues.size(); ++i)
+    EXPECT_EQ(unpacked_vector[i], kInputValues[i]);
+}
+
 }  // namespace win
 }  // namespace base
diff --git a/build/android/gyp/compile_java.py b/build/android/gyp/compile_java.py
index 5a7bcb7f..797592e 100755
--- a/build/android/gyp/compile_java.py
+++ b/build/android/gyp/compile_java.py
@@ -30,11 +30,12 @@
 
 # Full list of checks: https://errorprone.info/bugpatterns
 ERRORPRONE_WARNINGS_TO_TURN_OFF = [
-    # These 2 should really be turned on.
+    # These should really be turned on.
     'ParameterNotNullable',
     'CollectionUndefinedEquality',
     'ModifyCollectionInEnhancedForLoop',
-    # The following 12 are super useful, but too many existing issues.
+    # The following are super useful, but existing issues need to be fixed first
+    # before they can start failing the build on new errors.
     'InvalidParam',
     'InvalidLink',
     'InvalidInlineTag',
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 5e3897c4..f01a966 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -315,9 +315,6 @@
 For some Java related types, a list of extra `.jar` files to use at build time
 but not at runtime.
 
-* `deps_info['extra_classpath_interface_jars']:
-The interface jars corresponding to extra_classpath_jars.
-
 ## <a name="target_java_binary">Target type `java_binary`</a>:
 
 This type corresponds to a Java binary, which is nothing more than a
@@ -1390,87 +1387,62 @@
   if options.type == 'group':
     if options.extra_classpath_jars:
       # These are .jars to add to javac classpath but not to runtime classpath.
-      extra_jars = build_utils.ParseGnList(options.extra_classpath_jars)
-      deps_info['extra_classpath_jars'] = extra_jars
-      deps_info['extra_classpath_interface_jars'] = extra_jars
+      extra_classpath_jars = build_utils.ParseGnList(
+          options.extra_classpath_jars)
+      deps_info['extra_classpath_jars'] = extra_classpath_jars
 
   if is_java_target:
     # The classpath used to compile this target when annotation processors are
     # present.
-    javac_classpath = [
-        c['unprocessed_jar_path'] for c in direct_library_deps]
+    javac_classpath = set(c['unprocessed_jar_path']
+                          for c in direct_library_deps)
     # The classpath used to compile this target when annotation processors are
     # not present. These are also always used to know when a target needs to be
     # rebuilt.
-    javac_interface_classpath = [
-        c['interface_jar_path'] for c in direct_library_deps]
-    # The classpath used for error prone.
-    javac_full_interface_classpath = [
-        c['interface_jar_path'] for c in all_library_deps]
-    # The path of the jetified jars.
-    jetified_full_jar_classpath = [
-        c['jetified_jar_path'] for c in all_library_deps
-    ]
+    javac_interface_classpath = set(c['interface_jar_path']
+                                    for c in direct_library_deps)
     # The classpath used for bytecode-rewritting.
-    javac_full_classpath = [
-        c['unprocessed_jar_path'] for c in all_library_deps]
+    javac_full_classpath = set(c['unprocessed_jar_path']
+                               for c in all_library_deps)
+    # The classpath used for error prone.
+    javac_full_interface_classpath = set(c['interface_jar_path']
+                                         for c in all_library_deps)
+    # The path of the jetified jars.
+    jetified_full_jar_classpath = set(c['jetified_jar_path']
+                                      for c in all_library_deps)
 
     # Adding base module to classpath to compile against its R.java file
     if base_module_build_config:
-      javac_full_classpath.append(
+      javac_full_classpath.add(
           base_module_build_config['deps_info']['unprocessed_jar_path'])
-      javac_full_interface_classpath.append(
+      javac_full_interface_classpath.add(
           base_module_build_config['deps_info']['interface_jar_path'])
-      jetified_full_jar_classpath.append(
+      jetified_full_jar_classpath.add(
           base_module_build_config['deps_info']['jetified_jar_path'])
 
     for dep in direct_group_deps:
-      javac_classpath.extend(dep.get('extra_classpath_jars', []))
-      javac_interface_classpath.extend(
-          dep.get('extra_classpath_interface_jars', []))
+      if 'extra_classpath_jars' in dep:
+        javac_classpath.update(dep['extra_classpath_jars'])
+        javac_interface_classpath.update(dep['extra_classpath_jars'])
     for dep in all_group_deps:
-      javac_full_classpath.extend(dep.get('extra_classpath_jars', []))
-      javac_full_interface_classpath.extend(
-          dep.get('extra_classpath_interface_jars', []))
-      jetified_full_jar_classpath.extend(
-          dep.get('extra_classpath_interface_jars', []))
+      if 'extra_classpath_jars' in dep:
+        javac_full_classpath.update(dep['extra_classpath_jars'])
+        javac_full_interface_classpath.update(dep['extra_classpath_jars'])
+        jetified_full_jar_classpath.update(dep['extra_classpath_jars'])
 
-    # Deps to add to the compile-time classpath (but not the runtime classpath).
     # TODO(agrieve): Might be less confusing to fold these into bootclasspath.
-    javac_extra_jars = []
-    extra_jars = []
-    interface_extra_jars = []
-
+    # Deps to add to the compile-time classpath (but not the runtime classpath).
     # These are jars specified by input_jars_paths that almost never change.
-    # Just add them directly to all the *extra_jars.
+    # Just add them directly to all the classpaths.
     if options.extra_classpath_jars:
-      # These are .jars to add to javac classpath but not to runtime classpath.
-      javac_extra_jars.extend(
-          build_utils.ParseGnList(options.extra_classpath_jars))
-      extra_jars.extend(build_utils.ParseGnList(options.extra_classpath_jars))
-      interface_extra_jars.extend(
-          build_utils.ParseGnList(options.extra_classpath_jars))
-
-    if extra_jars:
-      deps_info['extra_classpath_jars'] = extra_jars
-
-    if interface_extra_jars:
-      deps_info['extra_classpath_interface_jars'] = interface_extra_jars
-
-    javac_extra_jars = [p for p in javac_extra_jars if p not in javac_classpath]
-    javac_classpath.extend(javac_extra_jars)
-    javac_full_classpath.extend(
-        p for p in javac_extra_jars if p not in javac_full_classpath)
-
-    interface_extra_jars = [
-        p for p in interface_extra_jars if p not in javac_interface_classpath
-    ]
-    javac_interface_classpath.extend(interface_extra_jars)
-    javac_full_interface_classpath.extend(
-        p for p in interface_extra_jars
-        if p not in javac_full_interface_classpath)
-    jetified_full_jar_classpath.extend(
-        p for p in interface_extra_jars if p not in jetified_full_jar_classpath)
+      extra_classpath_jars = build_utils.ParseGnList(
+          options.extra_classpath_jars)
+      deps_info['extra_classpath_jars'] = extra_classpath_jars
+      javac_classpath.update(extra_classpath_jars)
+      javac_interface_classpath.update(extra_classpath_jars)
+      javac_full_classpath.update(extra_classpath_jars)
+      javac_full_interface_classpath.update(extra_classpath_jars)
+      jetified_full_jar_classpath.update(extra_classpath_jars)
 
   if is_java_target or options.type == 'android_app_bundle':
     # The classpath to use to run this target (or as an input to ProGuard).
@@ -1715,21 +1687,16 @@
         if p not in device_classpath)
     # Include in the classpath classes that are added directly to the apk under
     # test (those that are not a part of a java_library).
-    javac_classpath.append(tested_apk_config['unprocessed_jar_path'])
-    javac_full_classpath.append(tested_apk_config['unprocessed_jar_path'])
-    javac_interface_classpath.append(tested_apk_config['interface_jar_path'])
-    javac_full_interface_classpath.append(
-        tested_apk_config['interface_jar_path'])
-    jetified_full_jar_classpath.append(tested_apk_config['interface_jar_path'])
-    javac_full_interface_classpath.extend(
-        p for p in tested_apk_config['javac_full_interface_classpath']
-        if p not in javac_full_interface_classpath)
-    jetified_full_jar_classpath.extend(
-        p for p in tested_apk_config['jetified_full_jar_classpath']
-        if p not in jetified_full_jar_classpath)
-    javac_full_classpath.extend(
-        p for p in tested_apk_config['javac_full_classpath']
-        if p not in javac_full_classpath)
+    javac_classpath.add(tested_apk_config['unprocessed_jar_path'])
+    javac_interface_classpath.add(tested_apk_config['interface_jar_path'])
+    javac_full_classpath.add(tested_apk_config['unprocessed_jar_path'])
+    javac_full_interface_classpath.add(tested_apk_config['interface_jar_path'])
+    jetified_full_jar_classpath.add(tested_apk_config['interface_jar_path'])
+    javac_full_classpath.update(tested_apk_config['javac_full_classpath'])
+    javac_full_interface_classpath.update(
+        tested_apk_config['javac_full_interface_classpath'])
+    jetified_full_jar_classpath.update(
+        tested_apk_config['jetified_full_jar_classpath'])
 
     # Exclude .jar files from the test apk that exist within the apk under test.
     tested_apk_library_deps = tested_apk_deps.All('java_library')
@@ -1756,8 +1723,8 @@
     dex_config['all_dex_files'] = all_dex_files
 
   if is_java_target:
-    config['javac']['classpath'] = javac_classpath
-    config['javac']['interface_classpath'] = javac_interface_classpath
+    config['javac']['classpath'] = sorted(javac_classpath)
+    config['javac']['interface_classpath'] = sorted(javac_interface_classpath)
     # Direct() will be of type 'java_annotation_processor', and so not included
     # in All('java_library').
     # Annotation processors run as part of the build, so need host_jar_path.
@@ -1770,9 +1737,11 @@
     ]
     config['javac']['processor_classes'] = [
         c['main_class'] for c in processor_deps.Direct()]
-    deps_info['javac_full_classpath'] = javac_full_classpath
-    deps_info['javac_full_interface_classpath'] = javac_full_interface_classpath
-    deps_info['jetified_full_jar_classpath'] = jetified_full_jar_classpath
+    deps_info['javac_full_classpath'] = sorted(javac_full_classpath)
+    deps_info['javac_full_interface_classpath'] = sorted(
+        javac_full_interface_classpath)
+    deps_info['jetified_full_jar_classpath'] = sorted(
+        jetified_full_jar_classpath)
   elif options.type == 'android_app_bundle':
     # bundles require javac_full_classpath to create .aab.jar.info.
     javac_full_classpath = set()
diff --git a/build/android/pylib/instrumentation/instrumentation_parser.py b/build/android/pylib/instrumentation/instrumentation_parser.py
index d38f6a5..dd9f9cc5 100644
--- a/build/android/pylib/instrumentation/instrumentation_parser.py
+++ b/build/android/pylib/instrumentation/instrumentation_parser.py
@@ -22,6 +22,10 @@
 
 STATUS_CODE_TEST_DURATION = 1337
 
+# When a test batch fails due to post-test Assertion failures (eg.
+# LifetimeAssert).
+STATUS_CODE_BATCH_FAILURE = 1338
+
 # http://developer.android.com/reference/android/app/Activity.html
 RESULT_CODE_OK = -1
 RESULT_CODE_CANCELED = 0
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index e3e8348..f1a7a0b 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -147,6 +147,14 @@
   cumulative_duration = 0
 
   for status_code, bundle in statuses:
+    # If the last test was a failure already, don't override that failure with
+    # post-test failures that could be caused by the original failure.
+    if (status_code == instrumentation_parser.STATUS_CODE_BATCH_FAILURE
+        and current_result.GetType() != base_test_result.ResultType.FAIL):
+      current_result.SetType(base_test_result.ResultType.FAIL)
+      _MaybeSetLog(bundle, current_result, symbolizer, device_abi)
+      continue
+
     if status_code == instrumentation_parser.STATUS_CODE_TEST_DURATION:
       # For the first result, duration will be set below to the difference
       # between the reported and actual durations to account for overhead like
@@ -185,13 +193,7 @@
           logging.error('Unrecognized status code %d. Handling as an error.',
                         status_code)
         current_result.SetType(base_test_result.ResultType.FAIL)
-    if _BUNDLE_STACK_ID in bundle:
-      if symbolizer and device_abi:
-        current_result.SetLog('%s\n%s' % (bundle[_BUNDLE_STACK_ID], '\n'.join(
-            symbolizer.ExtractAndResolveNativeStackTraces(
-                bundle[_BUNDLE_STACK_ID], device_abi))))
-      else:
-        current_result.SetLog(bundle[_BUNDLE_STACK_ID])
+    _MaybeSetLog(bundle, current_result, symbolizer, device_abi)
 
   if current_result:
     if current_result.GetType() == base_test_result.ResultType.UNKNOWN:
@@ -211,6 +213,16 @@
   return results
 
 
+def _MaybeSetLog(bundle, current_result, symbolizer, device_abi):
+  if _BUNDLE_STACK_ID in bundle:
+    if symbolizer and device_abi:
+      current_result.SetLog('%s\n%s' % (bundle[_BUNDLE_STACK_ID], '\n'.join(
+          symbolizer.ExtractAndResolveNativeStackTraces(
+              bundle[_BUNDLE_STACK_ID], device_abi))))
+    else:
+      current_result.SetLog(bundle[_BUNDLE_STACK_ID])
+
+
 def FilterTests(tests, filter_str=None, annotations=None,
                 excluded_annotations=None):
   """Filter a list of tests
diff --git a/build/config/python.gni b/build/config/python.gni
index 79dcc6e..3ac4898 100644
--- a/build/config/python.gni
+++ b/build/config/python.gni
@@ -103,7 +103,8 @@
     # Happens every time the template is instantiated, but benchmarking shows no
     # perceivable impact on overall 'gn gen' speed.
     _pydeps_file = invoker.script + "deps"
-    _pydeps_lines = read_file(_pydeps_file, "list lines")
+    _pydeps_lines =
+        read_file(_pydeps_file, "list lines")  # https://crbug.com/1102058
     _pydeps_entries = filter_exclude(_pydeps_lines, [ "#*" ])
 
     if (!defined(inputs)) {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 9925789..5acf57e 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20200706.0.1
+0.20200706.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 9925789..a7a9825d 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20200706.0.1
+0.20200706.1.1
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index f7fba64..971c865 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -15,10 +15,11 @@
 // See http://dev.chromium.org/developers/testing/threadsanitizer-tsan-v2
 // for the instructions on writing suppressions.
 char kTSanDefaultSuppressions[] =
-    // False positives in libdconfsettings.so, libflashplayer.so, libgio.so,
-    // libglib.so and libgobject.so.
+    // False positives in libdbus.so, libdconfsettings.so, libflashplayer.so,
+    // libgio.so, libglib.so and libgobject.so.
     // Since we don't instrument them, we cannot reason about the
     // synchronization in them.
+    "race:libdbus*.so\n"
     "race:libdconfsettings*.so\n"
     "race:libflashplayer.so\n"
     "race:libgio*.so\n"
diff --git a/buildtools/DEPS b/buildtools/DEPS
index c038f4a5..4703a66 100644
--- a/buildtools/DEPS
+++ b/buildtools/DEPS
@@ -14,7 +14,7 @@
   #
 
   # GN CIPD package version.
-  'gn_version': 'git_revision:b6203d186bff6b39ac25af6c1e80e1d3f96c949a',
+  'gn_version': 'git_revision:d585128cdaf3e6ff7bfd58641965e60c12618eb1',
 
   # When changing these, also update the svn revisions in deps_revisions.gni
   'clang_format_revision': '96636aa0e9f047f17447f2d45a094d0b59ed7917',
diff --git a/buildtools/checkdeps/OWNERS b/buildtools/checkdeps/OWNERS
deleted file mode 100644
index 06fefbf4..0000000
--- a/buildtools/checkdeps/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-brettw@chromium.org
diff --git a/buildtools/checkdeps/builddeps.py b/buildtools/checkdeps/builddeps.py
index 519228d..2fe48b2 100755
--- a/buildtools/checkdeps/builddeps.py
+++ b/buildtools/checkdeps/builddeps.py
@@ -233,6 +233,7 @@
       'File': FileImpl,
       'From': FromImpl,
       'Var': _VarImpl(local_scope).Lookup,
+      'Str': str,
     }
     deps_file_path = os.path.join(dir_path_local_abs, 'DEPS')
 
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index 43309848..0c4ac27 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -38,7 +38,7 @@
 class EventMetrics;
 class ScrollElasticityHelper;
 
-enum PointerResultType { kUnhandled = 0, kScrollbarScroll };
+enum class PointerResultType { kUnhandled = 0, kScrollbarScroll };
 
 // These enum values are reported in UMA. So these values should never be
 // removed or changed.
@@ -53,7 +53,7 @@
   InputHandlerPointerResult() = default;
   // Tells what type of processing occurred in the input handler as a result of
   // the pointer event.
-  PointerResultType type = kUnhandled;
+  PointerResultType type = PointerResultType::kUnhandled;
 
   // Tells what scroll_units should be used.
   ui::ScrollGranularity scroll_units =
@@ -128,7 +128,7 @@
  public:
   // Note these are used in a histogram. Do not reorder or delete existing
   // entries.
-  enum ScrollThread {
+  enum class ScrollThread {
     SCROLL_ON_MAIN_THREAD = 0,
     SCROLL_ON_IMPL_THREAD,
     SCROLL_IGNORED,
@@ -150,7 +150,7 @@
         : thread(thread),
           main_thread_scrolling_reasons(main_thread_scrolling_reasons),
           needs_main_thread_hit_test(needs_main_thread_hit_test) {}
-    ScrollThread thread = SCROLL_ON_IMPL_THREAD;
+    ScrollThread thread = ScrollThread::SCROLL_ON_IMPL_THREAD;
     uint32_t main_thread_scrolling_reasons =
         MainThreadScrollingReason::kNotScrollingOnMain;
     bool bubble = false;
diff --git a/cc/metrics/frame_sequence_metrics.cc b/cc/metrics/frame_sequence_metrics.cc
index 5e57019..c87391387 100644
--- a/cc/metrics/frame_sequence_metrics.cc
+++ b/cc/metrics/frame_sequence_metrics.cc
@@ -72,9 +72,10 @@
                                 FrameSequenceMetrics::ThreadType thread_type) {
   const auto sequence_type = metrics->type();
 
-  // For touch/wheel scroll, the slower thread is the one we want to report. For
-  // pinch-zoom, it's the compositor-thread.
-  if (sequence_type == FrameSequenceTrackerType::kTouchScroll ||
+  // For scrollbar/touch/wheel scroll, the slower thread is the one we want to
+  // report. For pinch-zoom, it's the compositor-thread.
+  if (sequence_type == FrameSequenceTrackerType::kScrollbarScroll ||
+      sequence_type == FrameSequenceTrackerType::kTouchScroll ||
       sequence_type == FrameSequenceTrackerType::kWheelScroll)
     return thread_type == metrics->GetEffectiveThread();
 
@@ -85,7 +86,8 @@
 }
 
 bool IsInteractionType(FrameSequenceTrackerType sequence_type) {
-  return sequence_type == FrameSequenceTrackerType::kTouchScroll ||
+  return sequence_type == FrameSequenceTrackerType::kScrollbarScroll ||
+         sequence_type == FrameSequenceTrackerType::kTouchScroll ||
          sequence_type == FrameSequenceTrackerType::kWheelScroll ||
          sequence_type == FrameSequenceTrackerType::kPinchZoom;
 }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 4b932597..8fa1a1c 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -131,6 +131,8 @@
 #include "ui/gfx/geometry/vector2d_f.h"
 #include "ui/gfx/skia_util.h"
 
+using ScrollThread = cc::InputHandler::ScrollThread;
+
 namespace cc {
 namespace {
 
@@ -228,10 +230,10 @@
                                   TRACE_ID_LOCAL(id));
 }
 
-enum ScrollThread { MAIN_THREAD, CC_THREAD };
+enum SlowScrollMetricThread { MAIN_THREAD, CC_THREAD };
 
 void RecordCompositorSlowScrollMetric(ui::ScrollInputType type,
-                                      ScrollThread scroll_thread) {
+                                      SlowScrollMetricThread scroll_thread) {
   bool scroll_on_main_thread = (scroll_thread == MAIN_THREAD);
   if (type == ui::ScrollInputType::kWheel) {
     UMA_HISTOGRAM_BOOLEAN("Renderer4.CompositorWheelScrollUpdateThread",
@@ -839,16 +841,10 @@
   bool did_animate = false;
 
   if (input_handler_client_) {
-    // This animates fling scrolls. But on Android WebView root flings are
-    // controlled by the application, so the compositor does not animate them.
-    bool ignore_fling =
-        settings_.ignore_root_layer_flings && IsCurrentlyScrollingViewport();
-    if (!ignore_fling) {
-      // This does not set did_animate, because if the InputHandlerClient
-      // changes anything it will be through the InputHandler interface which
-      // does SetNeedsRedraw.
-      input_handler_client_->Animate(monotonic_time);
-    }
+    // This does not set did_animate, because if the InputHandlerClient
+    // changes anything it will be through the InputHandler interface which
+    // does SetNeedsRedraw.
+    input_handler_client_->Animate(monotonic_time);
   }
 
   did_animate |= AnimatePageScale(monotonic_time);
@@ -926,8 +922,6 @@
 }
 
 void LayerTreeHostImpl::SetNeedsAnimateInput() {
-  DCHECK(!IsCurrentlyScrollingViewport() ||
-         !settings_.ignore_root_layer_flings);
   SetNeedsOneBeginImplFrame();
 }
 
@@ -3050,11 +3044,6 @@
 bool LayerTreeHostImpl::IsActivelyPrecisionScrolling() const {
   if (!CurrentlyScrollingNode())
     return false;
-  // On Android WebView root flings are controlled by the application,
-  // so the compositor does not animate them and can't tell if they
-  // are actually animating. So assume there are none.
-  if (settings_.ignore_root_layer_flings && IsCurrentlyScrollingViewport())
-    return false;
 
   if (!last_scroll_update_state_)
     return false;
@@ -3809,7 +3798,7 @@
     TRACE_EVENT1("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread",
                  "MainThreadScrollingReason",
                  scroll_node->main_thread_scrolling_reasons);
-    scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
+    scroll_status.thread = ScrollThread::SCROLL_ON_MAIN_THREAD;
     scroll_status.main_thread_scrolling_reasons =
         scroll_node->main_thread_scrolling_reasons;
     return scroll_status;
@@ -3819,7 +3808,7 @@
       scroll_tree.ScreenSpaceTransform(scroll_node->id);
   if (!screen_space_transform.IsInvertible()) {
     TRACE_EVENT0("cc", "LayerImpl::TryScroll: Ignored NonInvertibleTransform");
-    scroll_status.thread = InputHandler::SCROLL_IGNORED;
+    scroll_status.thread = ScrollThread::SCROLL_IGNORED;
     scroll_status.main_thread_scrolling_reasons =
         MainThreadScrollingReason::kNonInvertibleTransform;
     return scroll_status;
@@ -3827,7 +3816,7 @@
 
   if (!scroll_node->scrollable) {
     TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored not scrollable");
-    scroll_status.thread = InputHandler::SCROLL_IGNORED;
+    scroll_status.thread = ScrollThread::SCROLL_IGNORED;
     scroll_status.main_thread_scrolling_reasons =
         MainThreadScrollingReason::kNotScrollable;
     return scroll_status;
@@ -3843,7 +3832,7 @@
       !active_tree_->LayerByElementId(scroll_node->element_id)) {
     TRACE_EVENT0("cc",
                  "LayerImpl::tryScroll: Failed due to no scrolling layer");
-    scroll_status.thread = InputHandler::SCROLL_ON_MAIN_THREAD;
+    scroll_status.thread = ScrollThread::SCROLL_ON_MAIN_THREAD;
     scroll_status.main_thread_scrolling_reasons =
         MainThreadScrollingReason::kNonFastScrollableRegion;
     return scroll_status;
@@ -3859,19 +3848,19 @@
     TRACE_EVENT0("cc",
                  "LayerImpl::tryScroll: Ignored. Technically scrollable,"
                  " but has no affordance in either direction.");
-    scroll_status.thread = InputHandler::SCROLL_IGNORED;
+    scroll_status.thread = ScrollThread::SCROLL_IGNORED;
     scroll_status.main_thread_scrolling_reasons =
         MainThreadScrollingReason::kNotScrollable;
     return scroll_status;
   }
 
-  scroll_status.thread = InputHandler::SCROLL_ON_IMPL_THREAD;
+  scroll_status.thread = ScrollThread::SCROLL_ON_IMPL_THREAD;
   return scroll_status;
 }
 
 static bool IsMainThreadScrolling(const InputHandler::ScrollStatus& status,
                                   const ScrollNode* scroll_node) {
-  if (status.thread == InputHandler::SCROLL_ON_MAIN_THREAD) {
+  if (status.thread == ScrollThread::SCROLL_ON_MAIN_THREAD) {
     if (!!scroll_node->main_thread_scrolling_reasons) {
       DCHECK(MainThreadScrollingReason::MainThreadCanSetScrollReasons(
           status.main_thread_scrolling_reasons));
@@ -3946,7 +3935,7 @@
         return scroll_node;
       }
 
-      if (status.thread == InputHandler::SCROLL_ON_IMPL_THREAD &&
+      if (status.thread == ScrollThread::SCROLL_ON_IMPL_THREAD &&
           !impl_scroll_node) {
         impl_scroll_node = scroll_node;
       }
@@ -3985,7 +3974,7 @@
   TRACE_EVENT0("cc", "LayerTreeHostImpl::RootScrollBegin");
   if (!OuterViewportScrollNode()) {
     ScrollStatus scroll_status;
-    scroll_status.thread = InputHandler::SCROLL_IGNORED;
+    scroll_status.thread = ScrollThread::SCROLL_IGNORED;
     scroll_status.main_thread_scrolling_reasons =
         MainThreadScrollingReason::kNoScrollingLayer;
     return scroll_status;
@@ -4086,7 +4075,7 @@
         // thread. However, these cases shouldn't be user perceptible.
         scroll_status.main_thread_scrolling_reasons =
             MainThreadScrollingReason::kNoScrollingLayer;
-        scroll_status.thread = SCROLL_IGNORED;
+        scroll_status.thread = ScrollThread::SCROLL_IGNORED;
         return scroll_status;
       }
     } else {
@@ -4106,7 +4095,7 @@
           NOTREACHED();
           scroll_status.main_thread_scrolling_reasons =
               MainThreadScrollingReason::kNoScrollingLayer;
-          scroll_status.thread = SCROLL_IGNORED;
+          scroll_status.thread = ScrollThread::SCROLL_IGNORED;
           return scroll_status;
         }
 
@@ -4122,7 +4111,7 @@
                                        type)) {
             TRACE_EVENT_INSTANT0("cc", "Scrollbar Scrolling",
                                  TRACE_EVENT_SCOPE_THREAD);
-            scroll_status.thread = SCROLL_ON_MAIN_THREAD;
+            scroll_status.thread = ScrollThread::SCROLL_ON_MAIN_THREAD;
             scroll_status.main_thread_scrolling_reasons =
                 MainThreadScrollingReason::kScrollbarScrolling;
             return scroll_status;
@@ -4139,7 +4128,7 @@
           // ElementId of the hit-tested scroll node.
           TRACE_EVENT_INSTANT0("cc", "Request Main Thread Hit Test",
                                TRACE_EVENT_SCOPE_THREAD);
-          scroll_status.thread = SCROLL_ON_IMPL_THREAD;
+          scroll_status.thread = ScrollThread::SCROLL_ON_IMPL_THREAD;
           scroll_status.needs_main_thread_hit_test = true;
           return scroll_status;
         }
@@ -4160,7 +4149,7 @@
                                        type)) {
             TRACE_EVENT_INSTANT0("cc", "Scrollbar Scrolling",
                                  TRACE_EVENT_SCOPE_THREAD);
-            scroll_status.thread = SCROLL_ON_MAIN_THREAD;
+            scroll_status.thread = ScrollThread::SCROLL_ON_MAIN_THREAD;
             scroll_status.main_thread_scrolling_reasons =
                 MainThreadScrollingReason::kScrollbarScrolling;
             return scroll_status;
@@ -4168,7 +4157,7 @@
                          layer_impl, first_scrolling_layer_or_scrollbar)) {
             TRACE_EVENT_INSTANT0("cc", "Failed Hit Test",
                                  TRACE_EVENT_SCOPE_THREAD);
-            scroll_status.thread = SCROLL_UNKNOWN;
+            scroll_status.thread = ScrollThread::SCROLL_UNKNOWN;
             scroll_status.main_thread_scrolling_reasons =
                 MainThreadScrollingReason::kFailedHitTest;
             return scroll_status;
@@ -4193,7 +4182,7 @@
     DCHECK(!base::FeatureList::IsEnabled(features::kScrollUnification));
 
     RecordCompositorSlowScrollMetric(type, MAIN_THREAD);
-    scroll_status.thread = SCROLL_ON_MAIN_THREAD;
+    scroll_status.thread = ScrollThread::SCROLL_ON_MAIN_THREAD;
     return scroll_status;
   } else if (!scrolling_node) {
     scroll_status.main_thread_scrolling_reasons =
@@ -4204,7 +4193,7 @@
       // returning SCROLL_UNKNOWN.
       TRACE_EVENT_INSTANT0("cc", "Ignored - No ScrollNode (OOPIF)",
                            TRACE_EVENT_SCOPE_THREAD);
-      scroll_status.thread = SCROLL_UNKNOWN;
+      scroll_status.thread = ScrollThread::SCROLL_UNKNOWN;
     } else {
       // If we didn't hit a layer above we'd usually fallback to the
       // viewport scroll node. However, there may not be one if a scroll
@@ -4214,14 +4203,14 @@
       // configurations where input is allowed prior to a commit.
       TRACE_EVENT_INSTANT0("cc", "Ignored - No ScrollNode",
                            TRACE_EVENT_SCOPE_THREAD);
-      scroll_status.thread = SCROLL_IGNORED;
+      scroll_status.thread = ScrollThread::SCROLL_IGNORED;
     }
     return scroll_status;
   }
 
   DCHECK_EQ(scroll_status.main_thread_scrolling_reasons,
             MainThreadScrollingReason::kNotScrollingOnMain);
-  DCHECK_EQ(scroll_status.thread, SCROLL_ON_IMPL_THREAD);
+  DCHECK_EQ(scroll_status.thread, ScrollThread::SCROLL_ON_IMPL_THREAD);
 
   active_tree_->SetCurrentlyScrollingNode(scrolling_node);
 
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 8aa56e63..801f695 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -113,6 +113,8 @@
 using ::testing::_;
 using media::VideoFrame;
 
+using ScrollThread = cc::InputHandler::ScrollThread;
+
 namespace viz {
 struct FrameTimingDetails;
 }
@@ -515,10 +517,10 @@
             .get(),
         ui::ScrollInputType::kWheel);
     if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-      ASSERT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+      ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
       ASSERT_TRUE(status.needs_main_thread_hit_test);
     } else {
-      ASSERT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread);
+      ASSERT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
       ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest,
                 status.main_thread_scrolling_reasons);
     }
@@ -530,10 +532,10 @@
             .get(),
         ui::ScrollInputType::kWheel);
     if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-      ASSERT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+      ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
       ASSERT_TRUE(status.needs_main_thread_hit_test);
     } else {
-      ASSERT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread);
+      ASSERT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
       ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest,
                 status.main_thread_scrolling_reasons);
     }
@@ -545,7 +547,7 @@
                    ui::ScrollInputType::kWheel)
             .get(),
         ui::ScrollInputType::kWheel);
-    ASSERT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   }
 
   LayerImpl* AddScrollableLayer(LayerImpl* container,
@@ -1129,7 +1131,7 @@
                                          ui::ScrollInputType::kWheel)
                                   .get(),
                               ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_IGNORED, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer,
             status.main_thread_scrolling_reasons);
 
@@ -1138,7 +1140,7 @@
                                              ui::ScrollInputType::kWheel)
                                       .get(),
                                   ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_IGNORED, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer,
             status.main_thread_scrolling_reasons);
 }
@@ -1173,7 +1175,7 @@
                                            ui::ScrollInputType::kTouchscreen)
                                     .get(),
                                 ui::ScrollInputType::kTouchscreen);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_TRUE(host_impl_->CurrentlyScrollingNode());
 
     host_impl_->ScrollUpdate(UpdateState(gfx::Point(), gfx::Vector2d(0, 10),
@@ -1201,7 +1203,7 @@
   {
     InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
         scroll_state.get(), ui::ScrollInputType::kWheel);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_EQ(host_impl_->OuterViewportScrollNode(),
               host_impl_->CurrentlyScrollingNode());
     host_impl_->ScrollEnd();
@@ -1218,13 +1220,13 @@
     InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
         scroll_state.get(), ui::ScrollInputType::kWheel);
     if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-      EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+      EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
       EXPECT_FALSE(status.needs_main_thread_hit_test);
       EXPECT_EQ(
           MainThreadScrollingReason::kThreadedScrollingDisabled,
           host_impl_->CurrentlyScrollingNode()->main_thread_scrolling_reasons);
     } else {
-      EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+      EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
       EXPECT_EQ(
           host_impl_->OuterViewportScrollNode()->main_thread_scrolling_reasons,
           status.main_thread_scrolling_reasons);
@@ -1242,7 +1244,7 @@
                                          ui::ScrollInputType::kWheel)
                                   .get(),
                               ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
 
@@ -1277,7 +1279,7 @@
                                            ui::ScrollInputType::kTouchscreen)
                                     .get(),
                                 ui::ScrollInputType::kTouchscreen);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
               status.main_thread_scrolling_reasons);
     EXPECT_FALSE(host_impl_->IsActivelyPrecisionScrolling());
@@ -1307,7 +1309,7 @@
                                            ui::ScrollInputType::kWheel)
                                     .get(),
                                 ui::ScrollInputType::kWheel);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_FALSE(host_impl_->IsActivelyPrecisionScrolling());
 
     host_impl_->ScrollUpdate(
@@ -1353,7 +1355,7 @@
                                          ui::ScrollInputType::kWheel)
                                   .get(),
                               ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_IGNORED, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer,
             status.main_thread_scrolling_reasons);
 }
@@ -1377,7 +1379,7 @@
                                          ui::ScrollInputType::kWheel)
                                   .get(),
                               ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
 }
@@ -1389,7 +1391,7 @@
   // We should not crash if the tree is replaced while we are scrolling.
   gfx::ScrollOffset scroll_delta(0, 10);
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(),
                                    gfx::ScrollOffsetToVector2dF(scroll_delta),
@@ -1424,7 +1426,7 @@
                  ui::ScrollInputType::kWheel)
           .get(),
       ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
   host_impl_->ScrollUpdate(UpdateState(gfx::Point(), gfx::Vector2d(0, 10),
@@ -1469,7 +1471,7 @@
                                          ui::ScrollInputType::kWheel)
                                   .get(),
                               ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
   host_impl_->ScrollEnd();
@@ -1505,7 +1507,7 @@
                                          ui::ScrollInputType::kTouchscreen)
                                   .get(),
                               ui::ScrollInputType::kTouchscreen);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
   host_impl_->ScrollEnd();
@@ -1539,13 +1541,13 @@
                                   .get(),
                               ui::ScrollInputType::kWheel);
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_FALSE(status.needs_main_thread_hit_test);
     EXPECT_EQ(
         MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
         host_impl_->CurrentlyScrollingNode()->main_thread_scrolling_reasons);
   } else {
-    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
               status.main_thread_scrolling_reasons);
   }
@@ -1556,13 +1558,13 @@
                                   .get(),
                               ui::ScrollInputType::kTouchscreen);
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_FALSE(status.needs_main_thread_hit_test);
     EXPECT_EQ(
         MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
         host_impl_->CurrentlyScrollingNode()->main_thread_scrolling_reasons);
   } else {
-    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
               status.main_thread_scrolling_reasons);
   }
@@ -1613,12 +1615,12 @@
           .get(),
       ui::ScrollInputType::kWheel);
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
               status.main_thread_scrolling_reasons);
     EXPECT_TRUE(status.needs_main_thread_hit_test);
   } else {
-    EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest,
               status.main_thread_scrolling_reasons);
   }
@@ -1630,7 +1632,7 @@
                  ui::ScrollInputType::kWheel)
           .get(),
       ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
 }
@@ -1725,12 +1727,12 @@
           .get(),
       ui::ScrollInputType::kWheel);
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
               status.main_thread_scrolling_reasons);
     EXPECT_TRUE(status.needs_main_thread_hit_test);
   } else {
-    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
               status.main_thread_scrolling_reasons);
   }
@@ -1741,12 +1743,12 @@
           .get(),
       ui::ScrollInputType::kTouchscreen);
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
               status.main_thread_scrolling_reasons);
     EXPECT_TRUE(status.needs_main_thread_hit_test);
   } else {
-    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
               status.main_thread_scrolling_reasons);
   }
@@ -1757,7 +1759,7 @@
                  ui::ScrollInputType::kWheel)
           .get(),
       ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
 
@@ -1771,7 +1773,7 @@
                  ui::ScrollInputType::kTouchscreen)
           .get(),
       ui::ScrollInputType::kTouchscreen);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
   host_impl_->ScrollUpdate(UpdateState(gfx::Point(), gfx::Vector2d(0, 10),
@@ -1797,7 +1799,7 @@
                  ui::ScrollInputType::kWheel)
           .get(),
       ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
   EXPECT_FALSE(status.needs_main_thread_hit_test);
@@ -1814,12 +1816,12 @@
           .get(),
       ui::ScrollInputType::kWheel);
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
               status.main_thread_scrolling_reasons);
     EXPECT_TRUE(status.needs_main_thread_hit_test);
   } else {
-    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
               status.main_thread_scrolling_reasons);
   }
@@ -1864,7 +1866,7 @@
                                          ui::ScrollInputType::kTouchscreen)
                                   .get(),
                               ui::ScrollInputType::kTouchscreen);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             status.main_thread_scrolling_reasons);
 
@@ -1962,7 +1964,7 @@
 
   gfx::Point pointer_position(10, 10);
   gfx::Vector2dF x_delta(20, 0);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, x_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2007,7 +2009,7 @@
 
   gfx::Point pointer_position(10, 10);
   gfx::Vector2dF y_delta(0, 20);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, y_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2052,7 +2054,7 @@
 
   gfx::Point pointer_position(10, 10);
   gfx::Vector2dF delta(20, 20);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, delta,
                                          ui::ScrollInputType::kWheel)
@@ -2098,7 +2100,7 @@
 
   gfx::Point pointer_position(10, 10);
   gfx::Vector2dF y_delta(0, 20);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, y_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2114,7 +2116,7 @@
   gfx::Point pointer_position(10, 10);
   gfx::Vector2dF delta(20, 20);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, delta,
                                          ui::ScrollInputType::kWheel)
@@ -2171,7 +2173,7 @@
 
   gfx::Point pointer_position(10, 10);
   gfx::Vector2dF y_delta(0, 20);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, y_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2234,7 +2236,7 @@
 
   gfx::Point pointer_position(10, 10);
   gfx::Vector2dF x_delta(20, 0);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, x_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2273,7 +2275,7 @@
   begin_state->data()->delta_granularity =
       ui::ScrollGranularity::kScrollByPrecisePixel;
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_->ScrollBegin(begin_state.get(), ui::ScrollInputType::kWheel)
           .thread);
   EXPECT_FALSE(host_impl_->IsAnimatingForSnap());
@@ -2298,7 +2300,7 @@
 
   gfx::Point pointer_position(10, 10);
   gfx::Vector2dF x_delta(50, 0);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, x_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2348,7 +2350,7 @@
   // Should be (10, 10) in the scroller's coordinate.
   gfx::Point pointer_position(2, 2);
   gfx::Vector2dF delta(4, 4);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, delta,
                                          ui::ScrollInputType::kWheel)
@@ -2388,7 +2390,7 @@
   // Should be (10, 10) in the scroller's coordinate.
   gfx::Point pointer_position(2, 2);
   gfx::Vector2dF delta(4, 4);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, delta,
                                          ui::ScrollInputType::kWheel)
@@ -2440,7 +2442,7 @@
   gfx::Vector2dF diagonal_delta(-10, -10);
 
   // OverscrollBehaviorTypeAuto shouldn't prevent scroll propagation.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, x_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2465,7 +2467,7 @@
 
   // OverscrollBehaviorContain on x should prevent propagations of scroll
   // on x.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, x_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2484,7 +2486,7 @@
 
   // OverscrollBehaviorContain on x shouldn't prevent propagations of
   // scroll on y.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, y_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2503,7 +2505,7 @@
 
   // A scroll update with both x & y delta will adhere to the most restrictive
   // case.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, diagonal_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2529,7 +2531,7 @@
 
   // OverscrollBehaviorContain on y shouldn't prevent propagations of
   // scroll on x.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, x_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2548,7 +2550,7 @@
 
   // OverscrollBehaviorContain on y should prevent propagations of scroll
   // on y.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, y_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2567,7 +2569,7 @@
 
   // A scroll update with both x & y delta will adhere to the most restrictive
   // case.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, diagonal_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2592,7 +2594,7 @@
 
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(pointer_position, x_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2634,7 +2636,7 @@
   gfx::Point scroll_position(10, 10);
   gfx::Vector2dF scroll_delta(10, 10);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(scroll_position, scroll_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2655,7 +2657,7 @@
 
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(scroll_position, scroll_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2675,7 +2677,7 @@
   GetScrollNode(overflow)->user_scrollable_vertical = false;
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(scroll_position, scroll_delta,
                                          ui::ScrollInputType::kWheel)
@@ -2711,7 +2713,7 @@
       ui::ScrollInputType::kWheel);
 
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
               status.main_thread_scrolling_reasons);
     // We don't have a layer for the scroller but we didn't hit a non-fast
@@ -2719,7 +2721,7 @@
     // thread hit test in this case.
     EXPECT_FALSE(status.needs_main_thread_hit_test);
   } else {
-    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
               status.main_thread_scrolling_reasons);
   }
@@ -3016,7 +3018,7 @@
     host_impl_->ScrollEnd();
 
     gfx::Vector2d scroll_delta(0, 10);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                            ui::ScrollInputType::kWheel)
@@ -3444,7 +3446,7 @@
       new LatencyInfoSwapPromise(latency_info));
 
   SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100));
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 10),
                                          ui::ScrollInputType::kTouchscreen)
@@ -4996,7 +4998,7 @@
                                            ui::ScrollInputType::kWheel)
                                     .get(),
                                 ui::ScrollInputType::kWheel);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     host_impl_->ScrollEnd();
   }
 
@@ -5007,7 +5009,7 @@
                                            ui::ScrollInputType::kTouchscreen)
                                     .get(),
                                 ui::ScrollInputType::kTouchscreen);
-    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kScrollbarScrolling,
               status.main_thread_scrolling_reasons);
   }
@@ -5019,7 +5021,7 @@
                                            ui::ScrollInputType::kWheel)
                                     .get(),
                                 ui::ScrollInputType::kWheel);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
               status.main_thread_scrolling_reasons);
     host_impl_->ScrollEnd();
@@ -5032,7 +5034,7 @@
                                            ui::ScrollInputType::kTouchscreen)
                                     .get(),
                                 ui::ScrollInputType::kTouchscreen);
-    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kScrollbarScrolling,
               status.main_thread_scrolling_reasons);
   }
@@ -5502,7 +5504,7 @@
   }
 
   // Scrolling should update metadata immediately.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                          ui::ScrollInputType::kWheel)
@@ -6066,7 +6068,7 @@
                                          ui::ScrollInputType::kWheel)
                                   .get(),
                               ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_IGNORED, status.thread);
   EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer,
             status.main_thread_scrolling_reasons);
   EXPECT_FALSE(did_request_redraw_);
@@ -6199,7 +6201,7 @@
   EXPECT_VIEWPORT_GEOMETRIES(1);
   EXPECT_EQ(gfx::SizeF(50, 50), active_tree->ScrollableSize());
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 25),
                                          ui::ScrollInputType::kTouchscreen)
@@ -6274,7 +6276,7 @@
   EXPECT_EQ(gfx::RectF(0, 0, 160, 160), parent_clip->clip);
   EXPECT_EQ(gfx::RectF(0, 0, 150, 150), scroll_clip->clip);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 25),
                                          ui::ScrollInputType::kTouchscreen)
@@ -6353,7 +6355,7 @@
   EXPECT_VIEWPORT_GEOMETRIES(1.0f);
   EXPECT_EQ(gfx::SizeF(200, 1000), active_tree->ScrollableSize());
 
-  ASSERT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 25),
                                          ui::ScrollInputType::kTouchscreen)
@@ -6403,7 +6405,7 @@
   EXPECT_EQ(gfx::Size(50, 15), scrollbar_layer->bounds());
   EXPECT_EQ(gfx::Rect(20, 0, 10, 3), scrollbar_layer->ComputeThumbQuadRect());
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 25),
                                          ui::ScrollInputType::kTouchscreen)
@@ -6458,7 +6460,7 @@
 
   gfx::Vector2dF top_controls_scroll_delta(0, 5.25f);
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(), top_controls_scroll_delta,
                                    ui::ScrollInputType::kTouchscreen)
@@ -6498,7 +6500,7 @@
   outer_scroll->SetDrawsContent(true);
   host_impl_->active_tree()->PushPageScaleFromMainThread(2, 1, 2);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 50),
                                          ui::ScrollInputType::kTouchscreen)
@@ -6526,7 +6528,7 @@
 
   host_impl_->ScrollEnd();
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, -50),
                                          ui::ScrollInputType::kTouchscreen)
@@ -6587,7 +6589,7 @@
 
   gfx::Vector2dF top_controls_scroll_delta(0, 20);
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(), top_controls_scroll_delta,
                                    ui::ScrollInputType::kTouchscreen)
@@ -6610,7 +6612,7 @@
   // Scroll past the maximum extent. The delta shouldn't be greater than the
   // browser controls height.
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(), top_controls_scroll_delta,
                                    ui::ScrollInputType::kTouchscreen)
@@ -6628,7 +6630,7 @@
 
   // Scroll in the direction to make the browser controls show.
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(), -top_controls_scroll_delta,
                                    ui::ScrollInputType::kTouchscreen)
@@ -6701,7 +6703,7 @@
 
   // Scroll 25px to hide browser controls
   gfx::Vector2dF scroll_delta(0, 25);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -6902,7 +6904,7 @@
 
   // Hide the browser controls by 25px.
   gfx::Vector2dF scroll_delta(0, 25);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -6933,7 +6935,7 @@
 
   // Bring the browser controls down by 25px.
   scroll_delta = gfx::Vector2dF(0, -25);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -6967,7 +6969,7 @@
                   host_impl_->browser_controls_manager()->ContentTopOffset());
 
   gfx::Vector2dF scroll_delta(0, 25);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -7009,7 +7011,7 @@
   // Send a gesture scroll that will scroll the outer viewport, make sure the
   // browser controls get scrolled.
   gfx::Vector2dF scroll_delta(0, 15);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -7030,7 +7032,7 @@
           host_impl_->browser_controls_manager()->ContentTopOffset());
 
   scroll_delta = gfx::Vector2dF(0, 50);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -7053,7 +7055,7 @@
   SetScrollOffsetDelta(InnerViewportScrollLayer(), inner_viewport_offset);
 
   scroll_delta = gfx::Vector2dF(0, -65);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -7079,7 +7081,7 @@
       layer_size_, layer_size_, layer_size_);
   DrawFrame();
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 50),
                                          ui::ScrollInputType::kTouchscreen)
@@ -7098,7 +7100,7 @@
 
   host_impl_->ScrollEnd();
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, -25),
                                          ui::ScrollInputType::kTouchscreen)
@@ -7130,7 +7132,7 @@
   // Verify the layer is once-again non-scrollable.
   EXPECT_EQ(gfx::ScrollOffset(), MaxScrollOffset(InnerViewportScrollLayer()));
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                          ui::ScrollInputType::kTouchscreen)
@@ -7291,7 +7293,7 @@
   DrawFrame();
 
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(5, 5), gfx::Vector2dF(0, 10),
                                    ui::ScrollInputType::kWheel)
@@ -7320,7 +7322,7 @@
   DrawFrame();
 
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(5, 5), gfx::Vector2dF(0, 10),
                                    ui::ScrollInputType::kWheel)
@@ -7349,7 +7351,7 @@
                  ui::ScrollInputType::kWheel)
           .get(),
       ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(host_impl_->CurrentlyScrollingNode(),
             host_impl_->OuterViewportScrollNode());
 
@@ -7379,7 +7381,7 @@
                  ui::ScrollInputType::kWheel)
           .get(),
       ui::ScrollInputType::kWheel);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
   EXPECT_EQ(host_impl_->CurrentlyScrollingNode(),
             host_impl_->OuterViewportScrollNode());
 
@@ -7408,7 +7410,7 @@
           .get(),
       ui::ScrollInputType::kWheel);
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_FALSE(status.needs_main_thread_hit_test);
     EXPECT_EQ(
         MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
@@ -7416,7 +7418,7 @@
   } else {
     // Scrolling fails because the content layer is asking to be scrolled on the
     // main thread.
-    EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
               status.main_thread_scrolling_reasons);
   }
@@ -7436,7 +7438,7 @@
   gfx::ScrollOffset expected_scroll_delta(scroll_delta);
   LayerImpl* outer_scroll = OuterViewportScrollLayer();
   gfx::ScrollOffset expected_max_scroll = MaxScrollOffset(outer_scroll);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                          ui::ScrollInputType::kWheel)
@@ -7480,7 +7482,7 @@
   gfx::ScrollOffset expected_scroll_delta(scroll_delta);
   LayerImpl* outer_scroll = OuterViewportScrollLayer();
   gfx::ScrollOffset expected_max_scroll = MaxScrollOffset(outer_scroll);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                          ui::ScrollInputType::kWheel)
@@ -7581,7 +7583,7 @@
   gfx::Vector2d scroll_delta(0, 10);
   gfx::ScrollOffset expected_scroll_delta(scroll_delta);
   gfx::ScrollOffset expected_max_scroll(MaxScrollOffset(outer_scroll));
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                          ui::ScrollInputType::kWheel)
@@ -7639,7 +7641,7 @@
   DrawFrame();
   {
     gfx::Vector2d scroll_delta(-8, -7);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                            ui::ScrollInputType::kWheel)
@@ -7697,7 +7699,7 @@
   viz::BeginFrameArgs begin_frame_args =
       viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, -100),
                                          ui::ScrollInputType::kWheel)
@@ -7781,7 +7783,7 @@
   DrawFrame();
   {
     gfx::Vector2d scroll_delta(0, -10);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                            ui::ScrollInputType::kTouchscreen)
@@ -7806,7 +7808,7 @@
 
     // The next time we scroll we should only scroll the parent.
     scroll_delta = gfx::Vector2d(0, -3);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                            ui::ScrollInputType::kTouchscreen)
@@ -7837,7 +7839,7 @@
     // After scrolling the parent, another scroll on the opposite direction
     // should still scroll the child.
     scroll_delta = gfx::Vector2d(0, 7);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                            ui::ScrollInputType::kTouchscreen)
@@ -7870,7 +7872,7 @@
     host_impl_->active_tree()->SetPageScaleOnActiveTree(2);
 
     scroll_delta = gfx::Vector2d(0, -2);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(1, 1), scroll_delta,
                                            ui::ScrollInputType::kTouchscreen)
@@ -7915,7 +7917,7 @@
     gfx::ScrollOffset scroll_delta(0, 4);
     // Scrolling should be able to happen on the compositor thread here.
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(BeginState(gfx::Point(5, 5),
                                      gfx::ScrollOffsetToVector2dF(scroll_delta),
@@ -7958,7 +7960,7 @@
   {
     gfx::ScrollOffset scroll_delta(0, 4);
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(BeginState(gfx::Point(5, 5),
                                      gfx::ScrollOffsetToVector2dF(scroll_delta),
@@ -7998,7 +8000,7 @@
 
   // Scrolling should still work even though we did not draw yet.
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(5, 5), gfx::Vector2dF(0, 10),
                                    ui::ScrollInputType::kWheel)
@@ -8021,7 +8023,7 @@
 
   // Scroll to the right in screen coordinates with a gesture.
   gfx::Vector2d gesture_scroll_delta(10, 0);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gesture_scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -8043,7 +8045,7 @@
   // Reset and scroll down with the wheel.
   SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF());
   gfx::ScrollOffset wheel_scroll_delta(0, 10);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(
                     BeginState(gfx::Point(),
@@ -8100,7 +8102,7 @@
     // Scroll down in screen coordinates with a gesture.
     gfx::Vector2d gesture_scroll_delta(0, 10);
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(BeginState(gfx::Point(1, 1), gesture_scroll_delta,
                                      ui::ScrollInputType::kTouchscreen)
@@ -8131,7 +8133,7 @@
     SetScrollOffsetDelta(child, gfx::Vector2dF());
     gfx::Vector2d gesture_scroll_delta(10, 0);
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(BeginState(gfx::Point(1, 1), gesture_scroll_delta,
                                      ui::ScrollInputType::kTouchscreen)
@@ -8212,7 +8214,7 @@
   for (int i = 0; i < 4; ++i) {
     SetScrollOffsetDelta(child, gfx::Vector2dF());
     DrawFrame();
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(viewport_point,
                                            gfx::ScrollOffsetToVector2dF(
@@ -8254,7 +8256,7 @@
 
   // Scroll down in screen coordinates with a gesture.
   gfx::Vector2d scroll_delta(0, 10);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -8277,7 +8279,7 @@
   // Reset and scroll down with the wheel.
   SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF());
   gfx::ScrollOffset wheel_scroll_delta(0, 10);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(
                     BeginState(gfx::Point(),
@@ -8382,7 +8384,7 @@
   gfx::Vector2dF scroll_delta(0, 10);
   gfx::ScrollOffset current_offset(7, 8);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                          ui::ScrollInputType::kTouchscreen)
@@ -8498,7 +8500,7 @@
     auto begin_state = BeginState(gfx::Point(), scroll_delta,
                                   ui::ScrollInputType::kTouchscreen);
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(begin_state.get(), ui::ScrollInputType::kTouchscreen)
             .thread);
@@ -8541,7 +8543,7 @@
     auto begin_state =
         BeginState(gfx::Point(), scroll_delta, ui::ScrollInputType::kWheel);
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_->ScrollBegin(begin_state.get(), ui::ScrollInputType::kWheel)
             .thread);
 
@@ -8763,7 +8765,7 @@
   EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
 
   // In-bounds scrolling does not affect overscroll.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                          ui::ScrollInputType::kWheel)
@@ -8937,7 +8939,7 @@
   DrawFrame();
   {
     gfx::Vector2d scroll_delta(0, -10);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                            ui::ScrollInputType::kTouchscreen)
@@ -8958,7 +8960,7 @@
     // The next time we scroll we should only scroll the parent, but overscroll
     // should still not reach the root layer.
     scroll_delta = gfx::Vector2d(0, -30);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                            ui::ScrollInputType::kTouchscreen)
@@ -8970,7 +8972,7 @@
     EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
     host_impl_->ScrollEnd();
 
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                            ui::ScrollInputType::kTouchscreen)
@@ -8991,7 +8993,7 @@
     // After scrolling the parent, another scroll on the opposite direction
     // should scroll the child.
     scroll_delta = gfx::Vector2d(0, 70);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                            ui::ScrollInputType::kTouchscreen)
@@ -9022,7 +9024,7 @@
   DrawFrame();
   {
     gfx::Vector2d scroll_delta(0, 8);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(5, 5), scroll_delta,
                                            ui::ScrollInputType::kWheel)
@@ -9064,7 +9066,7 @@
   EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
 
   // Even though the layer can't scroll the overscroll still happens.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                          ui::ScrollInputType::kWheel)
@@ -9091,7 +9093,7 @@
     // of the content. unnecessary glow effect calls shouldn't be
     // called while scrolling up without reaching the edge of the content.
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 100),
                                      ui::ScrollInputType::kWheel)
@@ -9118,7 +9120,7 @@
     // unusedrootDelta should be subtracted from applied delta so that
     // unwanted glow effect calls are not called.
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 20),
                                      ui::ScrollInputType::kTouchscreen)
@@ -9145,7 +9147,7 @@
     host_impl_->ScrollEnd();
     // TestCase to check  kEpsilon, which prevents minute values to trigger
     // gloweffect without reaching edge.
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(
                       BeginState(gfx::Point(0, 0), gfx::Vector2dF(-0.12f, 0.1f),
@@ -9257,7 +9259,7 @@
   EXPECT_EQ(nullptr, host_impl_->active_tree()->FindLayerThatIsHitByPoint(
                          gfx::PointF(0, 60)));
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_MAIN_THREAD,
+      ScrollThread::SCROLL_ON_MAIN_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(0, 60), gfx::Vector2dF(0, 10),
                                    ui::ScrollInputType::kWheel)
@@ -9269,7 +9271,7 @@
   EXPECT_NE(nullptr, host_impl_->active_tree()->FindLayerThatIsHitByPoint(
                          gfx::PointF(0, 0)));
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_MAIN_THREAD,
+      ScrollThread::SCROLL_ON_MAIN_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 10),
                                    ui::ScrollInputType::kWheel)
@@ -9677,7 +9679,7 @@
   EXPECT_EQ(nullptr, host_impl_->active_tree()->FindLayerThatIsHitByPoint(
                          gfx::PointF(0, 60)));
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(0, 60), gfx::Vector2dF(0, 10),
                                    ui::ScrollInputType::kWheel)
@@ -9691,7 +9693,7 @@
   EXPECT_NE(nullptr, host_impl_->active_tree()->FindLayerThatIsHitByPoint(
                          gfx::PointF(0, 0)));
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 10),
                                    ui::ScrollInputType::kWheel)
@@ -11125,7 +11127,7 @@
 // LayerTreeHostImpl::IsInitialScrollHitTestReliable for details.
 TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollHitTestIsNotReliable) {
   // If we ray cast a scroller that is not on the first layer's ancestor chain,
-  // we should return SCROLL_UNKNOWN.
+  // we should return ScrollThread::SCROLL_UNKNOWN.
   gfx::Size viewport_size(50, 50);
   gfx::Size content_size(100, 100);
   SetupViewportLayersOuterScrolls(viewport_size, content_size);
@@ -11148,10 +11150,10 @@
                                   .get(),
                               ui::ScrollInputType::kWheel);
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_TRUE(status.needs_main_thread_hit_test);
   } else {
-    EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest,
               status.main_thread_scrolling_reasons);
   }
@@ -11162,7 +11164,7 @@
 TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollHitTestAncestorMismatch) {
   // If we ray cast a scroller this is on the first layer's ancestor chain, but
   // is not the first scroller we encounter when walking up from the layer, we
-  // should also return SCROLL_UNKNOWN.
+  // should also return ScrollThread::SCROLL_UNKNOWN.
   gfx::Size viewport_size(50, 50);
   gfx::Size content_size(100, 100);
   SetupViewportLayersOuterScrolls(viewport_size, content_size);
@@ -11191,10 +11193,10 @@
                                   .get(),
                               ui::ScrollInputType::kWheel);
   if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_TRUE(status.needs_main_thread_hit_test);
   } else {
-    EXPECT_EQ(InputHandler::SCROLL_UNKNOWN, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest,
               status.main_thread_scrolling_reasons);
   }
@@ -11214,7 +11216,7 @@
 
   // We should have scrolled |child_scroll| even though it does not move
   // any layer that is a drawn RSLL member.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                          ui::ScrollInputType::kWheel)
@@ -11403,7 +11405,7 @@
     SetupViewportLayersInnerScrolls(gfx::Size(50, 50), gfx::Size(100, 100));
 
     // Scrolling normally should not trigger any forwarding.
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                            ui::ScrollInputType::kTouchscreen)
@@ -11424,7 +11426,7 @@
     // Scrolling with a scroll handler should defer the swap to the main
     // thread.
     host_impl_->active_tree()->set_have_scroll_event_handlers(true);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                            ui::ScrollInputType::kTouchscreen)
@@ -11533,7 +11535,7 @@
   const float residue = 10;
   float offset = top_controls_height_ - residue;
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, offset),
                                    ui::ScrollInputType::kTouchscreen)
@@ -11620,7 +11622,7 @@
   LayerImpl* viewport_layer = InnerViewportScrollLayer();
 
   const float delta = top_controls_height_;
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, delta),
                                          ui::ScrollInputType::kWheel)
@@ -11668,7 +11670,7 @@
   const float residue = 35;
   float offset = top_controls_height_ - residue;
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, offset),
                                    ui::ScrollInputType::kTouchscreen)
@@ -11759,7 +11761,7 @@
   const float residue = 15;
   float offset = top_controls_height_ - residue;
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, offset),
                                    ui::ScrollInputType::kTouchscreen)
@@ -11837,7 +11839,7 @@
 
   float offset = 50;
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, offset),
                                    ui::ScrollInputType::kTouchscreen)
@@ -12028,7 +12030,7 @@
                                inner_viewport.height() / 2);
 
     // Make sure the scroll goes to the inner viewport first.
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                            ui::ScrollInputType::kTouchscreen)
@@ -12078,7 +12080,7 @@
   DrawFrame();
 
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_
           ->RootScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                        ui::ScrollInputType::kTouchscreen)
@@ -12088,7 +12090,7 @@
   EXPECT_EQ(host_impl_->CurrentlyScrollingNode(),
             host_impl_->OuterViewportScrollNode());
   host_impl_->ScrollEnd();
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                          ui::ScrollInputType::kTouchscreen)
@@ -12117,7 +12119,7 @@
 
   // Ensure inner viewport doesn't react to scrolls (test it's unscrollable).
   EXPECT_VECTOR_EQ(gfx::Vector2dF(), CurrentScrollOffset(inner_scroll));
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 100),
                                          ui::ScrollInputType::kTouchscreen)
@@ -12505,7 +12507,7 @@
   LayerImpl* scrolling_layer = OuterViewportScrollLayer();
 
   host_impl_->set_force_smooth_wheel_scrolling_for_testing(false);
-  ASSERT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 50),
                                          ui::ScrollInputType::kWheel)
@@ -12652,7 +12654,7 @@
         new SimpleSwapPromiseMonitor(nullptr, host_impl_.get(),
                                      &set_needs_commit_count,
                                      &set_needs_redraw_count));
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 50),
                                            ui::ScrollInputType::kWheel)
@@ -12859,7 +12861,7 @@
   // animation update code.
   {
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(BeginState(gfx::Point(10, 10), gfx::Vector2d(0, 10),
                                      ui::ScrollInputType::kWheel)
@@ -13335,7 +13337,7 @@
     auto begin_state = BeginState(gfx::Point(350, 575), gfx::Vector2d(0, 40),
                                   ui::ScrollInputType::kScrollbar);
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(begin_state.get(), ui::ScrollInputType::kScrollbar)
             .thread);
@@ -13503,7 +13505,7 @@
     auto begin_state = BeginState(gfx::Point(350, 560), gfx::Vector2d(0, 40),
                                   ui::ScrollInputType::kScrollbar);
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_
             ->ScrollBegin(begin_state.get(), ui::ScrollInputType::kScrollbar)
             .thread);
@@ -13538,7 +13540,7 @@
         host_impl_->scrollbar_controller_for_testing()->ScrollbarLayer());
 
     EXPECT_EQ(
-        InputHandler::SCROLL_ON_IMPL_THREAD,
+        ScrollThread::SCROLL_ON_IMPL_THREAD,
         host_impl_->ScrollBegin(begin_state.get(), ui::ScrollInputType::kWheel)
             .thread);
 
@@ -13724,7 +13726,7 @@
   const gfx::Size viewport_size(50, 100);
   SetupViewportLayersOuterScrolls(viewport_size, content_size);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                          ui::ScrollInputType::kWheel)
@@ -13735,7 +13737,7 @@
   host_impl_->ScrollEnd();
 
   // The second ScrollBegin should not get ignored.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                          ui::ScrollInputType::kWheel)
@@ -13765,7 +13767,7 @@
   host_impl_->UpdateAnimationState(true);
   host_impl_->DidFinishImplFrame(begin_frame_args);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 50),
                                          ui::ScrollInputType::kWheel)
@@ -13818,7 +13820,7 @@
       viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
 
   // Create animation with a 100ms delay.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 100),
                                          ui::ScrollInputType::kWheel)
@@ -13884,7 +13886,7 @@
       viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
 
   // Perform animated scroll.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 50),
                                          ui::ScrollInputType::kWheel)
@@ -13929,7 +13931,7 @@
   begin_state->data()->delta_granularity =
       ui::ScrollGranularity::kScrollByPrecisePixel;
   EXPECT_EQ(
-      InputHandler::SCROLL_ON_IMPL_THREAD,
+      ScrollThread::SCROLL_ON_IMPL_THREAD,
       host_impl_->ScrollBegin(begin_state.get(), ui::ScrollInputType::kWheel)
           .thread);
   auto update_state = UpdateState(gfx::Point(0, y), gfx::Vector2d(0, 50),
@@ -13965,7 +13967,7 @@
   viz::BeginFrameArgs begin_frame_args =
       viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(0, 50),
                                          ui::ScrollInputType::kWheel)
@@ -14055,7 +14057,7 @@
       base::TimeTicks() + base::TimeDelta::FromMilliseconds(250);
   viz::BeginFrameArgs begin_frame_args =
       viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(10, 20),
                                          ui::ScrollInputType::kWheel)
@@ -14151,7 +14153,7 @@
       base::TimeTicks() + base::TimeDelta::FromMilliseconds(50);
   viz::BeginFrameArgs begin_frame_args =
       viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(90, 90),
                                          ui::ScrollInputType::kWheel)
@@ -14215,7 +14217,7 @@
   viz::BeginFrameArgs begin_frame_args =
       viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2d(50, 50),
                                          ui::ScrollInputType::kWheel)
@@ -14431,7 +14433,7 @@
     host_impl_->ScrollEnd();
 
     gfx::Vector2dF scroll_delta(0, 5);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
               host_impl_
                   ->ScrollBegin(BeginState(gfx::Point(), scroll_delta,
                                            ui::ScrollInputType::kWheel)
@@ -15504,7 +15506,7 @@
   }
 
   // Scrolling should update metadata immediately.
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(0, 10),
                                          ui::ScrollInputType::kWheel)
@@ -15767,7 +15769,7 @@
   ScrollTree& scroll_tree =
       host_impl_->active_tree()->property_trees()->scroll_tree;
 
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD,
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
             host_impl_
                 ->ScrollBegin(BeginState(gfx::Point(), gfx::Vector2dF(),
                                          ui::ScrollInputType::kTouchscreen)
@@ -16200,7 +16202,7 @@
                  ui::ScrollInputType::kTouchscreen)
           .get(),
       ui::ScrollInputType::kTouchscreen);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
 }
 
 TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
@@ -16619,7 +16621,7 @@
   {
     ScrollStatus status = ScrollBegin(Vector2d(0, 10));
 
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_TRUE(status.needs_main_thread_hit_test);
 
     // The scroll hasn't started yet though.
@@ -16632,7 +16634,7 @@
   {
     ScrollStatus status = ContinuedScrollBegin(ScrollerElementId());
 
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_FALSE(status.needs_main_thread_hit_test);
 
     EXPECT_TRUE(CurrentlyScrollingNode());
@@ -16708,7 +16710,7 @@
                               "");
 #else
     status = ContinuedScrollBegin(kInvalidId);
-    EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_IGNORED, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer,
               status.main_thread_scrolling_reasons);
 #endif
@@ -16726,7 +16728,7 @@
 
     ScrollStatus status = ScrollBegin(Vector2d(0, 10));
     status = ContinuedScrollBegin(kUnknown);
-    EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_IGNORED, status.thread);
     EXPECT_EQ(MainThreadScrollingReason::kNoScrollingLayer,
               status.main_thread_scrolling_reasons);
   }
@@ -16751,7 +16753,7 @@
   // thread hit test.
   {
     ScrollStatus status = ScrollBegin(Vector2d(0, 10));
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_TRUE(status.needs_main_thread_hit_test);
   }
 
@@ -16759,7 +16761,7 @@
   // normal on the impl thread.
   {
     ScrollStatus status = ContinuedScrollBegin(ScrollerElementId());
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_FALSE(status.needs_main_thread_hit_test);
 
     EXPECT_TRUE(CurrentlyScrollingNode());
@@ -16776,7 +16778,7 @@
 
   {
     ScrollStatus status = ScrollBegin(Vector2d(0, 10));
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_FALSE(status.needs_main_thread_hit_test);
   }
 }
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index 3a95b18..7009c549 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -41,6 +41,8 @@
 
 using ::testing::Mock;
 
+using ScrollThread = cc::InputHandler::ScrollThread;
+
 namespace cc {
 namespace {
 
@@ -693,7 +695,7 @@
         InputHandler::ScrollStatus status =
             impl->ScrollBegin(BeginState(scroll_point, scroll_amount_).get(),
                               ui::ScrollInputType::kTouchscreen);
-        EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
         impl->ScrollUpdate(UpdateState(gfx::Point(), scroll_amount_).get());
         auto* scrolling_node = impl->CurrentlyScrollingNode();
         CHECK(scrolling_node);
@@ -717,7 +719,7 @@
         InputHandler::ScrollStatus status =
             impl->ScrollBegin(BeginState(scroll_point, scroll_amount_).get(),
                               ui::ScrollInputType::kWheel);
-        EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
         impl->ScrollUpdate(UpdateState(gfx::Point(), scroll_amount_).get());
         impl->ScrollEnd();
 
@@ -1126,7 +1128,7 @@
           ui::ScrollGranularity::kScrollByPixel;
       InputHandler::ScrollStatus status = host_impl->ScrollBegin(
           scroll_state.get(), ui::ScrollInputType::kWheel);
-      EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+      EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
       scroll_state = UpdateState(scroll_point, scroll_amount);
       scroll_state->data()->delta_granularity =
           ui::ScrollGranularity::kScrollByPixel;
@@ -1187,7 +1189,7 @@
       new ScrollState(begin_scroll_state_data));
   auto scroll_status = host_impl->ScrollBegin(
       begin_scroll_state.get(), ui::ScrollInputType::kTouchscreen);
-  EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, scroll_status.thread);
+  EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, scroll_status.thread);
   auto* scrolling_node = host_impl->CurrentlyScrollingNode();
   EXPECT_TRUE(scrolling_node);
   EXPECT_EQ(scrolling_node->element_id, scroller->element_id());
@@ -1537,7 +1539,7 @@
     ScrollState scroll_state(scroll_state_data);
     InputHandler::ScrollStatus status =
         impl->ScrollBegin(&scroll_state, ui::ScrollInputType::kTouchscreen);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread)
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread)
         << "In Frame " << impl->active_tree()->source_frame_number();
 
     switch (cur_step_) {
@@ -1604,11 +1606,11 @@
         BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 1)).get(),
         ui::ScrollInputType::kTouchscreen);
     if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-      EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+      EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
       EXPECT_TRUE(status.needs_main_thread_hit_test);
       impl->ScrollEnd();
     } else {
-      EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+      EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
       EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
                 status.main_thread_scrolling_reasons);
     }
@@ -1616,7 +1618,7 @@
     status = impl->ScrollBegin(
         BeginState(gfx::Point(21, 21), gfx::Vector2dF(0, 1)).get(),
         ui::ScrollInputType::kTouchscreen);
-    EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+    EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
     EXPECT_FALSE(status.needs_main_thread_hit_test);
     EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
               status.main_thread_scrolling_reasons);
@@ -1684,7 +1686,7 @@
         // scrolling reason, we still must fallback to main thread scrolling due
         // to the fact that it has a main thread scrolling ancestor.
         EXPECT_EQ(impl->CurrentlyScrollingNode(), nullptr);
-        EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
         EXPECT_EQ(MainThreadScrollingReason::kThreadedScrollingDisabled,
                   status.main_thread_scrolling_reasons);
       }
@@ -1700,7 +1702,7 @@
       InputHandler::ScrollStatus status =
           impl->ScrollBegin(&scroll_state, ui::ScrollInputType::kTouchscreen);
       if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-        EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
         EXPECT_FALSE(status.needs_main_thread_hit_test);
         EXPECT_EQ(impl->CurrentlyScrollingNode(),
                   impl->OuterViewportScrollNode());
@@ -1708,7 +1710,7 @@
         // Since the viewport has a main thread scrolling reason, this
         // too should fallback to the main thread.
         EXPECT_EQ(impl->CurrentlyScrollingNode(), nullptr);
-        EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
         EXPECT_EQ(MainThreadScrollingReason::kThreadedScrollingDisabled,
                   status.main_thread_scrolling_reasons);
       }
@@ -2681,13 +2683,13 @@
       if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
         // Hitting a non fast region should request a hit test from the main
         // thread.
-        EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
         EXPECT_TRUE(status.needs_main_thread_hit_test);
         impl->ScrollEnd();
       } else {
         // Prior to scroll unification, this forces scrolling to the main
         // thread.
-        EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
         EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
                   status.main_thread_scrolling_reasons);
       }
@@ -2700,10 +2702,10 @@
           BeginState(gfx::Point(80, 20), gfx::Vector2dF(0, 1)).get(),
           ui::ScrollInputType::kTouchscreen);
       if (base::FeatureList::IsEnabled(features::kScrollUnification)) {
-        EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
         EXPECT_FALSE(status.needs_main_thread_hit_test);
       } else {
-        EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
         EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
                   status.main_thread_scrolling_reasons);
       }
@@ -2720,7 +2722,7 @@
         // Even though the point intersects a non-fast region, the first hit
         // layer is scrollable from the compositor thread so no need to involve
         // the main thread.
-        EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
         EXPECT_FALSE(status.needs_main_thread_hit_test);
         EXPECT_EQ(scroll_node, impl->CurrentlyScrollingNode());
         impl->ScrollEnd();
@@ -2728,7 +2730,7 @@
         // Though the middle layer is a composited scroller and is hit first, we
         // cannot do a fast scroll because an ancestor on the scroll chain has
         // hit a non-fast region.
-        EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread);
+        EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
         EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion,
                   status.main_thread_scrolling_reasons);
       }
@@ -2787,7 +2789,7 @@
           BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 10)).get(),
           ui::ScrollInputType::kTouchscreen);
 
-      ASSERT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+      ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
       ASSERT_EQ(layer_->scroll_tree_index(),
                 impl->CurrentlyScrollingNode()->id);
 
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 446d467..4bb6d8a0 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -89,7 +89,6 @@
   bool use_zero_copy = false;
   bool use_partial_raster = false;
   bool enable_elastic_overscroll = false;
-  bool ignore_root_layer_flings = false;
   size_t scheduled_raster_task_limit = 32;
   bool use_occlusion_for_tile_prioritization = false;
   bool use_layer_lists = false;
diff --git a/cc/trees/ukm_manager.cc b/cc/trees/ukm_manager.cc
index 9d4eab1..37ecb8a 100644
--- a/cc/trees/ukm_manager.cc
+++ b/cc/trees/ukm_manager.cc
@@ -112,6 +112,7 @@
         CASE_FOR_MAIN_THREAD_TRACKER(MainThreadAnimation);
         CASE_FOR_MAIN_THREAD_TRACKER(PinchZoom);
         CASE_FOR_MAIN_THREAD_TRACKER(RAF);
+        CASE_FOR_MAIN_THREAD_TRACKER(ScrollbarScroll);
         CASE_FOR_MAIN_THREAD_TRACKER(TouchScroll);
         CASE_FOR_MAIN_THREAD_TRACKER(Universal);
         CASE_FOR_MAIN_THREAD_TRACKER(Video);
@@ -135,6 +136,7 @@
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(MainThreadAnimation);
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(PinchZoom);
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(RAF);
+        CASE_FOR_COMPOSITOR_THREAD_TRACKER(ScrollbarScroll);
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(TouchScroll);
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(Universal);
         CASE_FOR_COMPOSITOR_THREAD_TRACKER(Video);
@@ -157,6 +159,7 @@
         CASE_FOR_SLOWER_THREAD_TRACKER(MainThreadAnimation);
         CASE_FOR_SLOWER_THREAD_TRACKER(PinchZoom);
         CASE_FOR_SLOWER_THREAD_TRACKER(RAF);
+        CASE_FOR_SLOWER_THREAD_TRACKER(ScrollbarScroll);
         CASE_FOR_SLOWER_THREAD_TRACKER(TouchScroll);
         CASE_FOR_SLOWER_THREAD_TRACKER(Universal);
         CASE_FOR_SLOWER_THREAD_TRACKER(Video);
@@ -280,6 +283,7 @@
       CASE_FOR_TRACKER(MainThreadAnimation);
       CASE_FOR_TRACKER(PinchZoom);
       CASE_FOR_TRACKER(RAF);
+      CASE_FOR_TRACKER(ScrollbarScroll);
       CASE_FOR_TRACKER(TouchScroll);
       CASE_FOR_TRACKER(Video);
       CASE_FOR_TRACKER(WheelScroll);
diff --git a/cc/trees/ukm_manager_unittest.cc b/cc/trees/ukm_manager_unittest.cc
index 2b55162..ad0b88c 100644
--- a/cc/trees/ukm_manager_unittest.cc
+++ b/cc/trees/ukm_manager_unittest.cc
@@ -74,6 +74,7 @@
 const char kMainThreadAnimation[] = "MainThreadAnimation";
 const char kPinchZoom[] = "PinchZoom";
 const char kRAF[] = "RAF";
+const char kScrollbarScroll[] = "ScrollbarScroll";
 const char kTouchScroll[] = "TouchScroll";
 const char kUniversal[] = "Universal";
 const char kVideo[] = "Video";
@@ -261,6 +262,8 @@
 
   CompositorFrameReporter::ActiveTrackers active_trackers;
   active_trackers.set(
+      static_cast<size_t>(FrameSequenceTrackerType::kScrollbarScroll));
+  active_trackers.set(
       static_cast<size_t>(FrameSequenceTrackerType::kTouchScroll));
   active_trackers.set(
       static_cast<size_t>(FrameSequenceTrackerType::kCompositorAnimation));
@@ -336,6 +339,7 @@
 
   test_ukm_recorder_->ExpectEntryMetric(entry, kCompositorAnimation, true);
   test_ukm_recorder_->ExpectEntryMetric(entry, kTouchScroll, true);
+  test_ukm_recorder_->ExpectEntryMetric(entry, kScrollbarScroll, true);
   EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kMainThreadAnimation));
   EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kPinchZoom));
   EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kRAF));
diff --git a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
index 57274b41..eaaebd3 100644
--- a/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.proguard_flags.expected
@@ -82,12 +82,15 @@
 
 # Contains flags that we'd like all Chromium .apks to use.
 
-# Not needed for Android and saves a bit of processing time.
--dontpreverify
-
 # Keep line number information, useful for stack traces.
 -keepattributes SourceFile,LineNumberTable
 
+# Enable protobuf-related optimizations.
+-shrinkunusedprotofields
+
+# Allowing Proguard to change modifiers.
+-allowaccessmodification
+
 # Keep all CREATOR fields within Parcelable that are kept.
 -keepclassmembers class * implements android.os.Parcelable {
   public static *** CREATOR;
@@ -148,24 +151,6 @@
   static boolean isLoggable(...);
 }
 
-# The following chart was created on July 20, 2016, to decide on 3 optimization
-# passes for Chrome.
-# optimization passes | time | .dex size | dirty memory per process
-# -----------------------------------------------------------------
-#          1          | 0:48 |  5805676  |         488972
-#          2          | 1:07 |  5777376  |         487092
-#          3          | 1:24 |  5772192  |         486596
-#          4          | 1:42 |  5771124  |         486484
-#          5          | 1:56 |  5770504  |         486432
--optimizationpasses 3
-
-# Horizontal class merging marginally increases dex size (as of Mar 2018).
--optimizations !class/merging/horizontal
-
-# Allowing Proguard to change modifiers. This change shrinks the .dex size by
-# ~1%, and reduces the method count by ~4%.
--allowaccessmodification
-
 # Workaround for crbug/1002847. Methods of BaseGmsClient are incorrectly
 # removed even though they are required for the derived class GmsClient
 # to correctly implement Api$Client.
@@ -177,11 +162,6 @@
   public boolean requiresSignIn();
 }
 
-# Protobuf java lite runtime uses reflection
--keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite {
-  <fields>;
-}
-
 ################################################################################
 # ../../base/android/proguard/chromium_code.flags
 ################################################################################
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
index 845891a..32c6f8e 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -124,7 +124,8 @@
     public TestRule mProcessor = new Features.InstrumentationProcessor();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     /**
      * Only launch Chrome without waiting for a current tab.
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
index c34e8096..4aa194fa 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceLayoutTest.java
@@ -180,7 +180,8 @@
     public TestRule mProcessor = new Features.InstrumentationProcessor();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @SuppressWarnings("FieldCanBeLocal")
     private EmbeddedTestServer mTestServer;
diff --git a/chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java b/chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
index cc6ec45..90fce29ff 100644
--- a/chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
+++ b/chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
@@ -62,12 +62,7 @@
      * @return Whether the Start Surface SinglePane is enabled.
      */
     public static boolean isStartSurfaceSinglePaneEnabled() {
-        // TODO(crbug.com/1062013): The values cached to START_SURFACE_SINGLE_PANE_ENABLED_KEY
-        // should be honored for some time. Remove only after M85 to be safe.
-        return isStartSurfaceEnabled()
-                && (START_SURFACE_VARIATION.getValue().equals("single")
-                        || SharedPreferencesManager.getInstance().readBoolean(
-                                ChromePreferenceKeys.START_SURFACE_SINGLE_PANE_ENABLED_KEY, false));
+        return isStartSurfaceEnabled() && START_SURFACE_VARIATION.getValue().equals("single");
     }
 
     /**
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/TrendyTermsCoordinatorTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/TrendyTermsCoordinatorTest.java
index 61f7359..2abe6df1 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/TrendyTermsCoordinatorTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/TrendyTermsCoordinatorTest.java
@@ -32,7 +32,8 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 public class TrendyTermsCoordinatorTest extends DummyUiActivityTestCase {
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private TrendyTermsCoordinator mCoordinator;
     private RecyclerView mRecyclerView;
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java
index 3c22974..6e7c6ef 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphTest.java
@@ -97,7 +97,8 @@
     public TestRule mProcessor = new Features.InstrumentationProcessor();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Before
     public void setUp() {
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiTest.java
index 60bc87a..8dfbcc2 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiTest.java
@@ -69,7 +69,8 @@
     public TestRule mProcessor = new Features.InstrumentationProcessor();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Before
     public void setUp() {
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
index e5c01e8..f2c43e6 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorTest.java
@@ -63,7 +63,8 @@
     public TestRule mProcessor = new Features.InstrumentationProcessor();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private TabSelectionEditorTestingRobot mRobot = new TabSelectionEditorTestingRobot();
 
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageCardRenderTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageCardRenderTest.java
index fc2cb18..fd927e6 100644
--- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageCardRenderTest.java
+++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedNewTabPageCardRenderTest.java
@@ -70,7 +70,8 @@
     public SuggestionsDependenciesRule mSuggestionsDeps = new SuggestionsDependenciesRule();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Rule
     public FeedDataInjectRule mFeedDataInjector = new FeedDataInjectRule(true);
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/network_fetch/FeedNewTabPageCardInstrumentationTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/network_fetch/FeedNewTabPageCardInstrumentationTest.java
index 0def4c0..1b4e8fb 100644
--- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/network_fetch/FeedNewTabPageCardInstrumentationTest.java
+++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/network_fetch/FeedNewTabPageCardInstrumentationTest.java
@@ -44,7 +44,8 @@
             new ChromeActivityTestRule<>(ChromeActivity.class);
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Before
     public void setUp() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 9e344ce..2851b05 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -465,6 +465,9 @@
 
     @Override
     protected void initializeStartupMetrics() {
+        // Initialize the activity session tracker as early as possible so that
+        // it can start background tasks.
+        ChromeActivitySessionTracker.getInstance();
         mActivityTabStartupMetricsTracker =
                 new ActivityTabStartupMetricsTracker(mTabModelSelectorSupplier);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
index 270572a7..0ec4b8fe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -12,8 +12,6 @@
 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
 import org.chromium.chrome.browser.flags.CachedFieldTrialParameter;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
-import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.tasks.ConditionalTabStripUtils;
 import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
@@ -103,15 +101,6 @@
         tryToCatchMissingParameters(fieldTrialsToCache);
         CachedFeatureFlags.cacheFieldTrialParameters(fieldTrialsToCache);
 
-        // TODO(crbug.com/1062013): Remove this after M85.
-        // This pref is only needed while clients are transitioning to caching via
-        // {@link StartSurfaceConfiguration#START_SURFACE_VARIATION}. It is still honored by
-        // {@link StartSurfaceConfiguration#isStartSurfaceSinglePaneEnabled()}. When it is removed,
-        // the cached value will be lost, but this only matters if the client hasn't started Chrome
-        // in months, and the effect is only that they will use a default value for the first run.
-        SharedPreferencesManager.getInstance().removeKey(
-                ChromePreferenceKeys.START_SURFACE_SINGLE_PANE_ENABLED_KEY);
-
         mIsFinishedCachingNativeFlags = true;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderMediator.java
index f42104967..66dfd50 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderMediator.java
@@ -25,7 +25,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserver;
 import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserver.PerformanceClass;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.ui.favicon.IconType;
@@ -55,8 +55,7 @@
         } else if (params.isVideo()) {
             setVideoIcon();
         }
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.CONTEXT_MENU_PERFORMANCE_INFO)
-                && params.isAnchor()) {
+        if (PerformanceHintsObserver.isContextMenuPerformanceInfoEnabled() && params.isAnchor()) {
             mModel.set(RevampedContextMenuHeaderProperties.URL_PERFORMANCE_CLASS, performanceClass);
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index cbe8798..e99af84 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -59,6 +59,7 @@
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemSchedule;
 import org.chromium.components.offline_items_collection.OfflineItemState;
 import org.chromium.components.offline_items_collection.PendingState;
 import org.chromium.components.offline_items_collection.UpdateDelta;
@@ -1381,6 +1382,20 @@
     }
 
     /**
+     * Change the download schedule to start the download in a different condition.
+     * @param id The id of the {@link OfflineItem} that requests the change.
+     * @param schedule The download schedule that defines when to start the download.
+     * @param isOffTheRecord Whether the download is for off the record profile.
+     */
+    public void changeSchedule(
+            final ContentId id, final OfflineItemSchedule schedule, boolean isOffTheRecord) {
+        boolean onlyOnWifi = (schedule == null) ? false : schedule.onlyOnWifi;
+        long startTimeMs = (schedule == null) ? -1 : schedule.startTimeMs;
+        DownloadManagerServiceJni.get().changeSchedule(getNativeDownloadManagerService(),
+                DownloadManagerService.this, id.id, onlyOnWifi, startTimeMs, isOffTheRecord);
+    }
+
+    /**
      * Add an Intent extra for StateAtCancel UMA to know the state of a request prior to a
      * user-initated cancel.
      * @param intent The Intent associated with the download action.
@@ -1816,6 +1831,8 @@
         void renameDownload(long nativeDownloadManagerService, DownloadManagerService caller,
                 String downloadGuid, String targetName, Callback</*RenameResult*/ Integer> callback,
                 boolean isOffTheRecord);
+        void changeSchedule(long nativeDownloadManagerService, DownloadManagerService caller,
+                String downloadGuid, boolean onlyOnWifi, long startTimeMs, boolean isOffTheRecord);
         void getAllDownloads(long nativeDownloadManagerService, DownloadManagerService caller,
                 boolean isOffTheRecord);
         void checkForExternallyRemovedDownloads(long nativeDownloadManagerService,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProviderImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProviderImpl.java
index 438e83f4..ec088ed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProviderImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProviderImpl.java
@@ -22,6 +22,7 @@
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineContentProvider.Observer;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemSchedule;
 import org.chromium.components.offline_items_collection.OfflineItemShareInfo;
 import org.chromium.components.offline_items_collection.ShareCallback;
 import org.chromium.components.offline_items_collection.VisualsCallback;
@@ -203,6 +204,12 @@
                 item.id, name, callback, item.isOffTheRecord);
     }
 
+    @Override
+    public void changeSchedule(final OfflineItem item, final OfflineItemSchedule schedule) {
+        DownloadManagerService.getDownloadManagerService().changeSchedule(
+                item.id, schedule, item.isOffTheRecord);
+    }
+
     /**
      * There could be some situations where we can't visually represent this download in the UI.
      * This should be handled in native/be more generic, but it's here in the glue for now.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java
index 393b148..12b6ea6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java
@@ -14,6 +14,7 @@
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemSchedule;
 import org.chromium.components.offline_items_collection.OpenParams;
 import org.chromium.components.offline_items_collection.ShareCallback;
 import org.chromium.components.offline_items_collection.UpdateDelta;
@@ -113,6 +114,15 @@
         }
     }
 
+    /** @see OfflineContentProvider#changeSchedule */
+    public void changeSchedule(final OfflineItem item, final OfflineItemSchedule schedule) {
+        if (mLegacyProvider != null && LegacyHelpers.isLegacyDownload(item.id)) {
+            mLegacyProvider.changeSchedule(item, schedule);
+        } else {
+            mProvider.changeSchedule(item.id, schedule);
+        }
+    }
+
     /** @see OfflineContentProvider#getItemById(ContentId, Callback) */
     public void getItemById(ContentId id, Callback<OfflineItem> callback) {
         if (mLegacyProvider != null && LegacyHelpers.isLegacyDownload(id)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
index 08a25f01..3424df0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
@@ -343,7 +343,8 @@
 
     private void onChangeItem(OfflineItem item) {
         UmaUtils.recordItemAction(ViewAction.MENU_CHANGE);
-        // TODO(xingliu): Implement this by wiring to download later dialog.
+        // TODO(xingliu): Hook to download later dialog to generate the schedule.
+        mProvider.changeSchedule(item, null);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/items/DownloadBlockedOfflineContentProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/download/items/DownloadBlockedOfflineContentProvider.java
index 079e11d..179a494 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/items/DownloadBlockedOfflineContentProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/items/DownloadBlockedOfflineContentProvider.java
@@ -10,6 +10,7 @@
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemSchedule;
 import org.chromium.components.offline_items_collection.OpenParams;
 import org.chromium.components.offline_items_collection.ShareCallback;
 import org.chromium.components.offline_items_collection.UpdateDelta;
@@ -64,6 +65,12 @@
     }
 
     @Override
+    public void changeSchedule(final ContentId id, final OfflineItemSchedule schedule) {
+        assert !LegacyHelpers.isLegacyDownload(id);
+        mProvider.changeSchedule(id, schedule);
+    }
+
+    @Override
     public void getItemById(ContentId id, Callback<OfflineItem> callback) {
         assert !LegacyHelpers.isLegacyDownload(id);
         mProvider.getItemById(id, callback);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
index 2a1feeb9..ddeb743 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ContentViewFocusTest.java
@@ -35,7 +35,6 @@
 import org.chromium.content_public.browser.ViewEventSink;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
-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.TestTouchUtils;
 import org.chromium.content_public.browser.test.util.TouchCommon;
@@ -130,15 +129,10 @@
             edgeSwipeHandler.swipeUpdated(100, 0, 100, 0, 100, 0);
         });
 
-        CriteriaHelper.pollUiThread(
-                new Criteria("Layout still requesting Tab Android view be attached") {
-                    @Override
-                    public boolean isSatisfied() {
-                        LayoutManager driver =
-                                mChromeTabbedActivityTestRule.getActivity().getLayoutManager();
-                        return !driver.getActiveLayout().shouldDisplayContentOverlay();
-                    }
-                });
+        CriteriaHelper.pollUiThread(() -> {
+            LayoutManager driver = mChromeTabbedActivityTestRule.getActivity().getLayoutManager();
+            return !driver.getActiveLayout().shouldDisplayContentOverlay();
+        }, "Layout still requesting Tab Android view be attached");
 
         // Make sure the view loses focus. It is immediately given focus back
         // because it's the only focusable view.
@@ -147,15 +141,10 @@
         // End the drag
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> edgeSwipeHandler.swipeFinished());
 
-        CriteriaHelper.pollUiThread(
-                new Criteria("Layout not requesting Tab Android view be attached") {
-                    @Override
-                    public boolean isSatisfied() {
-                        LayoutManager driver =
-                                mChromeTabbedActivityTestRule.getActivity().getLayoutManager();
-                        return driver.getActiveLayout().shouldDisplayContentOverlay();
-                    }
-                });
+        CriteriaHelper.pollUiThread(() -> {
+            LayoutManager driver = mChromeTabbedActivityTestRule.getActivity().getLayoutManager();
+            return driver.getActiveLayout().shouldDisplayContentOverlay();
+        }, "Layout not requesting Tab Android view be attached");
 
         Assert.assertTrue("Content view didn't regain focus", blockForFocusChanged());
         Assert.assertFalse("Unexpected focus change", haveFocusChanges());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
index b349aefe..c3b4692 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
@@ -9,6 +9,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.view.KeyEvent;
 
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -68,20 +69,16 @@
         // the initial value problematic. We solve this by explicitly specifying the initial zoom
         // level via the viewport tag and waiting for the zoom level to reach that value before we
         // proceed with the rest of the test.
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mCoordinates.getPageScaleFactor() - INITIAL_SCALE < FLOAT_DELTA;
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            Criteria.checkThat((double) mCoordinates.getPageScaleFactor(),
+                    Matchers.is(Matchers.closeTo(INITIAL_SCALE, FLOAT_DELTA)));
         }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
     }
 
     private void waitForZoomIn(final float initialZoomLevel) {
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mCoordinates.getPageScaleFactor() > initialZoomLevel;
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            Criteria.checkThat(
+                    mCoordinates.getPageScaleFactor(), Matchers.greaterThan(initialZoomLevel));
         }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
     }
 
@@ -122,11 +119,9 @@
                 InstrumentationRegistry.getInstrumentation(), tab.getView(), KeyEvent.KEYCODE_BACK);
 
         // We should zoom out to the previous zoom level.
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return (mCoordinates.getPageScaleFactor() - initialZoomLevel) < FLOAT_DELTA;
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            Criteria.checkThat((double) mCoordinates.getPageScaleFactor(),
+                    Matchers.is(Matchers.closeTo(initialZoomLevel, FLOAT_DELTA)));
         }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
index 6cf71b9..343de79 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -6,12 +6,12 @@
 
 import android.content.pm.ActivityInfo;
 import android.support.test.InstrumentationRegistry;
-import android.text.TextUtils;
 import android.util.Base64;
 import android.view.KeyEvent;
 
 import androidx.test.filters.MediumTest;
 
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -93,26 +93,15 @@
         new TabLoadObserver(mActivityTestRule.getActivity().getActivityTab())
                 .fullyLoadUrl(startUrl);
 
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final UrlBar urlBar =
-                        (UrlBar) mActivityTestRule.getActivity().findViewById(R.id.url_bar);
-                Assert.assertNotNull("urlBar is null", urlBar);
-
-                if (!TextUtils.equals(expectedLocation(endUrl), urlBar.getText().toString())) {
-                    updateFailureReason(String.format("Expected url bar text: %s, actual: %s",
-                            expectedLocation(endUrl), urlBar.getText().toString()));
-                    return false;
-                }
-                if (!TextUtils.equals(endUrl,
-                            mActivityTestRule.getActivity().getActivityTab().getUrlString())) {
-                    updateFailureReason(String.format("Expected tab url: %s, actual: %s", endUrl,
-                            mActivityTestRule.getActivity().getActivityTab().getUrlString()));
-                    return false;
-                }
-                return true;
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            final UrlBar urlBar =
+                    (UrlBar) mActivityTestRule.getActivity().findViewById(R.id.url_bar);
+            Criteria.checkThat("urlBar is null", urlBar, Matchers.notNullValue());
+            Criteria.checkThat("UrlBar text wrong", urlBar.getText().toString(),
+                    Matchers.is(expectedLocation(endUrl)));
+            Criteria.checkThat("Tab url wrong",
+                    mActivityTestRule.getActivity().getActivityTab().getUrlString(),
+                    Matchers.is(endUrl));
         });
     }
 
@@ -357,8 +346,10 @@
                 mTestServer.getURL("/chrome/test/data/android/redirect/one.html");
         typeInOmniboxAndNavigate(initialUrl, null);
 
-        CriteriaHelper.pollInstrumentationThread(Criteria.equals(redirectedUrl,
-                () -> mActivityTestRule.getActivity().getActivityTab().getUrlString()));
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            Criteria.checkThat(mActivityTestRule.getActivity().getActivityTab().getUrlString(),
+                    Matchers.is(redirectedUrl));
+        });
     }
 
     /**
@@ -390,8 +381,10 @@
         typeInOmniboxAndNavigate(initialUrl, null);
 
         // Now intent fallback should be triggered assuming 'non_existent' scheme cannot be handled.
-        CriteriaHelper.pollInstrumentationThread(Criteria.equals(
-                targetUrl, () -> mActivityTestRule.getActivity().getActivityTab().getUrlString()));
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            Criteria.checkThat(mActivityTestRule.getActivity().getActivityTab().getUrlString(),
+                    Matchers.is(targetUrl));
+        });
 
         // Check if Java redirections were removed from the history.
         // Note that if we try to go back in the test: NavigateToEntry() is called, but
@@ -535,8 +528,9 @@
             // Wait for the url to change.
             final Tab tab = TabModelUtils.getCurrentTab(model);
             mActivityTestRule.assertWaitForPageScaleFactorMatch(0.75f);
-            CriteriaHelper.pollInstrumentationThread(
-                    Criteria.equals(mockedUrl, () -> getTabUrlOnUIThread(tab)), 5000, 50);
+            CriteriaHelper.pollInstrumentationThread(() -> {
+                Criteria.checkThat(getTabUrlOnUIThread(tab), Matchers.is(mockedUrl));
+            }, 5000, 50);
 
             // Make sure that we're showing new content now.
             Assert.assertEquals("Still showing spoofed data", "\"Real\"", getTabBodyText(tab));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java
index 1cfda4c..0fb22d7c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigationPopupTest.java
@@ -31,7 +31,6 @@
 import org.chromium.content_public.browser.NavigationEntry;
 import org.chromium.content_public.browser.NavigationHistory;
 import org.chromium.content_public.browser.test.mock.MockNavigationController;
-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;
 
@@ -97,16 +96,11 @@
         final TestNavigationController controller = new TestNavigationController();
         final ListPopupWindow popup = showPopup(controller);
 
-        CriteriaHelper.pollUiThread(new Criteria("All favicons did not get updated.") {
-            @Override
-            public boolean isSatisfied() {
-                NavigationHistory history = controller.mHistory;
-                for (int i = 0; i < history.getEntryCount(); i++) {
-                    if (history.getEntryAtIndex(i).getFavicon() == null) {
-                        return false;
-                    }
-                }
-                return true;
+        CriteriaHelper.pollUiThread(() -> {
+            NavigationHistory history = controller.mHistory;
+            for (int i = 0; i < history.getEntryCount(); i++) {
+                Assert.assertNotNull(
+                        "Favicon[" + i + "] not updated", history.getEntryAtIndex(i).getFavicon());
             }
         });
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
index 7523032b..55d78b5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
@@ -5,10 +5,10 @@
 package org.chromium.chrome.browser;
 
 import android.support.test.InstrumentationRegistry;
-import android.text.TextUtils;
 
 import androidx.test.filters.MediumTest;
 
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -37,7 +37,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
 
 /**
  * Tests whether popup windows appear.
@@ -87,7 +86,8 @@
     @Feature({"Popup"})
     public void testPopupInfobarAppears() {
         mActivityTestRule.loadUrl(mPopupHtmlUrl);
-        CriteriaHelper.pollUiThread(Criteria.equals(1, () -> getNumInfobarsShowing()));
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(getNumInfobarsShowing(), Matchers.is(1)));
     }
 
     @Test
@@ -99,10 +99,12 @@
         String url = mTestServer.getURL("/chrome/test/data/android/popup_on_click.html");
 
         mActivityTestRule.loadUrl(url);
-        CriteriaHelper.pollUiThread(Criteria.equals(0, () -> getNumInfobarsShowing()));
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(getNumInfobarsShowing(), Matchers.is(0)));
         DOMUtils.clickNode(
                 mActivityTestRule.getActivity().getActivityTab().getWebContents(), "link");
-        CriteriaHelper.pollUiThread(Criteria.equals(0, () -> getNumInfobarsShowing()));
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(getNumInfobarsShowing(), Matchers.is(0)));
     }
 
     @Test
@@ -115,43 +117,30 @@
         MockSafeBrowsingApiHandler.addMockResponse(url, METADATA_FOR_ABUSIVE_ENFORCEMENT);
 
         mActivityTestRule.loadUrl(url);
-        CriteriaHelper.pollUiThread(Criteria.equals(0, () -> getNumInfobarsShowing()));
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(getNumInfobarsShowing(), Matchers.is(0)));
         DOMUtils.clickNode(
                 mActivityTestRule.getActivity().getActivityTab().getWebContents(), "link");
-        CriteriaHelper.pollUiThread(Criteria.equals(1, () -> getNumInfobarsShowing()));
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(getNumInfobarsShowing(), Matchers.is(1)));
         Assert.assertEquals(1, selector.getTotalTabCount());
     }
 
     private void waitForForegroundInfoBar(@InfoBarIdentifier int id) {
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                if (getNumInfobarsShowing() == 0) {
-                    updateFailureReason("No infobars present");
-                    return false;
-                }
-                InfoBar frontInfoBar = mActivityTestRule.getInfoBars().get(0);
-                if (frontInfoBar.getInfoBarIdentifier() != id) {
-                    updateFailureReason(String.format(Locale.ENGLISH,
-                            "Invalid infobar type shown: %d", frontInfoBar.getInfoBarIdentifier()));
-                    frontInfoBar.onCloseButtonClicked();
-                    return false;
-                }
-                return true;
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(getNumInfobarsShowing(), Matchers.greaterThan(0));
+            InfoBar frontInfoBar = mActivityTestRule.getInfoBars().get(0);
+            if (frontInfoBar.getInfoBarIdentifier() != id) frontInfoBar.onCloseButtonClicked();
+            Criteria.checkThat("Invalid infobar type shown", frontInfoBar.getInfoBarIdentifier(),
+                    Matchers.is(id));
         });
     }
 
     private void waitForNoInfoBarOfType(@InfoBarIdentifier int id) {
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                List<InfoBar> infoBars = mActivityTestRule.getInfoBars();
-                if (infoBars.isEmpty()) return true;
-                for (InfoBar infoBar : infoBars) {
-                    if (infoBar.getInfoBarIdentifier() == id) return false;
-                }
-                return true;
+        CriteriaHelper.pollUiThread(() -> {
+            List<InfoBar> infoBars = mActivityTestRule.getInfoBars();
+            for (InfoBar infoBar : infoBars) {
+                Criteria.checkThat(infoBar.getInfoBarIdentifier(), Matchers.not(id));
             }
         });
     }
@@ -172,14 +161,14 @@
         final InfoBar infobar = infobars.get(0);
         Assert.assertEquals(InfoBarIdentifier.POPUP_BLOCKED_INFOBAR_DELEGATE_MOBILE,
                 infobar.getInfoBarIdentifier());
-        CriteriaHelper.pollUiThread(Criteria.equals(false, () -> container.isAnimating()));
+        CriteriaHelper.pollUiThread(() -> !container.isAnimating());
         TouchCommon.singleClickView(infobar.getView().findViewById(R.id.button_primary));
 
         // Document mode popups appear slowly and sequentially to prevent Android from throwing them
         // away, so use a long timeout.  http://crbug.com/498920.
-        CriteriaHelper.pollUiThread(
-                Criteria.equals("Two", () -> selector.getCurrentTab().getTitle()), 7500,
-                CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(selector.getCurrentTab().getTitle(), Matchers.is("Two"));
+        }, 7500, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
         waitForNoInfoBarOfType(InfoBarIdentifier.POPUP_BLOCKED_INFOBAR_DELEGATE_MOBILE);
 
         Assert.assertEquals(3, selector.getTotalTabCount());
@@ -187,21 +176,11 @@
 
         // Test that revisiting the original page makes popup windows immediately.
         mActivityTestRule.loadUrl(mPopupHtmlUrl);
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                int tabCount = selector.getTotalTabCount();
-                if (tabCount != 5) {
-                    updateFailureReason(String.format(
-                            Locale.ENGLISH, "Expected 5 tabs, but found: %d", tabCount));
-                    return false;
-                }
-
-                String tabTitle = selector.getCurrentTab().getTitle();
-                updateFailureReason(String.format(
-                        Locale.ENGLISH, "Exepcted title 'Two', but found: %s", tabTitle));
-                return TextUtils.equals("Two", tabTitle);
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            int tabCount = selector.getTotalTabCount();
+            Criteria.checkThat(tabCount, Matchers.is(5));
+            String tabTitle = selector.getCurrentTab().getTitle();
+            Criteria.checkThat(tabTitle, Matchers.is("Two"));
         }, 7500, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
         waitForNoInfoBarOfType(InfoBarIdentifier.POPUP_BLOCKED_INFOBAR_DELEGATE_MOBILE);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SafeBrowsingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SafeBrowsingTest.java
index d1bf75c..1fb617cf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/SafeBrowsingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SafeBrowsingTest.java
@@ -8,6 +8,7 @@
 
 import androidx.test.filters.MediumTest;
 
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -28,8 +29,6 @@
 import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.ui.base.PageTransition;
 
-import java.util.concurrent.Callable;
-
 /**
  * Test integration with the SafeBrowsingApiHandler.
  */
@@ -48,16 +47,19 @@
      * that would indicate this, unfortunately.
      */
     private void waitForInterstitial(final boolean shouldBeShown) {
-        CriteriaHelper.pollUiThread(Criteria.equals(shouldBeShown, new Callable<Boolean>() {
-            @Override
-            public Boolean call() {
-                // TODO(carlosil): For now, we check the presence of an interstitial through the
-                // title since isShowingInterstitialPage does not work with committed interstitials.
-                // Once we fully migrate to committed interstitials, this should be changed to a
-                // more robust check.
-                return getWebContents().getTitle().equals("Security error");
+        CriteriaHelper.pollUiThread(() -> {
+            // TODO(carlosil): For now, we check the presence of an interstitial through the
+            // title since isShowingInterstitialPage does not work with committed interstitials.
+            // Once we fully migrate to committed interstitials, this should be changed to a
+            // more robust check.
+            String title = getWebContents().getTitle();
+            String errorTitle = "Security error";
+            if (shouldBeShown) {
+                Criteria.checkThat(title, Matchers.is(errorTitle));
+            } else {
+                Criteria.checkThat(title, Matchers.not(errorTitle));
             }
-        }));
+        });
     }
 
     private WebContents getWebContents() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
index 0e7b07e..728e9fa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
@@ -12,6 +12,7 @@
 
 import androidx.test.filters.MediumTest;
 
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -79,15 +80,11 @@
         }
     }
 
-    private class IntentSentCriteria extends Criteria {
-        public IntentSentCriteria() {
-            super("SelectFileDialog never sent an intent.");
-        }
-
-        @Override
-        public boolean isSatisfied() {
-            return mActivityWindowAndroidForTest.lastIntent != null;
-        }
+    private void verifyIntentSent() {
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            Criteria.checkThat("SelectFileDialog never sent an intent.",
+                    mActivityWindowAndroidForTest.lastIntent, Matchers.notNullValue());
+        });
     }
 
     private WebContents mWebContents;
@@ -120,7 +117,7 @@
     public void testSelectFileAndCancelRequest() throws Throwable {
         {
             DOMUtils.clickNode(mWebContents, "input_file");
-            CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
+            verifyIntentSent();
             Assert.assertEquals(
                     Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
             Intent contentIntent =
@@ -133,7 +130,7 @@
 
         {
             DOMUtils.clickNode(mWebContents, "input_text");
-            CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
+            verifyIntentSent();
             Assert.assertEquals(
                     Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
             Intent contentIntent =
@@ -146,7 +143,7 @@
 
         {
             DOMUtils.clickNode(mWebContents, "input_any");
-            CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
+            verifyIntentSent();
             Assert.assertEquals(
                     Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
             Intent contentIntent =
@@ -159,7 +156,7 @@
 
         {
             DOMUtils.clickNode(mWebContents, "input_file_multiple");
-            CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
+            verifyIntentSent();
             Assert.assertEquals(
                     Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
             Intent contentIntent =
@@ -174,13 +171,13 @@
         }
 
         DOMUtils.clickNode(mWebContents, "input_image");
-        CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
+        verifyIntentSent();
         Assert.assertEquals(MediaStore.ACTION_IMAGE_CAPTURE,
                 mActivityWindowAndroidForTest.lastIntent.getAction());
         resetActivityWindowAndroidForTest();
 
         DOMUtils.clickNode(mWebContents, "input_audio");
-        CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
+        verifyIntentSent();
         Assert.assertEquals(MediaStore.Audio.Media.RECORD_SOUND_ACTION,
                 mActivityWindowAndroidForTest.lastIntent.getAction());
         resetActivityWindowAndroidForTest();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ServicificationBackgroundService.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ServicificationBackgroundService.java
index 7e5a1f0..b94e6c0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ServicificationBackgroundService.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ServicificationBackgroundService.java
@@ -14,7 +14,6 @@
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.init.EmptyBrowserParts;
 import org.chromium.content_public.browser.BrowserStartupController;
-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;
 
@@ -66,12 +65,7 @@
 
     public void waitForNativeLoaded() {
         CriteriaHelper.pollUiThread(
-                new Criteria("Failed while waiting for starting Service Manager.") {
-                    @Override
-                    public boolean isSatisfied() {
-                        return mNativeLoaded;
-                    }
-                });
+                () -> mNativeLoaded, "Failed while waiting for starting Service Manager.");
     }
 
     public void setSupportsServiceManagerOnly(boolean supportsServiceManagerOnly) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java
index a05b35d..3e8a09a5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java
@@ -29,7 +29,6 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ApplicationTestUtils;
 import org.chromium.chrome.test.util.ChromeTabUtils;
-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;
 
@@ -115,24 +114,14 @@
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> ChromeTabUtils.simulateRendererKilledForTesting(mTab, false));
 
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mTab.isHidden();
-            }
-        });
+        CriteriaHelper.pollUiThread(mTab::isHidden);
         Assert.assertTrue(mTab.needsReload());
         Assert.assertFalse(isShowingSadTab());
 
         ApplicationTestUtils.launchChrome(InstrumentationRegistry.getTargetContext());
 
         // The tab should be restored and visible.
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return !mTab.isHidden();
-            }
-        });
+        CriteriaHelper.pollUiThread(() -> !mTab.isHidden());
         Assert.assertFalse(mTab.needsReload());
         Assert.assertFalse(isShowingSadTab());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
index 39941bc..82701ea 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -10,13 +10,13 @@
 import android.os.Bundle;
 import android.provider.Browser;
 import android.support.test.InstrumentationRegistry;
-import android.text.TextUtils;
 import android.view.ContextMenu;
 import android.view.View;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.MediumTest;
 
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -40,6 +40,7 @@
 import org.chromium.chrome.test.util.ChromeTabUtils;
 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.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -69,20 +70,19 @@
     private static final String HTTPS_REFERRER = "https://chromium.org/";
     private static final String HTTPS_REFERRER_WITH_PATH = "https://chromium.org/path1/path2";
 
-    static class ElementFocusedCriteria extends Criteria {
+    static class ElementFocusedCriteria implements Runnable {
         private final Tab mTab;
         private final String mElementId;
 
         public ElementFocusedCriteria(Tab tab, String elementId) {
-            super("Text-field in page not focused.");
             mTab = tab;
             // Add quotes to match returned value from JS.
             mElementId = "\"" + elementId + "\"";
         }
 
         @Override
-        public boolean isSatisfied() {
-            String nodeId;
+        public void run() {
+            String nodeId = null;
             try {
                 StringBuilder sb = new StringBuilder();
                 sb.append("(function() {");
@@ -99,34 +99,31 @@
                 }
                 nodeId = jsonText;
             } catch (TimeoutException e) {
-                e.printStackTrace();
-                Assert.fail("Failed to retrieve focused node: TimeoutException was thrown");
-                return false;
+                throw new CriteriaNotSatisfiedException(e);
             }
-            return TextUtils.equals(mElementId, nodeId);
+            Criteria.checkThat("Text-field in page not focused.", nodeId, Matchers.is(mElementId));
         }
     }
 
-    static class ElementTextIsCriteria extends Criteria {
+    static class ElementTextIsCriteria implements Runnable {
         private final Tab mTab;
         private final String mElementId;
         private final String mExpectedText;
 
         public ElementTextIsCriteria(Tab tab, String elementId, String expectedText) {
-            super("Page does not have the text typed in.");
             mTab = tab;
             mElementId = elementId;
             mExpectedText = expectedText;
         }
 
         @Override
-        public boolean isSatisfied() {
+        public void run() {
             try {
                 String text = DOMUtils.getNodeValue(mTab.getWebContents(), mElementId);
-                return TextUtils.equals(mExpectedText, text);
+                Criteria.checkThat(
+                        "Page does not have the text typed in.", text, Matchers.is(mExpectedText));
             } catch (TimeoutException e) {
-                e.printStackTrace();
-                return false;
+                throw new CriteriaNotSatisfiedException(e);
             }
         }
     }
@@ -134,33 +131,31 @@
     /**
      * Criteria checking that the page referrer has the expected value.
      */
-    public static class ReferrerCriteria extends Criteria {
+    public static class ReferrerCriteria implements Runnable {
         private final Tab mTab;
         private final String mExpectedReferrer;
         private static final String GET_REFERRER_JS =
                 "(function() { return document.referrer; })();";
 
         public ReferrerCriteria(Tab tab, String expectedReferrer) {
-            super("Referrer is not as expected.");
             mTab = tab;
             // Add quotes to match returned value from JS.
             mExpectedReferrer = "\"" + expectedReferrer + "\"";
         }
 
         @Override
-        public boolean isSatisfied() {
-            String referrer;
+        public void run() {
+            String referrer = null;
             try {
                 String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult(
                         mTab.getWebContents(), GET_REFERRER_JS);
                 if (jsonText.equalsIgnoreCase("null")) jsonText = "";
                 referrer = jsonText;
             } catch (TimeoutException e) {
-                e.printStackTrace();
-                Assert.fail("TimeoutException was thrown");
-                return false;
+                throw new CriteriaNotSatisfiedException(e);
             }
-            return TextUtils.equals(mExpectedReferrer, referrer);
+            Criteria.checkThat(
+                    "Referrer is not as expected.", referrer, Matchers.is(mExpectedReferrer));
         }
     }
 
@@ -204,11 +199,9 @@
         // NoTouchMode changes external app launch behaviour depending on whether Chrome is
         // foregrounded - which it is for these tests.
         if (createNewTab) {
-            CriteriaHelper.pollUiThread(new Criteria("Failed to select different tab") {
-                @Override
-                public boolean isSatisfied() {
-                    return testRule.getActivity().getActivityTab() != originalTab;
-                }
+            CriteriaHelper.pollUiThread(() -> {
+                Criteria.checkThat("Failed to select different tab",
+                        testRule.getActivity().getActivityTab(), Matchers.not(originalTab));
             });
         }
         ChromeTabUtils.waitForTabPageLoaded(testRule.getActivity().getActivityTab(), expectedUrl);
@@ -424,8 +417,7 @@
                 mActivityTestRule.getActivity().hasWindowFocus());
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> mActivityTestRule.getActivity().onBackPressed());
-        CriteriaHelper.pollUiThread(
-                Criteria.equals(false, () -> mActivityTestRule.getActivity().hasWindowFocus()));
+        CriteriaHelper.pollUiThread(() -> !mActivityTestRule.getActivity().hasWindowFocus());
     }
 
     /**
@@ -469,8 +461,7 @@
                 mActivityTestRule.getActivity().hasWindowFocus());
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> mActivityTestRule.getActivity().onBackPressed());
-        CriteriaHelper.pollUiThread(
-                Criteria.equals(false, () -> mActivityTestRule.getActivity().hasWindowFocus()));
+        CriteriaHelper.pollUiThread(() -> !mActivityTestRule.getActivity().hasWindowFocus());
     }
 
     /**
@@ -509,8 +500,7 @@
                 mActivityTestRule.getActivity().hasWindowFocus());
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> mActivityTestRule.getActivity().onBackPressed());
-        CriteriaHelper.pollUiThread(
-                Criteria.equals(false, () -> mActivityTestRule.getActivity().hasWindowFocus()));
+        CriteriaHelper.pollUiThread(() -> !mActivityTestRule.getActivity().hasWindowFocus());
     }
 
     /**
@@ -542,8 +532,7 @@
                 mActivityTestRule.getActivity().hasWindowFocus());
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> mActivityTestRule.getActivity().onBackPressed());
-        CriteriaHelper.pollUiThread(
-                Criteria.equals(false, () -> mActivityTestRule.getActivity().hasWindowFocus()));
+        CriteriaHelper.pollUiThread(() -> !mActivityTestRule.getActivity().hasWindowFocus());
     }
 
     /**
@@ -682,8 +671,11 @@
                 (Runnable) ()
                         -> TabModelUtils.closeTabByIndex(
                                 mActivityTestRule.getActivity().getCurrentTabModel(), 0));
-        CriteriaHelper.pollUiThread(Criteria.equals(0,
-                () -> mActivityTestRule.getActivity().getTabModelSelector().getTotalTabCount()));
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(
+                    mActivityTestRule.getActivity().getTabModelSelector().getTotalTabCount(),
+                    Matchers.is(0));
+        });
 
         // Defines one gigantic link spanning the whole page that creates a new
         // window with chrome/test/data/android/google.html.
@@ -710,8 +702,11 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         InstrumentationRegistry.getTargetContext().startActivity(intent);
 
-        CriteriaHelper.pollUiThread(Criteria.equals(1,
-                () -> mActivityTestRule.getActivity().getTabModelSelector().getTotalTabCount()));
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(
+                    mActivityTestRule.getActivity().getTabModelSelector().getTotalTabCount(),
+                    Matchers.is(1));
+        });
         ApplicationTestUtils.assertWaitForPageScaleFactorMatch(
                 mActivityTestRule.getActivity(), 0.5f);
 
@@ -723,12 +718,8 @@
                 (Callable<View>) ()
                         -> mActivityTestRule.getActivity().getActivityTab().getContentView());
         TouchCommon.longPressView(view);
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return observer.mContextMenu != null;
-            }
-        });
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(observer.mContextMenu, Matchers.notNullValue()));
         mActivityTestRule.getActivity().getActivityTab().removeObserver(observer);
 
         // Select the "open in new tab" option.
@@ -737,14 +728,20 @@
                                 R.id.contextmenu_open_in_new_tab, 0)));
 
         // The second tab should open in the background.
-        CriteriaHelper.pollUiThread(Criteria.equals(2,
-                () -> mActivityTestRule.getActivity().getTabModelSelector().getTotalTabCount()));
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(
+                    mActivityTestRule.getActivity().getTabModelSelector().getTotalTabCount(),
+                    Matchers.is(2));
+        });
 
         // Hitting "back" should close the tab, minimize Chrome, and select the background tab.
         // Confirm that the number of tabs is correct and that closing the tab didn't cause a crash.
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> mActivityTestRule.getActivity().onBackPressed());
-        CriteriaHelper.pollUiThread(Criteria.equals(1,
-                () -> mActivityTestRule.getActivity().getTabModelSelector().getTotalTabCount()));
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(
+                    mActivityTestRule.getActivity().getTabModelSelector().getTotalTabCount(),
+                    Matchers.is(1));
+        });
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 9d0a945..afd4170 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -23,6 +23,7 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -204,11 +205,13 @@
                                         + "})()",
                                 null));
 
-        CriteriaHelper.pollUiThread(Criteria.equals(2,
-                () -> mActivityTestRule.getActivity()
+        CriteriaHelper.pollUiThread(() -> {
+            int tabCount = mActivityTestRule.getActivity()
                                    .getTabModelSelector()
                                    .getModel(false)
-                                   .getCount()));
+                                   .getCount();
+            Criteria.checkThat(tabCount, Matchers.is(2));
+        });
     }
 
     @Test
@@ -226,25 +229,17 @@
 
         final AtomicReference<JavascriptTabModalDialog> dialog = new AtomicReference<>();
 
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                dialog.set(getCurrentAlertDialog());
-
-                return dialog.get() != null;
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            dialog.set(getCurrentAlertDialog());
+            Criteria.checkThat(dialog.get(), Matchers.notNullValue());
         });
 
         onView(withId(R.id.positive_button)).perform(click());
 
         dialog.set(null);
 
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return getCurrentAlertDialog() == null;
-            }
-        });
+        CriteriaHelper.pollInstrumentationThread(
+                () -> Criteria.checkThat(getCurrentAlertDialog(), Matchers.nullValue()));
 
         Assert.assertTrue("Incognito model was not selected",
                 mActivityTestRule.getActivity().getTabModelSelector().isIncognitoSelected());
@@ -285,14 +280,11 @@
                 () -> Assert.assertEquals("The tab count is wrong", tabCount + 1,
                                 mActivityTestRule.getActivity().getCurrentTabModel().getCount()));
 
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Tab tab = mActivityTestRule.getActivity().getCurrentTabModel().getTabAt(1);
-                String title = tab.getTitle().toLowerCase(Locale.US);
-                String expectedTitle = "new tab";
-                return title.startsWith(expectedTitle);
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Tab tab = mActivityTestRule.getActivity().getCurrentTabModel().getTabAt(1);
+            String title = tab.getTitle().toLowerCase(Locale.US);
+            String expectedTitle = "new tab";
+            Criteria.checkThat(title, Matchers.startsWith(expectedTitle));
         });
 
         ChromeTabUtils.closeCurrentTab(
@@ -303,15 +295,10 @@
     }
 
     private void assertWaitForKeyboardStatus(final boolean show) {
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                updateFailureReason("expected keyboard show: " + show);
-                return show
-                        == mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(
-                                   mActivityTestRule.getActivity(),
-                                   mActivityTestRule.getActivity().getTabsView());
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            boolean isKeyboardShowing = mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(
+                    mActivityTestRule.getActivity(), mActivityTestRule.getActivity().getTabsView());
+            Criteria.checkThat(isKeyboardShowing, Matchers.is(show));
         });
     }
 
@@ -379,17 +366,12 @@
     }
 
     private void assertWaitForSelectedText(final String text) {
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                WebContents webContents = mActivityTestRule.getWebContents();
-                SelectionPopupController controller =
-                        SelectionPopupController.fromWebContents(webContents);
-                final String actualText = controller.getSelectedText();
-                updateFailureReason(
-                        "expected selected text: [" + text + "], but got: [" + actualText + "]");
-                return text.equals(actualText);
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            WebContents webContents = mActivityTestRule.getWebContents();
+            SelectionPopupController controller =
+                    SelectionPopupController.fromWebContents(webContents);
+            final String actualText = controller.getSelectedText();
+            Criteria.checkThat(actualText, Matchers.is(text));
         });
     }
 
@@ -1104,14 +1086,12 @@
                     }
                 });
 
-        CriteriaHelper.pollUiThread(new Criteria("Did not finish animation") {
-            @Override
-            public boolean isSatisfied() {
-                Layout layout =
-                        mActivityTestRule.getActivity().getLayoutManager().getActiveLayout();
-                return !layout.isLayoutAnimating();
-            }
-        });
+        CriteriaHelper.pollUiThread(() -> {
+            return !mActivityTestRule.getActivity()
+                            .getLayoutManager()
+                            .getActiveLayout()
+                            .isLayoutAnimating();
+        }, "Did not finish animation");
     }
 
     private void swipeToCloseNTabs(
@@ -1409,12 +1389,8 @@
         Assert.assertEquals("Tab count is expected to increment by 1 after clicking new tab button",
                 initialTabCount + 1, newTabCount);
         UiUtils.settleDownUI(InstrumentationRegistry.getInstrumentation());
-        CriteriaHelper.pollInstrumentationThread(new Criteria("Should not be in overview mode") {
-            @Override
-            public boolean isSatisfied() {
-                return !mActivityTestRule.getActivity().isInOverviewMode();
-            }
-        });
+        CriteriaHelper.pollInstrumentationThread(
+                () -> !mActivityTestRule.getActivity().isInOverviewMode());
     }
 
     @Test
@@ -1628,14 +1604,12 @@
                     swipeXChange, 0.f, swipeXChange, 0.f, swipeXChange, 0.f);
         });
 
-        CriteriaHelper.pollUiThread(
-                new Criteria("Layout still requesting Tab Android view be attached") {
-                    @Override
-                    public boolean isSatisfied() {
-                        LayoutManager driver = mActivityTestRule.getActivity().getLayoutManager();
-                        return !driver.getActiveLayout().shouldDisplayContentOverlay();
-                    }
-                });
+        CriteriaHelper.pollUiThread(() -> {
+            return !mActivityTestRule.getActivity()
+                            .getLayoutManager()
+                            .getActiveLayout()
+                            .shouldDisplayContentOverlay();
+        });
 
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
             Assert.assertFalse("Keyboard should be hidden while swiping",
@@ -1644,14 +1618,10 @@
             edgeSwipeHandler.swipeFinished();
         });
 
-        CriteriaHelper.pollUiThread(
-                new Criteria("Layout not requesting Tab Android view be attached") {
-                    @Override
-                    public boolean isSatisfied() {
-                        LayoutManager driver = mActivityTestRule.getActivity().getLayoutManager();
-                        return driver.getActiveLayout().shouldDisplayContentOverlay();
-                    }
-                });
+        CriteriaHelper.pollUiThread(() -> {
+            LayoutManager driver = mActivityTestRule.getActivity().getLayoutManager();
+            return driver.getActiveLayout().shouldDisplayContentOverlay();
+        }, "Layout not requesting Tab Android view be attached");
 
         Assert.assertFalse("Keyboard should not be shown",
                 mActivityTestRule.getKeyboardDelegate().isKeyboardShowing(
@@ -1857,7 +1827,7 @@
 
     private void assertFileExists(final File fileToCheck, final boolean expected) {
         CriteriaHelper.pollInstrumentationThread(
-                Criteria.equals(expected, () -> fileToCheck.exists()));
+                () -> Criteria.checkThat(fileToCheck.exists(), Matchers.is(expected)));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java
index 98a2f6b..33647e4f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/UrlSchemeTest.java
@@ -11,6 +11,7 @@
 
 import androidx.test.filters.MediumTest;
 
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -121,23 +122,18 @@
         mActivityTestRule.loadUrl(createContentUrl(resource));
 
         // Make sure iframe is really loaded by verifying the title
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mActivityTestRule.getActivity().getActivityTab().getTitle().equals(
-                        "iframe loaded");
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(mActivityTestRule.getActivity().getActivityTab().getTitle(),
+                    Matchers.is("iframe loaded"));
         });
         // Make sure that content provider was asked to provide the content.
         ensureResourceRequestCountInContentProviderNotLessThan(iframe, 1);
         mActivityTestRule.runJavaScriptCodeInCurrentTab(script);
 
         // Make sure content access failed by verifying that title is set to fail.
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mActivityTestRule.getActivity().getActivityTab().getTitle().equals("fail");
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(mActivityTestRule.getActivity().getActivityTab().getTitle(),
+                    Matchers.is("fail"));
         });
     }
 
@@ -150,12 +146,9 @@
                 + "&url=" + URLEncoder.encode(imageUrl));
 
         // Make sure the CORS request fail in the page.
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return !mActivityTestRule.getActivity().getActivityTab().getTitle().equals(
-                        "running");
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(mActivityTestRule.getActivity().getActivityTab().getTitle(),
+                    Matchers.not("running"));
         });
 
         // Make sure that content provider was asked to provide the content.
@@ -205,12 +198,9 @@
 
         mActivityTestRule.loadUrl(createContentUrl(resource));
 
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return !mActivityTestRule.getActivity().getActivityTab().getTitle().equals(
-                        "running");
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(mActivityTestRule.getActivity().getActivityTab().getTitle(),
+                    Matchers.not("running"));
         });
 
         // Make sure that content provider was asked to provide the content.
@@ -253,12 +243,9 @@
         mActivityTestRule.loadUrl(url);
         mActivityTestRule.runJavaScriptCodeInCurrentTab(script);
 
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mActivityTestRule.getActivity().getActivityTab().getTitle().equals(
-                        expectedTitle);
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(mActivityTestRule.getActivity().getActivityTab().getTitle(),
+                    Matchers.is(expectedTitle));
         });
         ensureResourceRequestCountInContentProviderNotLessThan(resource, expectedLoadCount);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java
index b156973..2bd5160 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java
@@ -10,6 +10,7 @@
 import android.support.test.InstrumentationRegistry;
 import android.view.KeyEvent;
 
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -26,6 +27,7 @@
 import org.chromium.content_public.browser.WebContents;
 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.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.media.MediaSwitches;
@@ -52,8 +54,14 @@
     }
 
     private void waitForContentsFullscreenState(boolean fullscreenValue) {
-        CriteriaHelper.pollInstrumentationThread(
-                Criteria.equals(fullscreenValue, () -> DOMUtils.isFullscreen(getWebContents())));
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            try {
+                Criteria.checkThat(
+                        DOMUtils.isFullscreen(getWebContents()), Matchers.is(fullscreenValue));
+            } catch (TimeoutException ex) {
+                throw new CriteriaNotSatisfiedException(ex);
+            }
+        });
     }
 
     private boolean isScreenOrientationLocked() {
@@ -72,25 +80,18 @@
     }
 
     private void waitUntilLockedToLandscape() {
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                try {
-                    return isScreenOrientationLocked() && isScreenOrientationLandscape();
-                } catch (TimeoutException e) {
-                    return false;
-                }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            try {
+                Criteria.checkThat(isScreenOrientationLocked(), Matchers.is(true));
+                Criteria.checkThat(isScreenOrientationLandscape(), Matchers.is(true));
+            } catch (TimeoutException e) {
+                throw new CriteriaNotSatisfiedException(e);
             }
         });
     }
 
     private void waitUntilUnlocked() {
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return !isScreenOrientationLocked();
-            }
-        });
+        CriteriaHelper.pollInstrumentationThread(() -> !isScreenOrientationLocked());
     }
 
     @Before
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java
index 35caa05..c49a5307 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/WarmupManagerTest.java
@@ -34,7 +34,6 @@
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
-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;
 import org.chromium.content_public.browser.test.util.WebContentsUtils;
@@ -112,12 +111,8 @@
             webContents.addObserver(observer);
             webContentsReference.set(webContents);
         });
-        CriteriaHelper.pollUiThread(new Criteria("Spare renderer is not initialized") {
-            @Override
-            public boolean isSatisfied() {
-                return isRenderViewReady.get();
-            }
-        });
+        CriteriaHelper.pollUiThread(
+                () -> isRenderViewReady.get(), "Spare renderer is not initialized");
         PostTask.runOrPostTask(
                 UiThreadTaskTraits.DEFAULT, () -> webContentsReference.get().destroy());
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility_tab_switcher/OverviewListLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility_tab_switcher/OverviewListLayoutTest.java
index 48d0df6..75f436f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility_tab_switcher/OverviewListLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility_tab_switcher/OverviewListLayoutTest.java
@@ -14,6 +14,7 @@
 
 import com.google.android.material.tabs.TabLayout;
 
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -44,7 +45,6 @@
 import org.chromium.content_public.browser.test.util.TouchCommon;
 import org.chromium.ui.test.util.UiRestriction;
 
-import java.util.concurrent.Callable;
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -65,49 +65,19 @@
     private static final int SWIPE_START_Y_OFFSET = 10;
     private static final int SWIPE_END_X = 20;
 
-    private class ChildCountCriteria extends Criteria {
-        private final int mChildCount;
-
-        public ChildCountCriteria(int count) {
-            mChildCount = count;
-        }
-
-        @Override
-        public boolean isSatisfied() {
-            return mChildCount
-                    == TestThreadUtils.runOnUiThreadBlockingNoException(new Callable<Integer>() {
-                           @Override
-                           public Integer call() {
-                               return getList().getChildCount();
-                           }
-                       });
-        }
+    private void verifyChildCount(int count) {
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(getList().getChildCount(), Matchers.is(count)));
     }
 
-    private class TabModelCountCountCriteria extends Criteria {
-        private final boolean mIncognito;
-        private final int mTabCount;
-
-        public TabModelCountCountCriteria(boolean incognito, int count) {
-            mIncognito = incognito;
-            mTabCount = count;
-        }
-
-        @Override
-        public boolean isSatisfied() {
-            int actualTabCount =
-                    TestThreadUtils.runOnUiThreadBlockingNoException(new Callable<Integer>() {
-                        @Override
-                        public Integer call() {
-                            return mActivityTestRule.getActivity()
-                                    .getTabModelSelector()
-                                    .getModel(mIncognito)
-                                    .getCount();
-                        }
-                    });
-            updateFailureReason("Expected tab count: " + mTabCount + ", Actual: " + actualTabCount);
-            return mTabCount == actualTabCount;
-        }
+    private void verifyTabModelCount(boolean incognito, int count) {
+        CriteriaHelper.pollUiThread(() -> {
+            int actualCount = mActivityTestRule.getActivity()
+                                      .getTabModelSelector()
+                                      .getModel(incognito)
+                                      .getCount();
+            Criteria.checkThat(actualCount, Matchers.is(count));
+        });
     }
 
     @Before
@@ -132,7 +102,7 @@
         TestTouchUtils.performClickOnMainSync(InstrumentationRegistry.getInstrumentation(),
                 mActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button));
 
-        CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(4));
+        verifyChildCount(4);
     }
 
     private AccessibilityTabModelListItem getListItemAndDisableAnimations(int index) {
@@ -157,11 +127,13 @@
     private void toggleTabSwitcher(final boolean expectVisible) {
         TestTouchUtils.performClickOnMainSync(InstrumentationRegistry.getInstrumentation(),
                 mActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button));
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                boolean isVisible = (getContainer() != null && getContainer().getParent() != null);
-                return isVisible == expectVisible;
+        CriteriaHelper.pollUiThread(() -> {
+            if (expectVisible) {
+                Criteria.checkThat(getContainer(), Matchers.notNullValue());
+                Criteria.checkThat(getContainer().getParent(), Matchers.notNullValue());
+            } else {
+                if (getContainer() == null) return;
+                Criteria.checkThat(getContainer().getParent(), Matchers.nullValue());
             }
         });
     }
@@ -317,8 +289,8 @@
         MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
                 mActivityTestRule.getActivity(), R.id.close_all_tabs_menu_id);
 
-        CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(0));
-        CriteriaHelper.pollInstrumentationThread(new TabModelCountCountCriteria(false, 0));
+        verifyChildCount(0);
+        verifyTabModelCount(false, 0);
         Assert.assertFalse(mActivityTestRule.getActivity()
                                    .findViewById(R.id.tab_switcher_mode_tab_switcher_button)
                                    .isEnabled());
@@ -335,13 +307,13 @@
         mActivityTestRule.newIncognitoTabsFromMenu(2);
         TestTouchUtils.performClickOnMainSync(InstrumentationRegistry.getInstrumentation(),
                 mActivityTestRule.getActivity().findViewById(R.id.tab_switcher_button));
-        CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(2));
+        verifyChildCount(2);
 
         MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
                 mActivityTestRule.getActivity(), R.id.close_all_incognito_tabs_menu_id);
-        CriteriaHelper.pollInstrumentationThread(new TabModelCountCountCriteria(true, 0));
+        verifyTabModelCount(true, 0);
 
-        CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(4));
+        verifyChildCount(4);
         Assert.assertTrue(mActivityTestRule.getActivity()
                                   .findViewById(R.id.tab_switcher_mode_tab_switcher_button)
                                   .isEnabled());
@@ -349,8 +321,8 @@
         MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
                 mActivityTestRule.getActivity(), R.id.close_all_tabs_menu_id);
 
-        CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(0));
-        CriteriaHelper.pollInstrumentationThread(new TabModelCountCountCriteria(false, 0));
+        verifyChildCount(0);
+        verifyTabModelCount(false, 0);
         Assert.assertFalse(mActivityTestRule.getActivity()
                                    .findViewById(R.id.tab_switcher_mode_tab_switcher_button)
                                    .isEnabled());
@@ -403,12 +375,12 @@
 
         TestThreadUtils.runOnUiThreadBlocking(() -> incognitoButton.select());
 
-        CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(2));
+        verifyChildCount(2);
 
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> getContainer().getStandardTabsButton().select());
 
-        CriteriaHelper.pollInstrumentationThread(new ChildCountCriteria(4));
+        verifyChildCount(4);
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java
index 1af7fd5..c71980e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java
@@ -58,7 +58,8 @@
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private static final String TEST_URL = UrlUtils.encodeHtmlDataUri("<html>foo</html>");
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
index 61901601..6fd2f6a8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
@@ -104,7 +104,8 @@
             new ChromeActivityTestRule<>(ChromeActivity.class);
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private static final String TEST_PAGE_URL_GOOGLE = "/chrome/test/data/android/google.html";
     private static final String TEST_PAGE_TITLE_GOOGLE = "The Google";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java
index da9d710..578734f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java
@@ -12,6 +12,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
@@ -22,8 +23,6 @@
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.webapps.WebappTestHelper;
-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;
 
 import java.util.Arrays;
@@ -45,23 +44,6 @@
     public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
             new ChromeActivityTestRule<>(ChromeActivity.class);
 
-    private boolean mCallbackCalled;
-
-    private class CallbackCriteria extends Criteria {
-        public CallbackCriteria() {
-            mCallbackCalled = false;
-        }
-
-        @Override
-        public boolean isSatisfied() {
-            if (mCallbackCalled) {
-                mCallbackCalled = false;
-                return true;
-            }
-            return false;
-        }
-    }
-
     @Before
     public void setUp() throws InterruptedException {
         mActivityTestRule.startMainActivityOnBlankPage();
@@ -95,34 +77,36 @@
         }
         Assert.assertEquals(apps.keySet(), WebappRegistry.getRegisteredWebappIdsForTesting());
 
+        CallbackHelper dataClearedExcludingDomainHelper = new CallbackHelper();
         // Clear cookies and site data excluding the registrable domain "google.com".
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             BrowsingDataBridge.getInstance().clearBrowsingDataExcludingDomains(
                     new OnClearBrowsingDataListener() {
                         @Override
                         public void onBrowsingDataCleared() {
-                            mCallbackCalled = true;
+                            dataClearedExcludingDomainHelper.notifyCalled();
                         }
                     },
                     new int[] {BrowsingDataType.COOKIES}, TimePeriod.ALL_TIME,
                     new String[] {"google.com"}, new int[] {1}, new String[0], new int[0]);
         });
-        CriteriaHelper.pollUiThread(new CallbackCriteria());
+        dataClearedExcludingDomainHelper.waitForFirst();
 
         // The last two webapps should have been unregistered.
         Assert.assertEquals(new HashSet<String>(Arrays.asList("webapp1")),
                 WebappRegistry.getRegisteredWebappIdsForTesting());
 
+        CallbackHelper dataClearedNoUrlFilterHelper = new CallbackHelper();
         // Clear cookies and site data with no url filter.
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             BrowsingDataBridge.getInstance().clearBrowsingData(new OnClearBrowsingDataListener() {
                 @Override
                 public void onBrowsingDataCleared() {
-                    mCallbackCalled = true;
+                    dataClearedNoUrlFilterHelper.notifyCalled();
                 }
             }, new int[] {BrowsingDataType.COOKIES}, TimePeriod.ALL_TIME);
         });
-        CriteriaHelper.pollUiThread(new CallbackCriteria());
+        dataClearedNoUrlFilterHelper.waitForFirst();
 
         // All webapps should have been unregistered.
         Assert.assertTrue(WebappRegistry.getRegisteredWebappIdsForTesting().isEmpty());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentTest.java
index 05c7147..b6737a0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentTest.java
@@ -127,11 +127,8 @@
                 ? 10000L
                 : CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL;
 
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return preferences.getProgressDialog() == null;
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(preferences.getProgressDialog(), Matchers.nullValue());
         }, kDelay, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
 
@@ -309,7 +306,7 @@
      * A criterion that is satisfied when a ClearBrowsingDataFragment fragment in the given
      * Settings activity is closed.
      */
-    static class PreferenceScreenClosedCriterion extends Criteria {
+    static class PreferenceScreenClosedCriterion implements Runnable {
         final SettingsActivity mSettingsActivity;
 
         /**
@@ -322,10 +319,11 @@
         }
 
         @Override
-        public boolean isSatisfied() {
+        public void run() {
             ClearBrowsingDataFragment fragment =
                     (ClearBrowsingDataFragment) mSettingsActivity.getMainFragment();
-            return fragment == null || !fragment.isVisible();
+            if (fragment == null) return;
+            Criteria.checkThat(fragment.isVisible(), Matchers.is(false));
         }
     }
 
@@ -360,15 +358,13 @@
                 new OpenPreferencesEnableDialogAndClickClearRunnable(settingsActivity2));
 
         // The dialog about other forms of history should now be shown.
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                ClearBrowsingDataFragment fragment =
-                        (ClearBrowsingDataFragment) settingsActivity2.getMainFragment();
-                OtherFormsOfHistoryDialogFragment dialog =
-                        fragment.getDialogAboutOtherFormsOfBrowsingHistory();
-                return dialog != null && dialog.getActivity() != null;
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            ClearBrowsingDataFragment fragment =
+                    (ClearBrowsingDataFragment) settingsActivity2.getMainFragment();
+            OtherFormsOfHistoryDialogFragment dialog =
+                    fragment.getDialogAboutOtherFormsOfBrowsingHistory();
+            Criteria.checkThat(dialog, Matchers.notNullValue());
+            Criteria.checkThat(dialog.getActivity(), Matchers.notNullValue());
         });
 
         // Close that dialog.
@@ -437,14 +433,16 @@
     private void waitForImportantDialogToShow(
             final ClearBrowsingDataFragment preferences, final int numImportantSites) {
         CriteriaHelper.pollUiThread(() -> {
-            Assert.assertNotNull(preferences);
-            Assert.assertNotNull(preferences.getImportantSitesDialogFragment());
-            Assert.assertTrue(
-                    preferences.getImportantSitesDialogFragment().getDialog().isShowing());
+            Criteria.checkThat(preferences, Matchers.notNullValue());
+            Criteria.checkThat(
+                    preferences.getImportantSitesDialogFragment(), Matchers.notNullValue());
+            Criteria.checkThat(
+                    preferences.getImportantSitesDialogFragment().getDialog().isShowing(),
+                    Matchers.is(true));
 
             ListView sitesList = preferences.getImportantSitesDialogFragment().getSitesList();
-            Assert.assertEquals(numImportantSites, sitesList.getAdapter().getCount());
-            Assert.assertThat(
+            Criteria.checkThat(sitesList.getAdapter().getCount(), Matchers.is(numImportantSites));
+            Criteria.checkThat(
                     sitesList.getChildCount(), Matchers.greaterThanOrEqualTo(numImportantSites));
         });
     }
@@ -565,13 +563,9 @@
         });
 
         // Check that our server origin is in the set of deselected domains.
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                ConfirmImportantSitesDialogFragment dialog =
-                        fragment.getImportantSitesDialogFragment();
-                return dialog.getDeselectedDomains().contains(kKeepDomain);
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            ConfirmImportantSitesDialogFragment dialog = fragment.getImportantSitesDialogFragment();
+            Criteria.checkThat(dialog.getDeselectedDomains(), Matchers.hasItem(kKeepDomain));
         });
 
         // Click the clear button.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java
index 60616b2..f80441566 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java
@@ -67,7 +67,8 @@
             new ChromeActivityTestRule<>(ChromeActivity.class);
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     // The dialog we are testing.
     private ContactsPickerDialog mDialog;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuRenderTest.java
index 0596392..56620f48 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuRenderTest.java
@@ -47,7 +47,8 @@
             new NightModeTestUtils.NightModeParams().getParameters();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private ModelListAdapter mAdapter;
     private ModelList mListItems;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index def3c0b..d1044bb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -35,7 +35,6 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
-import android.text.TextUtils;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.SubMenu;
@@ -56,6 +55,7 @@
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
 
+import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -123,6 +123,7 @@
 import org.chromium.content_public.browser.test.util.ClickUtils;
 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.CriteriaNotSatisfiedException;
 import org.chromium.content_public.browser.test.util.DOMUtils;
 import org.chromium.content_public.browser.test.util.JavaScriptUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -785,11 +786,8 @@
             Assert.assertNotNull(item);
             getActivity().onMenuOrKeyboardAction(R.id.open_in_browser_id, false);
         });
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return InstrumentationRegistry.getInstrumentation().checkMonitorHit(monitor, 1);
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            return InstrumentationRegistry.getInstrumentation().checkMonitorHit(monitor, 1);
         });
 
         callbackTriggered.waitForCallback(0);
@@ -842,27 +840,16 @@
                 CustomTabsTestUtils.createMinimalCustomTabIntent(
                         InstrumentationRegistry.getTargetContext(),
                         mTestServer.getURL(SELECT_POPUP_PAGE)));
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return currentTab != null && currentTab.getWebContents() != null;
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(currentTab, Matchers.notNullValue());
+            Criteria.checkThat(currentTab.getWebContents(), Matchers.notNullValue());
         });
         DOMUtils.clickNode(mCustomTabActivityTestRule.getWebContents(), "select");
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return isSelectPopupVisible(mCustomTabActivityTestRule.getActivity());
-            }
-        });
+        CriteriaHelper.pollUiThread(
+                () -> isSelectPopupVisible(mCustomTabActivityTestRule.getActivity()));
         final ChromeActivity newActivity = reparentAndVerifyTab();
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return isSelectPopupVisible(newActivity);
-            }
-        });
+        CriteriaHelper.pollUiThread(() -> isSelectPopupVisible(newActivity));
     }
     /**
      * Test whether the color of the toolbar is correctly customized. For L or later releases,
@@ -1125,8 +1112,9 @@
                     return getSessionDataHolder().handleIntent(
                             CustomTabsTestUtils.createMinimalCustomTabIntent(context, mTestPage2));
                 }));
-        CriteriaHelper.pollInstrumentationThread(
-                Criteria.equals(mTestPage, () -> getActivity().getActivityTab().getUrlString()));
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            Criteria.checkThat(getActivity().getActivityTab().getUrlString(), is(mTestPage));
+        });
         Assert.assertTrue("CustomTabContentHandler can't handle intent with same session",
                 TestThreadUtils.runOnUiThreadBlockingNoException(() -> {
                     intent.setData(Uri.parse(mTestPage2));
@@ -1141,8 +1129,9 @@
             }
         });
         pageLoadFinishedHelper.waitForCallback(0);
-        CriteriaHelper.pollInstrumentationThread(
-                Criteria.equals(mTestPage2, () -> getActivity().getActivityTab().getUrlString()));
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            Criteria.checkThat(getActivity().getActivityTab().getUrlString(), is(mTestPage2));
+        });
     }
 
     @Test
@@ -1386,22 +1375,17 @@
         }
 
         mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return url.equals(currentTab.getUrlString());
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(currentTab.getUrlString(), is(url));
         });
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                CustomTabToolbar toolbar =
-                        mCustomTabActivityTestRule.getActivity().findViewById(R.id.toolbar);
-                TextView titleBar = toolbar.findViewById(R.id.title_bar);
-                return titleBar != null && titleBar.isShown()
-                        && (titleBar.getText()).toString().equals(expectedTitle);
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            CustomTabToolbar toolbar =
+                    mCustomTabActivityTestRule.getActivity().findViewById(R.id.toolbar);
+            TextView titleBar = toolbar.findViewById(R.id.title_bar);
+            Criteria.checkThat(titleBar, Matchers.notNullValue());
+            Criteria.checkThat(titleBar.isShown(), is(true));
+            Criteria.checkThat(titleBar.getText().toString(), is(expectedTitle));
         });
     }
 
@@ -1420,24 +1404,18 @@
         Assert.assertTrue(connection.newSession(token));
         Assert.assertTrue(connection.requestPostMessageChannel(token, null));
         mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return mTestPage.equals(currentTab.getUrlString());
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(currentTab.getUrlString(), is(mTestPage));
         });
         Assert.assertTrue(
                 connection.postMessage(token, "Message", null) == CustomTabsService.RESULT_SUCCESS);
         TestThreadUtils.runOnUiThreadBlocking(
                 (Runnable) () -> mCustomTabActivityTestRule.getActivity().getActivityTab().loadUrl(
                                 new LoadUrlParams(mTestPage2)));
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return ChromeTabUtils.isLoadingAndRenderingDone(currentTab);
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            return ChromeTabUtils.isLoadingAndRenderingDone(currentTab);
         });
         Assert.assertTrue(connection.postMessage(token, "Message", null)
                 == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR);
@@ -1458,12 +1436,9 @@
         Assert.assertTrue(connection.newSession(token));
         Assert.assertTrue(connection.requestPostMessageChannel(token, null));
         mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return mTestPage.equals(currentTab.getUrlString());
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(currentTab.getUrlString(), is(mTestPage));
         });
         Assert.assertTrue(
                 connection.postMessage(token, "Message", null) == CustomTabsService.RESULT_SUCCESS);
@@ -1499,12 +1474,9 @@
                 CustomTabsSessionToken.getSessionTokenFromIntent(intent);
         Assert.assertTrue(connection.newSession(token));
         mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return mTestPage.equals(currentTab.getUrlString());
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(currentTab.getUrlString(), is(mTestPage));
         });
         Assert.assertTrue(connection.postMessage(token, "Message", null)
                 == CustomTabsService.RESULT_FAILURE_MESSAGING_ERROR);
@@ -1526,12 +1498,9 @@
         Assert.assertTrue(connection.newSession(token));
         Assert.assertTrue(connection.requestPostMessageChannel(token, null));
         mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return url.equals(currentTab.getUrlString());
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(currentTab.getUrlString(), is(url));
         });
         Assert.assertTrue(connection.postMessage(token, "New title", null)
                 == CustomTabsService.RESULT_SUCCESS);
@@ -1607,12 +1576,9 @@
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return url.equals(currentTab.getUrlString());
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(currentTab.getUrlString(), is(url));
         });
 
         session.requestPostMessageChannel(Uri.parse("https://www.example.com/"));
@@ -1711,12 +1677,9 @@
 
         mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
 
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return url.equals(currentTab.getUrlString());
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(currentTab.getUrlString(), is(url));
         });
 
         if (requestTime == AFTER_INTENT) {
@@ -1762,12 +1725,9 @@
         setCanUseHiddenTabForSession(connection, token, false);
         Assert.assertTrue(connection.mayLaunchUrl(token, Uri.parse(mTestPage), null, null));
         mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
-                return mTestPage.equals(currentTab.getUrlString());
-            }
+        CriteriaHelper.pollInstrumentationThread(() -> {
+            final Tab currentTab = mCustomTabActivityTestRule.getActivity().getActivityTab();
+            Criteria.checkThat(currentTab.getUrlString(), is(mTestPage));
         });
 
         Assert.assertFalse(mCustomTabActivityTestRule.getActivity().getActivityTab().canGoBack());
@@ -2126,12 +2086,9 @@
             final CustomTabActivity activity = mCustomTabActivityTestRule.getActivity();
             activity.getComponent().resolveNavigationController().finish(FinishReason.OTHER);
         });
-        CriteriaHelper.pollUiThread(new Criteria("No new spare renderer") {
-            @Override
-            public boolean isSatisfied() {
-                return WarmupManager.getInstance().hasSpareWebContents();
-            }
-        }, 2000, 200);
+        CriteriaHelper.pollUiThread(()
+                                            -> WarmupManager.getInstance().hasSpareWebContents(),
+                "No new spare renderer", 2000, 200);
     }
 
     /**
@@ -2223,27 +2180,14 @@
         mCctHiddenCallback.waitForCallback("CCT not hidden.", 0);
         mTabbedModeShownCallback.waitForCallback("Tabbed mode not shown.", 0);
 
-        CriteriaHelper.pollUiThread(
-                Criteria.equals(true, () -> tabbedActivity.get().areTabModelsInitialized()));
+        CriteriaHelper.pollUiThread(() -> tabbedActivity.get().areTabModelsInitialized());
 
-        CriteriaHelper.pollUiThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                Tab tab = tabbedActivity.get().getActivityTab();
-                if (tab == null) {
-                    updateFailureReason("Tab is null");
-                    return false;
-                }
-                if (!tab.isIncognito()) {
-                    updateFailureReason("Incognito tab not selected");
-                    return false;
-                }
-                if (!TextUtils.equals(tab.getUrlString(), "about:blank")) {
-                    updateFailureReason("Wrong URL loaded in incognito tab");
-                    return false;
-                }
-                return true;
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Tab tab = tabbedActivity.get().getActivityTab();
+            Criteria.checkThat("Tab is null", tab, Matchers.notNullValue());
+            Criteria.checkThat("Incognito tab not selected", tab.isIncognito(), is(true));
+            Criteria.checkThat(
+                    "Wrong URL loaded in incognito tab", tab.getUrlString(), is("about:blank"));
         });
 
         ApplicationStatus.unregisterActivityStateListener(listener);
@@ -2385,13 +2329,13 @@
                 url -> url.contains(TARGET_BLANK_TEST_PAGE));
 
         DOMUtils.clickNode(activity.getActivityTab().getWebContents(), "target_blank_link");
-        CriteriaHelper.pollUiThread(Criteria.equals(2,
-                () -> activity.getCurrentTabModel().getCount()));
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(activity.getCurrentTabModel().getCount(), is(2)));
 
         ClickUtils.clickButton(activity.findViewById(R.id.close_button));
 
-        CriteriaHelper.pollUiThread(Criteria.equals(1,
-                () -> activity.getCurrentTabModel().getCount()));
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(activity.getCurrentTabModel().getCount(), is(1)));
         assertFalse(activity.isFinishing());
     }
 
@@ -2409,8 +2353,8 @@
         Assert.assertEquals(activity.getCurrentTabModel().getCount(), 1);
 
         DOMUtils.clickNode(activity.getActivityTab().getWebContents(), "target_blank_link");
-        CriteriaHelper.pollUiThread(Criteria.equals(2,
-                () -> activity.getCurrentTabModel().getCount()));
+        CriteriaHelper.pollUiThread(
+                () -> Criteria.checkThat(activity.getCurrentTabModel().getCount(), is(2)));
 
         ClickUtils.clickButton(activity.findViewById(R.id.close_button));
 
@@ -2484,13 +2428,10 @@
                         + lastActivity.getClass().getName(),
                 lastActivity instanceof ChromeActivity);
         final ChromeActivity newActivity = (ChromeActivity) lastActivity;
-        CriteriaHelper.pollUiThread((new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return newActivity.getActivityTab() != null
-                        && newActivity.getActivityTab().equals(tabToBeReparented);
-            }
-        }));
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(newActivity.getActivityTab(), Matchers.notNullValue());
+            Criteria.checkThat(newActivity.getActivityTab(), is(tabToBeReparented));
+        });
         assertEquals(newActivity.getWindowAndroid(), tabToBeReparented.getWindowAndroid());
         assertEquals(newActivity.getWindowAndroid(),
                 tabToBeReparented.getWebContents().getTopLevelNativeWindow());
@@ -2633,11 +2574,9 @@
 
     private static void ensureCompletedSpeculationForUrl(
             final CustomTabsConnection connection, final String url) {
-        CriteriaHelper.pollUiThread(new Criteria("Tab was not created") {
-            @Override
-            public boolean isSatisfied() {
-                return connection.getSpeculationParamsForTesting() != null;
-            }
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat("Tab was not created", connection.getSpeculationParamsForTesting(),
+                    Matchers.notNullValue());
         }, LONG_TIMEOUT_MS, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
         ChromeTabUtils.waitForTabPageLoaded(connection.getSpeculationParamsForTesting().tab, url);
     }
@@ -2676,13 +2615,12 @@
         }
     }
 
-    private static class ElementContentCriteria extends Criteria {
+    private static class ElementContentCriteria implements Runnable {
         private final Tab mTab;
         private final String mJsFunction;
         private final String mExpected;
 
         public ElementContentCriteria(Tab tab, String elementId, String expected) {
-            super("Page element is not as expected.");
             mTab = tab;
             mExpected = "\"" + expected + "\"";
             mJsFunction = "(function () { return document.getElementById(\"" + elementId
@@ -2690,22 +2628,17 @@
         }
 
         @Override
-        public boolean isSatisfied() {
-            String value;
+        public void run() {
+            String value = null;
             try {
                 String jsonText = JavaScriptUtils.executeJavaScriptAndWaitForResult(
                         mTab.getWebContents(), mJsFunction);
                 if (jsonText.equalsIgnoreCase("null")) jsonText = "";
                 value = jsonText;
             } catch (TimeoutException e) {
-                e.printStackTrace();
-                return false;
+                throw new CriteriaNotSatisfiedException(e);
             }
-            boolean isSatisfied = TextUtils.equals(mExpected, value);
-            if (!isSatisfied) {
-              updateFailureReason("Page element is " + value + " instead of expected " + mExpected);
-            }
-            return isSatisfied;
+            Criteria.checkThat("Page element is not as expected.", value, is(mExpected));
         }
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/StubbedOfflineContentProvider.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/StubbedOfflineContentProvider.java
index 3436f577..f3127ba5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/StubbedOfflineContentProvider.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/StubbedOfflineContentProvider.java
@@ -14,6 +14,7 @@
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemSchedule;
 import org.chromium.components.offline_items_collection.OpenParams;
 import org.chromium.components.offline_items_collection.RenameResult;
 import org.chromium.components.offline_items_collection.ShareCallback;
@@ -106,6 +107,9 @@
     public void resumeDownload(ContentId id, boolean hasUserGesture) {}
 
     @Override
+    public void changeSchedule(final ContentId id, final OfflineItemSchedule schedule) {}
+
+    @Override
     public void cancelDownload(ContentId id) {}
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
index fd6845fd..3da708a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
@@ -16,6 +16,7 @@
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
 import org.chromium.components.offline_items_collection.OfflineItemFilter;
+import org.chromium.components.offline_items_collection.OfflineItemSchedule;
 import org.chromium.components.offline_items_collection.OfflineItemState;
 import org.chromium.components.offline_items_collection.OpenParams;
 import org.chromium.components.offline_items_collection.RenameResult;
@@ -79,6 +80,10 @@
         public void pauseDownload(ContentId id) {}
         @Override
         public void resumeDownload(ContentId id, boolean hasUserGesture) {}
+
+        @Override
+        public void changeSchedule(final ContentId id, final OfflineItemSchedule schedule) {}
+
         @Override
         public void cancelDownload(ContentId id) {}
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageTest.java
index f18cf6a..48452641 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageTest.java
@@ -85,7 +85,8 @@
             new ChromeActivityTestRule<>(ChromeActivity.class);
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private Tab mTab;
     private RecyclerView mRecyclerView;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SyncErrorInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SyncErrorInfoBarTest.java
index c1bda41..3de1c746 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SyncErrorInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/SyncErrorInfoBarTest.java
@@ -49,7 +49,8 @@
     };
 
     @Rule
-    public final ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public final ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Before
     public void setUp() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
index 6f5e134..a404d684 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
@@ -23,7 +23,6 @@
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.components.embedder_support.view.ContentView;
 import org.chromium.content_public.browser.WebContents;
-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.DOMUtils;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -56,17 +55,6 @@
             + "</select>"
             + "</body></html>");
 
-    private class PopupShowingCriteria extends Criteria {
-        public PopupShowingCriteria() {
-            super("The select popup did not show up on click.");
-        }
-
-        @Override
-        public boolean isSatisfied() {
-            return isSelectPopupVisibleOnUiThread();
-        }
-    }
-
     private boolean isSelectPopupVisibleOnUiThread() {
         try {
             // clang-format off
@@ -92,7 +80,8 @@
 
         // Once clicked, the popup should show up.
         DOMUtils.clickNode(mActivityTestRule.getWebContents(), "select");
-        CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria());
+        CriteriaHelper.pollInstrumentationThread(
+                this::isSelectPopupVisibleOnUiThread, "The select popup did not show up on click.");
 
         // Now create and destroy a different WebContents.
         TestThreadUtils.runOnUiThreadBlocking(() -> {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java
index e4082b1..509203c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/jsdialog/JavascriptAppModalDialogTest.java
@@ -14,13 +14,13 @@
 
 import androidx.test.filters.MediumTest;
 
+import org.hamcrest.Matchers;
 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.Log;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags.Add;
 import org.chromium.base.test.util.Feature;
@@ -118,8 +118,7 @@
         // JavaScript onbeforeunload dialogs require a user gesture.
         tapViewAndWait();
         TestThreadUtils.runOnUiThreadBlocking(() -> { activity.onBackPressed(); });
-        CriteriaHelper.pollInstrumentationThread(new JavascriptAppModalDialogShownCriteria(
-                "Could not spawn or locate a modal dialog.", true));
+        assertJavascriptAppModalDialogShownState(true);
 
         // Click leave and verify that the tab is closed.
         JavascriptAppModalDialog jsDialog = getCurrentDialog();
@@ -208,8 +207,7 @@
         });
 
         // Closing the tab should have dismissed the dialog.
-        CriteriaHelper.pollInstrumentationThread(new JavascriptAppModalDialogShownCriteria(
-                "The dialog should have been dismissed when its tab was closed.", false));
+        assertJavascriptAppModalDialogShownState(false);
     }
 
     /**
@@ -241,8 +239,7 @@
             final OnEvaluateJavaScriptResultHelper helper, String script) {
         helper.evaluateJavaScriptForTests(
                 mActivityTestRule.getActivity().getCurrentWebContents(), script);
-        CriteriaHelper.pollInstrumentationThread(new JavascriptAppModalDialogShownCriteria(
-                "Could not spawn or locate a modal dialog.", true));
+        assertJavascriptAppModalDialogShownState(true);
         return helper;
     }
 
@@ -272,27 +269,16 @@
         }
     }
 
-    private static class JavascriptAppModalDialogShownCriteria extends Criteria {
-        private final boolean mShouldBeShown;
-
-        public JavascriptAppModalDialogShownCriteria(String error, boolean shouldBeShown) {
-            super(error);
-            mShouldBeShown = shouldBeShown;
-        }
-
-        @Override
-        public boolean isSatisfied() {
-            try {
-                return TestThreadUtils.runOnUiThreadBlocking(() -> {
-                    final boolean isShown =
-                            JavascriptAppModalDialog.getCurrentDialogForTest() != null;
-                    return mShouldBeShown == isShown;
-                });
-            } catch (ExecutionException e) {
-                Log.e(TAG, "Failed to getCurrentDialog", e);
-                return false;
+    private void assertJavascriptAppModalDialogShownState(boolean shouldBeShown) {
+        CriteriaHelper.pollUiThread(() -> {
+            JavascriptAppModalDialog dialog = JavascriptAppModalDialog.getCurrentDialogForTest();
+            if (shouldBeShown) {
+                Criteria.checkThat("Could not spawn or locate a modal dialog.", dialog,
+                        Matchers.notNullValue());
+            } else {
+                Criteria.checkThat("No dialog should be shown.", dialog, Matchers.nullValue());
             }
-        }
+        });
     }
 
     private TestCallbackHelperContainer getActiveTabTestCallbackHelperContainer() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java
index 5b93cf2e..958b16f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogViewRenderTest.java
@@ -66,7 +66,7 @@
     private TextView mCustomTextView2;
 
     @Rule
-    public RenderTestRule mRenderTestRule = new RenderTestRule();
+    public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
 
     public ModalDialogViewRenderTest(boolean nightModeEnabled) {
         // Sets a fake background color to make the screenshots easier to compare with bare eyes.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
index 80e9bd4..c220821 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -104,7 +104,8 @@
     public SuggestionsDependenciesRule mSuggestionsDeps = new SuggestionsDependenciesRule();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private static final String TEST_PAGE = "/chrome/test/data/android/navigate/simple.html";
     private static final String TEST_FEED =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java
index f72bb1e..d569ccc9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusViewRenderTest.java
@@ -34,7 +34,8 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 public class StatusViewRenderTest extends DummyUiActivityTestCase {
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private StatusView mStatusView;
     private PropertyModel mStatusModel;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
index b3355a6e..6c060e6c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -70,7 +70,7 @@
 
     @Rule
     public RenderTestRule mRenderTestRule =
-            new RenderTestRule.SkiaGoldBuilder().setRevision(3).build();
+            RenderTestRule.Builder.withPublicCorpus().setRevision(3).build();
 
     private boolean mIsSystemLocationSettingEnabled = true;
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/IsReadyToPayServiceHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/IsReadyToPayServiceHelperTest.java
index 2177863e..f518a32 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/IsReadyToPayServiceHelperTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/IsReadyToPayServiceHelperTest.java
@@ -35,7 +35,6 @@
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.components.payments.intent.IsReadyToPayServiceHelper;
-import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 
 /**
@@ -189,12 +188,7 @@
                     }
                 });
         helper.query();
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mErrorReceived;
-            }
-        });
+        CriteriaHelper.pollInstrumentationThread(() -> mErrorReceived);
     }
 
     @Test
@@ -219,12 +213,7 @@
                     });
             helper.query();
         });
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mResponseReceived;
-            }
-        });
+        CriteriaHelper.pollInstrumentationThread(() -> mResponseReceived);
     }
 
     @Test
@@ -249,12 +238,7 @@
                     });
             helper.query();
         });
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mErrorReceived;
-            }
-        });
+        CriteriaHelper.pollInstrumentationThread(() -> mErrorReceived);
     }
 
     @Test
@@ -279,12 +263,7 @@
                     });
             helper.query();
         });
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mErrorReceived;
-            }
-        });
+        CriteriaHelper.pollInstrumentationThread(() -> mErrorReceived);
     }
 
     @Test
@@ -311,11 +290,6 @@
         });
         // Assuming CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL >
         // IsReadyToPayServiceHelper.SERVICE_CONNECTION_TIMEOUT_MS.
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mErrorReceived;
-            }
-        });
+        CriteriaHelper.pollInstrumentationThread(() -> mErrorReceived);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
index 944c9e7..9c6f0dab9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestFreeShippingTest.java
@@ -54,7 +54,7 @@
             new PaymentRequestTestRule("payment_request_free_shipping_test.html", this, true);
 
     @Rule
-    public RenderTestRule mRenderTestRule = new RenderTestRule();
+    public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
 
     @BeforeClass
     public static void setUpBeforeActivityLaunched() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRetryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRetryTest.java
index 5828c833..7fd00d5f2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRetryTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRetryTest.java
@@ -50,7 +50,7 @@
             new PaymentRequestTestRule("payment_request_retry.html", this);
 
     @Rule
-    public RenderTestRule mRenderTestRule = new RenderTestRule();
+    public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
 
     @Override
     public void onMainActivityStarted() throws TimeoutException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
index 9561fab..8eb8f09 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionNavigationTest.java
@@ -15,15 +15,11 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.permissions.PermissionTestRule.DialogShownCriteria;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.LocationSettingsTestUtil;
 import org.chromium.content_public.browser.NavigationHandle;
-import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.ui.modaldialog.ModalDialogManager;
 
 /**
  * Test suite for interaction between permissions requests and navigation.
@@ -60,11 +56,7 @@
     public void testNavigationDismissesModalPermissionPrompt() throws Exception {
         mPermissionRule.setUpUrl(TEST_FILE);
         mPermissionRule.runJavaScriptCodeInCurrentTab("requestGeolocationPermission()");
-        ModalDialogManager dialogManager = TestThreadUtils.runOnUiThreadBlockingNoException(
-                mPermissionRule.getActivity()::getModalDialogManager);
-        DialogShownCriteria criteriaShown =
-                new DialogShownCriteria(dialogManager, "Dialog not shown", true);
-        CriteriaHelper.pollUiThread(criteriaShown);
+        mPermissionRule.waitForDialogShownState(true);
 
         mPermissionRule.runJavaScriptCodeInCurrentTab("navigate()");
 
@@ -80,8 +72,6 @@
         callbackHelper.waitForCallback(0);
         tab.removeObserver(navigationWaiter);
 
-        DialogShownCriteria criteriaNotShown =
-                new DialogShownCriteria(dialogManager, "Dialog shown", false);
-        CriteriaHelper.pollUiThread(criteriaNotShown);
+        mPermissionRule.waitForDialogShownState(false);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
index 1103bba6..654e00e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/PermissionTestRule.java
@@ -6,6 +6,7 @@
 
 import android.support.test.InstrumentationRegistry;
 
+import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
@@ -31,9 +32,6 @@
 import org.chromium.ui.modaldialog.ModalDialogManager;
 import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType;
 
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-
 /**
  * TestRule for permissions UI testing on Android.
  *
@@ -109,41 +107,6 @@
         }, desc);
     }
 
-    /**
-     * Criteria class to detect whether the permission dialog is shown.
-     */
-    protected static class DialogShownCriteria extends Criteria {
-        private ModalDialogManager mModalDialogManager;
-        private boolean mExpectDialog;
-
-        public DialogShownCriteria(
-                ModalDialogManager modalDialogManager, String error, boolean expectDialog) {
-            super(error);
-            mModalDialogManager = modalDialogManager;
-            mExpectDialog = expectDialog;
-        }
-
-        @Override
-        public boolean isSatisfied() {
-            try {
-                return TestThreadUtils.runOnUiThreadBlocking(new Callable<Boolean>() {
-                    @Override
-                    public Boolean call() {
-                        boolean isDialogShownForTest =
-                                PermissionDialogController.getInstance().isDialogShownForTest();
-                        if (isDialogShownForTest) {
-                            ModalDialogTestUtils.checkCurrentPresenter(
-                                    mModalDialogManager, ModalDialogType.TAB);
-                        }
-                        return isDialogShownForTest == mExpectDialog;
-                    }
-                });
-            } catch (ExecutionException e) {
-                return false;
-            }
-        }
-    }
-
     public PermissionTestRule() {
         this(false);
     }
@@ -265,7 +228,7 @@
     private void replyToPromptAndWaitForUpdates(PermissionUpdateWaiter updateWaiter, boolean allow,
             int nUpdates, boolean isDialog) throws Exception {
         if (isDialog) {
-            waitForDialog(getActivity());
+            waitForDialogShownState(true);
             replyToDialogAndWaitForUpdates(updateWaiter, nUpdates, allow);
         } else {
             replyToInfoBarAndWaitForUpdates(updateWaiter, nUpdates, allow);
@@ -321,6 +284,13 @@
     }
 
     /**
+     * Verify the shown state of the dialog.
+     */
+    protected void waitForDialogShownState(boolean expectedShowState) {
+        waitForDialogShownState(getActivity(), expectedShowState);
+    }
+
+    /**
      * Utility functions to support permissions testing in other contexts.
      */
     public static void replyToDialog(boolean allow, ChromeActivity activity) {
@@ -332,11 +302,26 @@
         });
     }
 
-    public static void waitForDialog(ChromeActivity activity) {
+    /**
+     * Wait for the permission dialog to be in the expected shown state.
+     */
+    public static void waitForDialogShownState(ChromeActivity activity, boolean expectedShowState) {
         ModalDialogManager dialogManager =
                 TestThreadUtils.runOnUiThreadBlockingNoException(activity::getModalDialogManager);
-        DialogShownCriteria criteria =
-                new DialogShownCriteria(dialogManager, "Dialog not shown", true);
-        CriteriaHelper.pollUiThread(criteria);
+        CriteriaHelper.pollUiThread(() -> {
+            boolean isDialogShownForTest =
+                    PermissionDialogController.getInstance().isDialogShownForTest();
+            if (isDialogShownForTest) {
+                ModalDialogTestUtils.checkCurrentPresenter(dialogManager, ModalDialogType.TAB);
+            }
+            Criteria.checkThat(isDialogShownForTest, Matchers.is(expectedShowState));
+        });
+    }
+
+    /**
+     * Wait for the permission dialog to be shown.
+     */
+    public static void waitForDialog(ChromeActivity activity) {
+        waitForDialogShownState(activity, true);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
index 201c17c..db3bd6d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
@@ -72,7 +72,8 @@
             new ChromeActivityTestRule<>(ChromeActivity.class);
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     // The dialog we are testing.
     private PhotoPickerDialog mDialog;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerDialogFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerDialogFragmentTest.java
index 489aa8c..ceacc27 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerDialogFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerDialogFragmentTest.java
@@ -56,7 +56,8 @@
     public final Features.JUnitProcessor mProcessor = new Features.JUnitProcessor();
 
     @Rule
-    public final ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public final ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Rule
     public final AccountManagerTestRule mAccountManagerTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheRenderTest.java
index fc926e5..49947e60 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheRenderTest.java
@@ -60,7 +60,8 @@
     }
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private FrameLayout mContentView;
     private ImageView mImageView;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheWithBadgeRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheWithBadgeRenderTest.java
index d166caf..0ba757a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheWithBadgeRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheWithBadgeRenderTest.java
@@ -44,7 +44,8 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 public class ProfileDataCacheWithBadgeRenderTest extends DummyUiActivityTestCase {
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Mock
     private ProfileDataCache.Observer mObserver;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SignOutDialogRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SignOutDialogRenderTest.java
index fca549f..ec5e012e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SignOutDialogRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SignOutDialogRenderTest.java
@@ -46,7 +46,8 @@
     public final DisableAnimationsTestRule mNoAnimationsRule = new DisableAnimationsTestRule();
 
     @Rule
-    public final ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public final ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Rule
     public final JniMocker mocker = new JniMocker();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java
index c71933a..680e281 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFragmentTest.java
@@ -68,7 +68,8 @@
     public final SyncTestRule mSyncTestRule = new SyncTestRule();
 
     @Rule
-    public final ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public final ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private SigninActivity mSigninActivity;
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGridLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGridLayoutTest.java
index 6779e82e..397a572d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGridLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGridLayoutTest.java
@@ -91,7 +91,8 @@
     public EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private static final String[] FAKE_MOST_VISITED_URLS = new String[] {
             "/chrome/test/data/android/navigate/one.html",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
index 2b8d36e..ac97e0d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
@@ -91,7 +91,8 @@
             RuleChain.outerRule(mSyncTestRule).around(mSettingsActivityTestRule);
 
     @Rule
-    public final ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public final ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Test
     @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
index 2fdef42c..86790a4a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
@@ -96,7 +96,8 @@
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Rule
     public TestRule mProcessor = new Features.InstrumentationProcessor();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuRenderTest.java
index ad99590..91cbfebd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherActionMenuRenderTest.java
@@ -44,7 +44,8 @@
             new NightModeTestUtils.NightModeParams().getParameters();
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     private View mView;
 
diff --git a/chrome/android/junit/DEPS b/chrome/android/junit/DEPS
index f6d1bcd7..057b872 100644
--- a/chrome/android/junit/DEPS
+++ b/chrome/android/junit/DEPS
@@ -3,6 +3,7 @@
   "+chrome/browser/android/lifecycle",
   "+chrome/browser/image_fetcher",
   "+chrome/android/java/src/org/chromium/chrome/browser/ssl/ChromeSecurityStateModelDelegate.java",
+  "+chrome/browser/performance_hints/android/java",
   "+chrome/browser/profiles/android",
   "+chrome/browser/tab",
   "+chrome/browser/thumbnail/generator/android/java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuCoordinatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuCoordinatorTest.java
index 8e2faaf..3e1f20a1 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuCoordinatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuCoordinatorTest.java
@@ -6,6 +6,7 @@
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.when;
 
 import android.app.Activity;
 import android.util.Pair;
@@ -16,16 +17,20 @@
 import org.junit.Test;
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
 import org.chromium.blink_public.common.ContextMenuDataMediaType;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuItem.Item;
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator.ContextMenuGroup;
 import org.chromium.chrome.browser.contextmenu.RevampedContextMenuCoordinator.ListItemType;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserver;
+import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserverJni;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.embedder_support.contextmenu.ContextMenuParams;
@@ -40,10 +45,14 @@
  * Unit tests for the Revamped context menu.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Features.DisableFeatures(ChromeFeatureList.CONTEXT_MENU_PERFORMANCE_INFO)
 public class RevampedContextMenuCoordinatorTest {
     @Rule
     public TestRule mProcessor = new Features.JUnitProcessor();
+    @Rule
+    public JniMocker mocker = new JniMocker();
+
+    @Mock
+    PerformanceHintsObserver.Natives mNativeMock;
 
     private RevampedContextMenuCoordinator mCoordinator;
     private Activity mActivity;
@@ -55,6 +64,9 @@
         mActivity = Robolectric.setupActivity(Activity.class);
         mWindow = new ActivityWindowAndroid(mActivity, false);
         mCoordinator = new RevampedContextMenuCoordinator(0, null);
+        MockitoAnnotations.initMocks(this);
+        mocker.mock(PerformanceHintsObserverJni.TEST_HOOKS, mNativeMock);
+        when(mNativeMock.isContextMenuPerformanceInfoEnabled()).thenReturn(false);
     }
 
     @After
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderMediatorTest.java
index 7f410b49..ae28a46 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderMediatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderMediatorTest.java
@@ -6,6 +6,7 @@
 
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.when;
 
 import android.app.Activity;
 
@@ -14,13 +15,17 @@
 import org.junit.Test;
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
 import org.chromium.blink_public.common.ContextMenuDataMediaType;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserver;
 import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserver.PerformanceClass;
+import org.chromium.chrome.browser.performance_hints.PerformanceHintsObserverJni;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.embedder_support.contextmenu.ContextMenuParams;
@@ -33,6 +38,11 @@
 public class RevampedContextMenuHeaderMediatorTest {
     @Rule
     public TestRule mProcessor = new Features.JUnitProcessor();
+    @Rule
+    public JniMocker mocker = new JniMocker();
+
+    @Mock
+    PerformanceHintsObserver.Natives mNativeMock;
 
     private Activity mActivity;
     private final Profile mProfile = Mockito.mock(Profile.class);
@@ -40,11 +50,13 @@
     @Before
     public void setUpTest() {
         mActivity = Robolectric.setupActivity(Activity.class);
+        MockitoAnnotations.initMocks(this);
+        mocker.mock(PerformanceHintsObserverJni.TEST_HOOKS, mNativeMock);
     }
 
     @Test
-    @Features.EnableFeatures(ChromeFeatureList.CONTEXT_MENU_PERFORMANCE_INFO)
     public void testPerformanceInfoEnabled() {
+        when(mNativeMock.isContextMenuPerformanceInfoEnabled()).thenReturn(true);
         PropertyModel model =
                 new PropertyModel.Builder(RevampedContextMenuHeaderProperties.ALL_KEYS)
                         .with(RevampedContextMenuHeaderProperties.URL_PERFORMANCE_CLASS,
@@ -60,8 +72,8 @@
     }
 
     @Test
-    @Features.DisableFeatures(ChromeFeatureList.CONTEXT_MENU_PERFORMANCE_INFO)
     public void testPerformanceInfoDisabled() {
+        when(mNativeMock.isContextMenuPerformanceInfoEnabled()).thenReturn(false);
         PropertyModel model =
                 new PropertyModel.Builder(RevampedContextMenuHeaderProperties.ALL_KEYS)
                         .with(RevampedContextMenuHeaderProperties.URL_PERFORMANCE_CLASS,
@@ -77,8 +89,8 @@
     }
 
     @Test
-    @Features.EnableFeatures(ChromeFeatureList.CONTEXT_MENU_PERFORMANCE_INFO)
     public void testNoPerformanceInfoOnNonAnchor() {
+        when(mNativeMock.isContextMenuPerformanceInfoEnabled()).thenReturn(true);
         PropertyModel model =
                 new PropertyModel.Builder(RevampedContextMenuHeaderProperties.ALL_KEYS)
                         .with(RevampedContextMenuHeaderProperties.URL_PERFORMANCE_CLASS,
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index a5adc71..0688eff 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -2789,7 +2789,7 @@
     Android settings
   </message>
   <message name="IDS_SETTINGS_ANDROID_APPS_SUBTEXT" desc="Description for the section for enabling and managing Google Play Store (Android) apps.">
-    Install apps and games from Google Play on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. &lt;a target="_blank" href="<ph name="URL">$2<ex>https://google.com/</ex></ph>"&gt;Learn more&lt;/a&gt;
+    Install apps and games from Google Play on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. <ph name="LINK_BEGIN">&lt;a target="_blank" href="$2<ex>https://google.com/</ex>"&gt;</ph>Learn more<ph name="LINK_END">&lt;/a&gt;</ph>
   </message>
   <!-- TODO(jamescook): Use device type instead of "Chromebook", which may
         require changing ArcPlayTermsOfServiceConsent resource id handling. -->
diff --git a/chrome/app/printing_strings.grdp b/chrome/app/printing_strings.grdp
index 9eb4ca36..44baefde 100644
--- a/chrome/app/printing_strings.grdp
+++ b/chrome/app/printing_strings.grdp
@@ -321,49 +321,49 @@
         End User License Agreement
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_CONNECTING_TO_DEVICE" desc="Error label to show under the destination dropdown when the device can't connect to the printer.">
-         Error connecting to <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph>
+         Connection error
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_DEVICE_ERROR" desc="Error label to show under the destination dropdown when the printer has a device error.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph> has a device error
+         Printer device error
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_DOOR_OPEN" desc="Error label to show under the destination dropdown when the printer has an open door.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph>'s door is open
+         Printer door is open
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_LOW_ON_INK" desc="Error label to show under the destination dropdown when the printer is low on ink.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph> is low on ink
+         Low on ink
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_LOW_ON_PAPER" desc="Error label to show under the destination dropdown when the printer is low on paper">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph> is low on paper
+         Low on paper
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_OUT_OF_INK" desc="Error label to show under the destination dropdown when the printer is out of ink.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph> is out of ink
+         Out of ink
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_OUT_OF_PAPER" desc="Error label to show under the destination dropdown when the printer is out of paper.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph> is out of paper
+         Out of paper
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_OUPUT_ALMOST_FULL" desc="Error label to show under the destination dropdown when the printer's output area is almost full.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph>'s output area is almost full
+         Output area is almost full
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_OUPUT_FULL" desc="Error label to show under the destination dropdown when the printer's output area is full.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph>'s output area is full
+         Output area is full
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_PAPER_JAM" desc="Error label to show under the destination dropdown when the printer has a paper jam.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph>'s paper is jammed
+         Paper is jammed
       </message>
-      <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_PAUSED" desc="Error label to show under the destination dropdown when the printer is paused.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph> is paused
+      <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_PAUSED" desc="Error label to show under the destination dropdown when the printer is in a paused state.">
+         Printer is paused
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_PRINTER_QUEUE_FULL" desc="Error label to show under the destination dropdown when the printer has a full queue.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph>'s queue is full
+         Printer queue is full
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_PRINTER_UNREACHABLE" desc="Error label to show under the destination dropdown when the printer is unreachable.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph> is unreachable
+         Printer is unreachable
       </message>
-      <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_STOPPED" desc="Error label to show under the destination dropdown when the printer is stopped.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph> is stopped
+      <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_STOPPED" desc="Error label to show under the destination dropdown when the printer is in a stopped state.">
+         Printer is stopped
       </message>
       <message name="IDS_PRINT_PREVIEW_PRINTER_STATUS_TRAY_MISSING" desc="Error label to show under the destination dropdown when the printer is missing a tray.">
-         <ph name="PRINTER_NAME">$1<ex>Home Office Printer</ex></ph> is missing a tray
+         Tray is missing
       </message>
       <message name="IDS_PRINT_PREVIEW_SHEETS_LIMIT_ERROR_MESSAGE" desc="Sheets limit error message, explaining to the user why printing is blocked.">
       {COUNT, plural,
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_CONNECTING_TO_DEVICE.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_CONNECTING_TO_DEVICE.png.sha1
new file mode 100644
index 0000000..c9b1646
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_CONNECTING_TO_DEVICE.png.sha1
@@ -0,0 +1 @@
+978189e21a59c1cad38ac97396bc4220853b0d20
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_DEVICE_ERROR.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_DEVICE_ERROR.png.sha1
new file mode 100644
index 0000000..14048ee
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_DEVICE_ERROR.png.sha1
@@ -0,0 +1 @@
+5edd6baee151e5822dc87d55712fa8f091f4c431
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_DOOR_OPEN.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_DOOR_OPEN.png.sha1
new file mode 100644
index 0000000..c1c07be2
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_DOOR_OPEN.png.sha1
@@ -0,0 +1 @@
+f2be6e1ffc9a5a4ddea272ab1fde1da72737d5f0
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_LOW_ON_INK.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_LOW_ON_INK.png.sha1
new file mode 100644
index 0000000..20cf14d
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_LOW_ON_INK.png.sha1
@@ -0,0 +1 @@
+5a440cb9d699ef2f7ae69d0653d5f90760e1f810
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_LOW_ON_PAPER.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_LOW_ON_PAPER.png.sha1
new file mode 100644
index 0000000..eaaa4dd
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_LOW_ON_PAPER.png.sha1
@@ -0,0 +1 @@
+8482204d609ac7812974410a387aca72f7bd6b14
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUPUT_ALMOST_FULL.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUPUT_ALMOST_FULL.png.sha1
new file mode 100644
index 0000000..ef84d26
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUPUT_ALMOST_FULL.png.sha1
@@ -0,0 +1 @@
+71cda66a9b0656f26ccb9032b8fa9dbd649f6740
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUPUT_FULL.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUPUT_FULL.png.sha1
new file mode 100644
index 0000000..7b00498
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUPUT_FULL.png.sha1
@@ -0,0 +1 @@
+fd3a1cb57450d9e7b28bab6cb6323f2e50149c03
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUT_OF_INK.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUT_OF_INK.png.sha1
new file mode 100644
index 0000000..16fce9d
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUT_OF_INK.png.sha1
@@ -0,0 +1 @@
+27fd1b3bfe0f9800b27dafb5a571137a04c9a66d
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUT_OF_PAPER.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUT_OF_PAPER.png.sha1
new file mode 100644
index 0000000..bd509021
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_OUT_OF_PAPER.png.sha1
@@ -0,0 +1 @@
+467ccefb5951a22d489c47ec7eddc4b03445497b
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PAPER_JAM.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PAPER_JAM.png.sha1
new file mode 100644
index 0000000..dcd4586
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PAPER_JAM.png.sha1
@@ -0,0 +1 @@
+80119474ffa517b9f1ec5c4577d592e38e141c56
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PAUSED.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PAUSED.png.sha1
new file mode 100644
index 0000000..b49d6de
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PAUSED.png.sha1
@@ -0,0 +1 @@
+5a75e0cc91b5eaaf976ff880a896df347b7beb7e
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PRINTER_QUEUE_FULL.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PRINTER_QUEUE_FULL.png.sha1
new file mode 100644
index 0000000..ddcaa9f
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PRINTER_QUEUE_FULL.png.sha1
@@ -0,0 +1 @@
+3c52e8fcb4d9823432bbd77e3a56a6e917fac121
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PRINTER_UNREACHABLE.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PRINTER_UNREACHABLE.png.sha1
new file mode 100644
index 0000000..b62cc869
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_PRINTER_UNREACHABLE.png.sha1
@@ -0,0 +1 @@
+852457d45839a5239a52cfbeab403a0cfd0f26dd
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_STOPPED.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_STOPPED.png.sha1
new file mode 100644
index 0000000..36e1c7d
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_STOPPED.png.sha1
@@ -0,0 +1 @@
+6d53f3ed901ed9222bc8254828685bbf3f274eb4
\ No newline at end of file
diff --git a/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_TRAY_MISSING.png.sha1 b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_TRAY_MISSING.png.sha1
new file mode 100644
index 0000000..709bcfd
--- /dev/null
+++ b/chrome/app/printing_strings_grdp/IDS_PRINT_PREVIEW_PRINTER_STATUS_TRAY_MISSING.png.sha1
@@ -0,0 +1 @@
+9bbc29fe09b3520d5ccbf9904bb60a62ac8bbf4b
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b60dd2d..42227bc3a 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -946,12 +946,8 @@
     "optimization_guide/optimization_guide_util.h",
     "optimization_guide/optimization_guide_web_contents_observer.cc",
     "optimization_guide/optimization_guide_web_contents_observer.h",
-    "optimization_guide/prediction/decision_tree_prediction_model.cc",
-    "optimization_guide/prediction/decision_tree_prediction_model.h",
     "optimization_guide/prediction/prediction_manager.cc",
     "optimization_guide/prediction/prediction_manager.h",
-    "optimization_guide/prediction/prediction_model.cc",
-    "optimization_guide/prediction/prediction_model.h",
     "optimization_guide/prediction/prediction_model_fetcher.cc",
     "optimization_guide/prediction/prediction_model_fetcher.h",
     "page_load_metrics/observers/aborts_page_load_metrics_observer.cc",
@@ -1042,6 +1038,8 @@
     "payments/payment_handler_permission_context.cc",
     "payments/payment_handler_permission_context.h",
     "payments/ssl_validity_checker.cc",
+    "performance_hints/performance_hints_features.cc",
+    "performance_hints/performance_hints_features.h",
     "performance_hints/performance_hints_observer.cc",
     "performance_hints/performance_hints_observer.h",
     "performance_hints/performance_hints_rewrite_handler.cc",
@@ -3109,8 +3107,6 @@
       "enterprise/connectors/reporting_service_settings.h",
       "enterprise/connectors/service_provider_config.cc",
       "enterprise/connectors/service_provider_config.h",
-      "enterprise/reporting/browser_report_generator.cc",
-      "enterprise/reporting/browser_report_generator.h",
       "enterprise/reporting/browser_report_generator_desktop.cc",
       "enterprise/reporting/browser_report_generator_desktop.h",
       "enterprise/reporting/extension_info.cc",
@@ -3308,11 +3304,17 @@
       "nearby_sharing/instantmessaging/stream_parser.h",
       "nearby_sharing/instantmessaging/token_fetcher.cc",
       "nearby_sharing/instantmessaging/token_fetcher.h",
+      "nearby_sharing/logging/log_buffer.h",
+      "nearby_sharing/logging/logging.h",
       "nearby_sharing/nearby_connection.h",
       "nearby_sharing/nearby_connections_manager.h",
       "nearby_sharing/nearby_connections_manager_impl.cc",
       "nearby_sharing/nearby_connections_manager_impl.h",
       "nearby_sharing/nearby_constants.h",
+      "nearby_sharing/nearby_notification_handler.cc",
+      "nearby_sharing/nearby_notification_handler.h",
+      "nearby_sharing/nearby_notification_manager.cc",
+      "nearby_sharing/nearby_notification_manager.h",
       "nearby_sharing/nearby_process_manager.cc",
       "nearby_sharing/nearby_process_manager.h",
       "nearby_sharing/nearby_sharing_prefs.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index a8a60c5..284f25b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -37,6 +37,7 @@
 #include "chrome/browser/net/stub_resolver_config_reader.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/notifications/scheduler/public/features.h"
+#include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/performance_manager/policies/policy_features.h"
 #include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
 #include "chrome/browser/predictors/loading_predictor_config.h"
@@ -5553,17 +5554,19 @@
                                     kPasswordChangeFeatureVariations,
                                     "PasswordChangeFeatureVariations.")},
 
-    {"context-menu-performance-info",
-     flag_descriptions::kContextMenuPerformanceInfoName,
-     flag_descriptions::kContextMenuPerformanceInfoDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kContextMenuPerformanceInfo)},
+    {"context-menu-performance-info-and-remote-hints-fetching",
+     flag_descriptions::kContextMenuPerformanceInfoAndRemoteHintFetchingName,
+     flag_descriptions::
+         kContextMenuPerformanceInfoAndRemoteHintFetchingDescription,
+     kOsAndroid,
+     FEATURE_VALUE_TYPE(kContextMenuPerformanceInfoAndRemoteHintFetching)},
 #endif  // !defined(OS_ANDROID)
 
 #if defined(OS_ANDROID)
     {"page-info-performance-hints",
      flag_descriptions::kPageInfoPerformanceHintsName,
      flag_descriptions::kPageInfoPerformanceHintsDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kPageInfoPerformanceHints)},
+     FEATURE_VALUE_TYPE(kPageInfoPerformanceHints)},
 #endif  // !defined(OS_ANDROID)
 
 #if defined(OS_ANDROID)
@@ -5790,6 +5793,10 @@
      FEATURE_VALUE_TYPE(features::kSharesheet)},
 #endif  // OS_CHROMEOS
 
+    {"schemeful-same-site", flag_descriptions::kSchemefulSameSiteName,
+     flag_descriptions::kSchemefulSameSiteDescription, kOsAll,
+     FEATURE_VALUE_TYPE(net::features::kSchemefulSameSite)},
+
     // 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/autofill_assistant/generic_ui_controller_android.cc b/chrome/browser/android/autofill_assistant/generic_ui_controller_android.cc
index 6c8c6cb..c1efbdd 100644
--- a/chrome/browser/android/autofill_assistant/generic_ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/generic_ui_controller_android.cc
@@ -444,17 +444,16 @@
 std::unique_ptr<GenericUiControllerAndroid>
 GenericUiControllerAndroid::CreateFromProto(
     const GenericUserInterfaceProto& proto,
-    const std::map<std::string, std::string> context,
     base::android::ScopedJavaGlobalRef<jobject> jcontext,
     base::android::ScopedJavaGlobalRef<jobject> jdelegate,
     EventHandler* event_handler,
     UserModel* user_model,
     BasicInteractions* basic_interactions) {
   // Create view layout.
-  auto view_handler = std::make_unique<ViewHandlerAndroid>(context);
+  auto view_handler = std::make_unique<ViewHandlerAndroid>();
   auto interaction_handler = std::make_unique<InteractionHandlerAndroid>(
-      context, event_handler, user_model, basic_interactions,
-      view_handler.get(), jcontext, jdelegate);
+      event_handler, user_model, basic_interactions, view_handler.get(),
+      jcontext, jdelegate);
   auto radio_button_controller =
       std::make_unique<RadioButtonController>(user_model);
   JNIEnv* env = base::android::AttachCurrentThread();
diff --git a/chrome/browser/android/autofill_assistant/generic_ui_controller_android.h b/chrome/browser/android/autofill_assistant/generic_ui_controller_android.h
index dd4b530..4e124c9 100644
--- a/chrome/browser/android/autofill_assistant/generic_ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/generic_ui_controller_android.h
@@ -29,7 +29,6 @@
   // Ownership of the arguments is not changed.
   static std::unique_ptr<GenericUiControllerAndroid> CreateFromProto(
       const GenericUserInterfaceProto& proto,
-      const std::map<std::string, std::string> context,
       base::android::ScopedJavaGlobalRef<jobject> jcontext,
       base::android::ScopedJavaGlobalRef<jobject> jdelegate,
       EventHandler* event_handler,
diff --git a/chrome/browser/android/autofill_assistant/interaction_handler_android.cc b/chrome/browser/android/autofill_assistant/interaction_handler_android.cc
index 6ea06d26..93301359 100644
--- a/chrome/browser/android/autofill_assistant/interaction_handler_android.cc
+++ b/chrome/browser/android/autofill_assistant/interaction_handler_android.cc
@@ -14,8 +14,8 @@
 #include "chrome/browser/android/autofill_assistant/generic_ui_interactions_android.h"
 #include "chrome/browser/android/autofill_assistant/view_handler_android.h"
 #include "components/autofill_assistant/browser/basic_interactions.h"
-#include "components/autofill_assistant/browser/field_formatter.h"
 #include "components/autofill_assistant/browser/generic_ui.pb.h"
+#include "components/autofill_assistant/browser/generic_ui_replace_placeholders.h"
 #include "components/autofill_assistant/browser/ui_delegate.h"
 #include "components/autofill_assistant/browser/user_model.h"
 #include "components/autofill_assistant/browser/value_util.h"
@@ -24,48 +24,9 @@
 
 namespace {
 
-// Helper RAII class that sets the execution context for callbacks and unsets
-// the context upon deletion. Simply unsetting the context after running the
-// callbacks is unsafe, as a callback may have ended the action, thus deleting
-// the context and leading to a crash.
-class SetExecutionContext {
- public:
-  SetExecutionContext(base::WeakPtr<UserModel> user_model,
-                      base::WeakPtr<ViewHandlerAndroid> view_handler,
-                      const std::map<std::string, std::string>& context)
-      : user_model_(user_model),
-        view_handler_(view_handler),
-        context_(context) {
-    if (user_model_ != nullptr) {
-      user_model_->AddIdentifierPlaceholders(context_);
-    }
-    if (view_handler_ != nullptr) {
-      view_handler_->AddIdentifierPlaceholders(context_);
-    }
-  }
-
-  ~SetExecutionContext() {
-    if (user_model_ != nullptr) {
-      user_model_->RemoveIdentifierPlaceholders(context_);
-    }
-    if (view_handler_ != nullptr) {
-      view_handler_->RemoveIdentifierPlaceholders(context_);
-    }
-  }
-
- private:
-  base::WeakPtr<UserModel> user_model_;
-  base::WeakPtr<ViewHandlerAndroid> view_handler_;
-  std::map<std::string, std::string> context_;
-};
-
-// Runs |callbacks| using the context provided by |interaction_handler| and
-// |additional_context|.
-// Note: parameters are passed by value, as their owner may go out of scope
-// before all callbacks have been processed.
-void RunWithContext(
+// Runs |callbacks|. Early-terminates if a callback causes the action to end.
+void RunCallbacks(
     std::vector<InteractionHandlerAndroid::InteractionCallback> callbacks,
-    std::map<std::string, std::string> additional_context,
     base::WeakPtr<InteractionHandlerAndroid> interaction_handler,
     base::WeakPtr<UserModel> user_model,
     base::WeakPtr<ViewHandlerAndroid> view_handler) {
@@ -73,10 +34,6 @@
     return;
   }
 
-  // Context is set via RAII to ensure that it is properly unset when done.
-  interaction_handler->AddContext(additional_context);
-  SetExecutionContext set_context(user_model, view_handler,
-                                  interaction_handler->GetContext());
   for (const auto& callback : callbacks) {
     callback.Run();
     // A callback may have caused |interaction_handler| to go out of scope.
@@ -84,15 +41,10 @@
       return;
     }
   }
-  if (interaction_handler != nullptr) {
-    interaction_handler->RemoveContext(additional_context);
-  }
 }
 
 void RunForEachLoop(
     const ForEachProto& proto,
-    const std::vector<InteractionHandlerAndroid::InteractionCallback>&
-        callbacks,
     base::WeakPtr<InteractionHandlerAndroid> interaction_handler,
     base::WeakPtr<UserModel> user_model,
     base::WeakPtr<ViewHandlerAndroid> view_handler) {
@@ -107,28 +59,37 @@
   }
 
   for (int i = 0; i < GetValueSize(*loop_value); ++i) {
-    // Temporarily add "<loop_counter> -> i" to execution context.
-    // Note: interactions may create nested UI instances. Those instances
-    // will inherit their parents' current context, which includes the
-    // placeholder for the loop variable currently being iterated.
-    RunWithContext(callbacks, /* additional_context = */
-                   {{proto.loop_counter(), base::NumberToString(i)}},
-                   interaction_handler, user_model, view_handler);
+    std::vector<InteractionHandlerAndroid::InteractionCallback> callbacks;
+    // Note: callback protos are copied and then modified. |proto| is unchanged.
+    for (auto callback_proto_copy : proto.callbacks()) {
+      ReplacePlaceholdersInCallback(
+          &callback_proto_copy,
+          {{proto.loop_counter(), base::NumberToString(i)}});
+      auto callback = interaction_handler->CreateInteractionCallbackFromProto(
+          callback_proto_copy);
+      if (!callback.has_value()) {
+        // Should never happen.
+        VLOG(1) << "Error creating ForEach interaction: failed to create "
+                   "callback";
+        return;
+      }
+      callbacks.emplace_back(*callback);
+    }
+
+    RunCallbacks(callbacks, interaction_handler, user_model, view_handler);
   }
 }
 
 }  // namespace
 
 InteractionHandlerAndroid::InteractionHandlerAndroid(
-    const std::map<std::string, std::string>& context,
     EventHandler* event_handler,
     UserModel* user_model,
     BasicInteractions* basic_interactions,
     ViewHandlerAndroid* view_handler,
     base::android::ScopedJavaGlobalRef<jobject> jcontext,
     base::android::ScopedJavaGlobalRef<jobject> jdelegate)
-    : context_(context),
-      event_handler_(event_handler),
+    : event_handler_(event_handler),
       user_model_(user_model),
       basic_interactions_(basic_interactions),
       view_handler_(view_handler),
@@ -154,20 +115,6 @@
   is_listening_ = false;
 }
 
-void InteractionHandlerAndroid::AddContext(
-    const std::map<std::string, std::string>& context) {
-  for (const auto& value : context) {
-    context_[value.first] = value.second;
-  }
-}
-
-void InteractionHandlerAndroid::RemoveContext(
-    const std::map<std::string, std::string>& context) {
-  for (const auto& value : context) {
-    context_.erase(value.first);
-  }
-}
-
 UserModel* InteractionHandlerAndroid::GetUserModel() const {
   return user_model_;
 }
@@ -215,9 +162,8 @@
 void InteractionHandlerAndroid::OnEvent(const EventHandler::EventKey& key) {
   auto it = interactions_.find(key);
   if (it != interactions_.end()) {
-    RunWithContext(it->second, /* additional_context = */ {},
-                   this->GetWeakPtr(), user_model_->GetWeakPtr(),
-                   view_handler_->GetWeakPtr());
+    RunCallbacks(it->second, this->GetWeakPtr(), user_model_->GetWeakPtr(),
+                 view_handler_->GetWeakPtr());
     // Note: it is unsafe to call any code after running callbacks, because
     // a callback may effectively delete *this.
   }
@@ -388,7 +334,8 @@
                    "loop_value_model_identifier not set";
         return base::nullopt;
       }
-      std::vector<InteractionHandlerAndroid::InteractionCallback> callbacks;
+      // Parse the callbacks here to fail view inflation in case of invalid
+      // callbacks.
       for (const auto& callback_proto : proto.for_each().callbacks()) {
         auto callback = CreateInteractionCallbackFromProto(callback_proto);
         if (!callback.has_value()) {
@@ -396,10 +343,9 @@
                      "callback";
           return base::nullopt;
         }
-        callbacks.emplace_back(*callback);
       }
       return base::Optional<InteractionCallback>(base::BindRepeating(
-          &RunForEachLoop, proto.for_each(), callbacks, GetWeakPtr(),
+          &RunForEachLoop, proto.for_each(), GetWeakPtr(),
           user_model_->GetWeakPtr(), view_handler_->GetWeakPtr()));
     }
     case CallbackProto::KIND_NOT_SET:
@@ -408,14 +354,7 @@
   }
 }
 
-void InteractionHandlerAndroid::DeleteNestedUi(const std::string& input) {
-  // Replace all placeholders in the input.
-  auto formatted_identifier = field_formatter::FormatString(input, context_);
-  if (!formatted_identifier.has_value()) {
-    VLOG(2) << "Error deleting nested UI: placeholder not found for " << input;
-    return;
-  }
-  std::string identifier = *formatted_identifier;
+void InteractionHandlerAndroid::DeleteNestedUi(const std::string& identifier) {
   auto it = nested_ui_controllers_.find(identifier);
   if (it != nested_ui_controllers_.end()) {
     nested_ui_controllers_.erase(it);
@@ -424,14 +363,7 @@
 
 const GenericUiControllerAndroid* InteractionHandlerAndroid::CreateNestedUi(
     const GenericUserInterfaceProto& proto,
-    const std::string& input) {
-  // Replace all placeholders in the input.
-  auto formatted_identifier = field_formatter::FormatString(input, context_);
-  if (!formatted_identifier.has_value()) {
-    VLOG(2) << "Error creating nested UI: placeholder not found for " << input;
-    return nullptr;
-  }
-  std::string identifier = *formatted_identifier;
+    const std::string& identifier) {
   if (nested_ui_controllers_.find(identifier) != nested_ui_controllers_.end()) {
     VLOG(2) << "Error creating nested UI: " << identifier
             << " already exixsts (did you forget to clear the previous "
@@ -439,7 +371,7 @@
     return nullptr;
   }
   auto nested_ui = GenericUiControllerAndroid::CreateFromProto(
-      proto, context_, jcontext_, jdelegate_, event_handler_, user_model_,
+      proto, jcontext_, jdelegate_, event_handler_, user_model_,
       basic_interactions_);
   const auto* nested_ui_ptr = nested_ui.get();
   if (nested_ui) {
diff --git a/chrome/browser/android/autofill_assistant/interaction_handler_android.h b/chrome/browser/android/autofill_assistant/interaction_handler_android.h
index 6ef0494..59980c6 100644
--- a/chrome/browser/android/autofill_assistant/interaction_handler_android.h
+++ b/chrome/browser/android/autofill_assistant/interaction_handler_android.h
@@ -36,7 +36,6 @@
 
   // Constructor. All dependencies must outlive this instance.
   InteractionHandlerAndroid(
-      const std::map<std::string, std::string>& context,
       EventHandler* event_handler,
       UserModel* user_model,
       BasicInteractions* basic_interactions,
@@ -50,15 +49,6 @@
   void StartListening();
   void StopListening();
 
-  // Adds |context| to the current context of this interaction handler.
-  void AddContext(const std::map<std::string, std::string>& context);
-
-  // Removes the keys in |context| from this handler's context.
-  void RemoveContext(const std::map<std::string, std::string>& context);
-
-  // Returns a copy of the current context.
-  std::map<std::string, std::string> GetContext() const { return context_; }
-
   // Access to the user model that this interaction handler is bound to.
   UserModel* GetUserModel() const;
 
@@ -82,10 +72,11 @@
   // bound to the model.
   void RunValueChangedCallbacks();
 
- private:
+  // Creates a callback from |proto|.
   base::Optional<InteractionCallback> CreateInteractionCallbackFromProto(
       const CallbackProto& proto);
 
+ private:
   // Deletes the nested ui controller associated with |identifier|.
   void DeleteNestedUi(const std::string& identifier);
 
@@ -103,11 +94,6 @@
   std::map<EventHandler::EventKey, std::vector<InteractionCallback>>
       interactions_;
 
-  // These key-value pairs specify context variables that the handler will use
-  // to resolve views and values. Nested instances will inherit their parents'
-  // context variables. Special interactions, such as ForEach, may modify the
-  // context while they are being executed.
-  std::map<std::string, std::string> context_;
   EventHandler* event_handler_ = nullptr;
   UserModel* user_model_ = nullptr;
   BasicInteractions* basic_interactions_ = nullptr;
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index 812e30f..83ee9f5 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -1774,8 +1774,7 @@
   auto jcontext =
       Java_AutofillAssistantUiController_getContext(env, java_object_);
   return GenericUiControllerAndroid::CreateFromProto(
-      proto, /* context = */ {},
-      base::android::ScopedJavaGlobalRef<jobject>(jcontext),
+      proto, base::android::ScopedJavaGlobalRef<jobject>(jcontext),
       generic_ui_delegate_.GetJavaObject(), ui_delegate_->GetEventHandler(),
       ui_delegate_->GetUserModel(), ui_delegate_->GetBasicInteractions());
 }
diff --git a/chrome/browser/android/autofill_assistant/view_handler_android.cc b/chrome/browser/android/autofill_assistant/view_handler_android.cc
index 982c71e0..d9bfcb4 100644
--- a/chrome/browser/android/autofill_assistant/view_handler_android.cc
+++ b/chrome/browser/android/autofill_assistant/view_handler_android.cc
@@ -3,13 +3,10 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/android/autofill_assistant/view_handler_android.h"
-#include "components/autofill_assistant/browser/field_formatter.h"
 
 namespace autofill_assistant {
 
-ViewHandlerAndroid::ViewHandlerAndroid(
-    const std::map<std::string, std::string>& identifier_placeholders)
-    : identifier_placeholders_(identifier_placeholders) {}
+ViewHandlerAndroid::ViewHandlerAndroid() = default;
 ViewHandlerAndroid::~ViewHandlerAndroid() = default;
 
 base::WeakPtr<ViewHandlerAndroid> ViewHandlerAndroid::GetWeakPtr() {
@@ -17,14 +14,7 @@
 }
 
 base::Optional<base::android::ScopedJavaGlobalRef<jobject>>
-ViewHandlerAndroid::GetView(const std::string& input) const {
-  // Replace all placeholders in the input.
-  auto formatted_identifier =
-      field_formatter::FormatString(input, identifier_placeholders_);
-  if (!formatted_identifier.has_value()) {
-    return base::nullopt;
-  }
-  std::string view_identifier = *formatted_identifier;
+ViewHandlerAndroid::GetView(const std::string& view_identifier) const {
   auto it = views_.find(view_identifier);
   if (it == views_.end()) {
     return base::nullopt;
@@ -34,31 +24,10 @@
 
 // Adds a view to the set of managed views.
 void ViewHandlerAndroid::AddView(
-    const std::string& input,
+    const std::string& view_identifier,
     base::android::ScopedJavaGlobalRef<jobject> jview) {
-  // Replace all placeholders in the input.
-  auto formatted_identifier =
-      field_formatter::FormatString(input, identifier_placeholders_);
-  if (!formatted_identifier.has_value()) {
-    return;
-  }
-  std::string view_identifier = *formatted_identifier;
   DCHECK(views_.find(view_identifier) == views_.end());
   views_.emplace(view_identifier, jview);
 }
 
-void ViewHandlerAndroid::AddIdentifierPlaceholders(
-    const std::map<std::string, std::string> placeholders) {
-  for (const auto& placeholder : placeholders) {
-    identifier_placeholders_[placeholder.first] = placeholder.second;
-  }
-}
-
-void ViewHandlerAndroid::RemoveIdentifierPlaceholders(
-    const std::map<std::string, std::string> placeholders) {
-  for (const auto& placeholder : placeholders) {
-    identifier_placeholders_.erase(placeholder.first);
-  }
-}
-
 }  // namespace autofill_assistant
diff --git a/chrome/browser/android/autofill_assistant/view_handler_android.h b/chrome/browser/android/autofill_assistant/view_handler_android.h
index 8433e87..1e67234 100644
--- a/chrome/browser/android/autofill_assistant/view_handler_android.h
+++ b/chrome/browser/android/autofill_assistant/view_handler_android.h
@@ -18,8 +18,7 @@
 // Manages a map of view-identifier -> android view instances.
 class ViewHandlerAndroid {
  public:
-  explicit ViewHandlerAndroid(
-      const std::map<std::string, std::string>& identifier_placeholders);
+  ViewHandlerAndroid();
   ~ViewHandlerAndroid();
   ViewHandlerAndroid(const ViewHandlerAndroid&) = delete;
   ViewHandlerAndroid& operator=(const ViewHandlerAndroid&) = delete;
@@ -28,8 +27,6 @@
 
   // Returns the view associated with |view_identifier| or base::nullopt if
   // there is no such view.
-  // -Placeholders in |view_identifier| of the form ${key} are automatically
-  // replaced (see |AddIdentifierPlaceholders|).
   base::Optional<base::android::ScopedJavaGlobalRef<jobject>> GetView(
       const std::string& view_identifier) const;
 
@@ -37,20 +34,8 @@
   void AddView(const std::string& view_identifier,
                base::android::ScopedJavaGlobalRef<jobject> jview);
 
-  // Adds a set of placeholders (overwrite if necessary). When looking up views
-  // by identifier, all occurrences of ${key} are automatically replaced by
-  // their value. Example: the current set of placeholders contains "i" -> "1".
-  // Looking up the view "view_${i}" will now actually lookup "view_1".
-  void AddIdentifierPlaceholders(
-      const std::map<std::string, std::string> placeholders);
-
-  // Removes a set of placeholders.
-  void RemoveIdentifierPlaceholders(
-      const std::map<std::string, std::string> placeholders);
-
  private:
   std::map<std::string, base::android::ScopedJavaGlobalRef<jobject>> views_;
-  std::map<std::string, std::string> identifier_placeholders_;
   base::WeakPtrFactory<ViewHandlerAndroid> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc
index d641b61..4e974eb 100644
--- a/chrome/browser/android/provider/chrome_browser_provider.cc
+++ b/chrome/browser/android/provider/chrome_browser_provider.cc
@@ -381,12 +381,12 @@
       : HistoryProviderTask(service, cancelable_tracker) {}
 
   history::URLID Run(const history::HistoryAndBookmarkRow& row) {
-    RunAsyncRequestOnUIThreadBlocking(
-        base::BindOnce(&AndroidHistoryProviderService::InsertHistoryAndBookmark,
-                       base::Unretained(service()), row,
-                       base::Bind(&AddBookmarkFromAPITask::OnBookmarkInserted,
-                                  base::Unretained(this)),
-                       cancelable_tracker()));
+    RunAsyncRequestOnUIThreadBlocking(base::BindOnce(
+        &AndroidHistoryProviderService::InsertHistoryAndBookmark,
+        base::Unretained(service()), row,
+        base::BindOnce(&AddBookmarkFromAPITask::OnBookmarkInserted,
+                       base::Unretained(this)),
+        cancelable_tracker()));
     return result_;
   }
 
@@ -419,8 +419,8 @@
         &AndroidHistoryProviderService::QueryHistoryAndBookmarks,
         base::Unretained(service()), projections, selection, selection_args,
         sort_order,
-        base::Bind(&QueryBookmarksFromAPITask::OnBookmarksQueried,
-                   base::Unretained(this)),
+        base::BindOnce(&QueryBookmarksFromAPITask::OnBookmarksQueried,
+                       base::Unretained(this)),
         cancelable_tracker()));
     return result_;
   }
@@ -449,8 +449,8 @@
     RunAsyncRequestOnUIThreadBlocking(base::BindOnce(
         &AndroidHistoryProviderService::UpdateHistoryAndBookmarks,
         base::Unretained(service()), row, selection, selection_args,
-        base::Bind(&UpdateBookmarksFromAPITask::OnBookmarksUpdated,
-                   base::Unretained(this)),
+        base::BindOnce(&UpdateBookmarksFromAPITask::OnBookmarksUpdated,
+                       base::Unretained(this)),
         cancelable_tracker()));
     return result_;
   }
@@ -478,8 +478,8 @@
     RunAsyncRequestOnUIThreadBlocking(base::BindOnce(
         &AndroidHistoryProviderService::DeleteHistoryAndBookmarks,
         base::Unretained(service()), selection, selection_args,
-        base::Bind(&RemoveBookmarksFromAPITask::OnBookmarksRemoved,
-                   base::Unretained(this)),
+        base::BindOnce(&RemoveBookmarksFromAPITask::OnBookmarksRemoved,
+                       base::Unretained(this)),
         cancelable_tracker()));
     return result_;
   }
@@ -504,12 +504,12 @@
 
   int Run(const std::string& selection,
           const std::vector<base::string16>& selection_args) {
-    RunAsyncRequestOnUIThreadBlocking(
-        base::BindOnce(&AndroidHistoryProviderService::DeleteHistory,
-                       base::Unretained(service()), selection, selection_args,
-                       base::Bind(&RemoveHistoryFromAPITask::OnHistoryRemoved,
-                                  base::Unretained(this)),
-                       cancelable_tracker()));
+    RunAsyncRequestOnUIThreadBlocking(base::BindOnce(
+        &AndroidHistoryProviderService::DeleteHistory,
+        base::Unretained(service()), selection, selection_args,
+        base::BindOnce(&RemoveHistoryFromAPITask::OnHistoryRemoved,
+                       base::Unretained(this)),
+        cancelable_tracker()));
     return result_;
   }
 
@@ -584,8 +584,8 @@
     BuildSearchRow(&internal_row);
     service()->InsertSearchTerm(
         internal_row,
-        base::Bind(&AddSearchTermFromAPITask::OnSearchTermInserted,
-                   base::Unretained(this)),
+        base::BindOnce(&AddSearchTermFromAPITask::OnSearchTermInserted,
+                       base::Unretained(this)),
         cancelable_tracker());
   }
 
@@ -618,8 +618,8 @@
         &AndroidHistoryProviderService::QuerySearchTerms,
         base::Unretained(service()), projections, selection, selection_args,
         sort_order,
-        base::Bind(&QuerySearchTermsFromAPITask::OnSearchTermsQueried,
-                   base::Unretained(this)),
+        base::BindOnce(&QuerySearchTermsFromAPITask::OnSearchTermsQueried,
+                       base::Unretained(this)),
         cancelable_tracker()));
     return result_;
   }
@@ -662,11 +662,9 @@
     history::SearchRow internal_row = row;
     BuildSearchRow(&internal_row);
     service()->UpdateSearchTerms(
-        internal_row,
-        selection,
-        selection_args,
-        base::Bind(&UpdateSearchTermsFromAPITask::OnSearchTermsUpdated,
-                   base::Unretained(this)),
+        internal_row, selection, selection_args,
+        base::BindOnce(&UpdateSearchTermsFromAPITask::OnSearchTermsUpdated,
+                       base::Unretained(this)),
         cancelable_tracker());
   }
 
@@ -693,8 +691,8 @@
     RunAsyncRequestOnUIThreadBlocking(base::BindOnce(
         &AndroidHistoryProviderService::DeleteSearchTerms,
         base::Unretained(service()), selection, selection_args,
-        base::Bind(&RemoveSearchTermsFromAPITask::OnSearchTermsDeleted,
-                   base::Unretained(this)),
+        base::BindOnce(&RemoveSearchTermsFromAPITask::OnSearchTermsDeleted,
+                       base::Unretained(this)),
         cancelable_tracker()));
     return result_;
   }
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index d3e7681..cd15aed 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -816,6 +816,12 @@
   NOTIMPLEMENTED();
 }
 
+void BackgroundFetchDelegateImpl::ChangeSchedule(
+    const offline_items_collection::ContentId& id,
+    base::Optional<offline_items_collection::OfflineItemSchedule> schedule) {
+  NOTIMPLEMENTED();
+}
+
 void BackgroundFetchDelegateImpl::AddObserver(Observer* observer) {
   DCHECK(!observers_.count(observer));
 
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
index b7c4fae..d9baa95 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
@@ -111,6 +111,10 @@
   void RenameItem(const offline_items_collection::ContentId& id,
                   const std::string& name,
                   RenameCallback callback) override;
+  void ChangeSchedule(
+      const offline_items_collection::ContentId& id,
+      base::Optional<offline_items_collection::OfflineItemSchedule> schedule)
+      override;
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
 
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 78b0449..62c66d2 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -505,9 +505,9 @@
 }
 
 ChromeBrowserMainParts::~ChromeBrowserMainParts() {
-  for (int i = static_cast<int>(chrome_extra_parts_.size())-1; i >= 0; --i)
-    delete chrome_extra_parts_[i];
-  chrome_extra_parts_.clear();
+  // Delete parts in the reverse of the order they were added.
+  while (!chrome_extra_parts_.empty())
+    chrome_extra_parts_.pop_back();
 }
 
 void ChromeBrowserMainParts::SetupMetrics() {
@@ -1790,8 +1790,9 @@
 
 // Public members:
 
-void ChromeBrowserMainParts::AddParts(ChromeBrowserMainExtraParts* parts) {
-  chrome_extra_parts_.push_back(parts);
+void ChromeBrowserMainParts::AddParts(
+    std::unique_ptr<ChromeBrowserMainExtraParts> parts) {
+  chrome_extra_parts_.push_back(std::move(parts));
 }
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h
index 308d3d5..294caf8 100644
--- a/chrome/browser/chrome_browser_main.h
+++ b/chrome/browser/chrome_browser_main.h
@@ -49,7 +49,7 @@
   ~ChromeBrowserMainParts() override;
 
   // Add additional ChromeBrowserMainExtraParts.
-  virtual void AddParts(ChromeBrowserMainExtraParts* parts);
+  void AddParts(std::unique_ptr<ChromeBrowserMainExtraParts> parts);
 
 #if !defined(OS_ANDROID)
   // Returns the RunLoop that would be run by MainMessageLoopRun. This is used
@@ -153,7 +153,7 @@
 
   // Vector of additional ChromeBrowserMainExtraParts.
   // Parts are deleted in the inverse order they are added.
-  std::vector<ChromeBrowserMainExtraParts*> chrome_extra_parts_;
+  std::vector<std::unique_ptr<ChromeBrowserMainExtraParts>> chrome_extra_parts_;
 
   // The system monitor instance, used by some subsystems to collect the system
   // metrics they need.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 89ad0f50..c7c26eb 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1355,36 +1355,39 @@
     // which they are added.
 #if defined(TOOLKIT_VIEWS)
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsViewsLinux());
+  main_parts->AddParts(
+      std::make_unique<ChromeBrowserMainExtraPartsViewsLinux>());
 #else
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsViews());
+  main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsViews>());
 #endif
 #endif
 
 #if defined(OS_CHROMEOS)
   // TODO(jamescook): Combine with ChromeBrowserMainPartsChromeos.
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsAsh());
+  main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsAsh>());
 #endif
 
 #if BUILDFLAG(IS_LACROS)
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsLacros());
+  main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsLacros>());
 #endif
 
 #if defined(USE_X11) || defined(USE_OZONE)
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsOzone());
+  main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsOzone>());
 #endif
 
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsPerformanceManager);
+  main_parts->AddParts(
+      std::make_unique<ChromeBrowserMainExtraPartsPerformanceManager>());
 
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsProfiling);
+  main_parts->AddParts(
+      std::make_unique<ChromeBrowserMainExtraPartsProfiling>());
 
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsMemory);
+  main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsMemory>());
 
   chrome::AddMetricsExtraParts(main_parts.get());
 
   // Always add ChromeBrowserMainExtraPartsGpu last to make sure
   // GpuDataManager initialization could pick up about:flags settings.
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsGpu);
+  main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsGpu>());
 
   return main_parts;
 }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 397a78e..9a9c154 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1758,6 +1758,8 @@
     "login/ui/views/user_board_view.h",
     "login/ui/web_contents_forced_title.cc",
     "login/ui/web_contents_forced_title.h",
+    "login/ui/webui_accelerator_mapping.cc",
+    "login/ui/webui_accelerator_mapping.h",
     "login/ui/webui_login_view.cc",
     "login/ui/webui_login_view.h",
     "login/user_board_view_mojo.cc",
diff --git a/chrome/browser/chromeos/arc/arc_support_host.cc b/chrome/browser/chromeos/arc/arc_support_host.cc
index 63a4d1bd..723dd43d 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.cc
+++ b/chrome/browser/chromeos/arc/arc_support_host.cc
@@ -189,7 +189,7 @@
 
 ArcSupportHost::ArcSupportHost(Profile* profile)
     : profile_(profile),
-      request_open_app_callback_(base::Bind(&RequestOpenApp)) {
+      request_open_app_callback_(base::BindRepeating(&RequestOpenApp)) {
   DCHECK(profile_);
 }
 
diff --git a/chrome/browser/chromeos/arc/arc_support_host.h b/chrome/browser/chromeos/arc/arc_support_host.h
index ccf69f31..dac4236 100644
--- a/chrome/browser/chromeos/arc/arc_support_host.h
+++ b/chrome/browser/chromeos/arc/arc_support_host.h
@@ -104,7 +104,8 @@
     virtual ~ErrorDelegate() = default;
   };
 
-  using RequestOpenAppCallback = base::Callback<void(Profile* profile)>;
+  using RequestOpenAppCallback =
+      base::RepeatingCallback<void(Profile* profile)>;
 
   explicit ArcSupportHost(Profile* profile);
   ~ArcSupportHost() override;
diff --git a/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
index 91d87feb..b2631c8e 100644
--- a/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
+++ b/chrome/browser/chromeos/arc/extensions/fake_arc_support.cc
@@ -35,8 +35,8 @@
 FakeArcSupport::FakeArcSupport(ArcSupportHost* support_host)
     : support_host_(support_host) {
   DCHECK(support_host_);
-  support_host_->SetRequestOpenAppCallbackForTesting(
-      base::Bind(&FakeArcSupport::Open, weak_ptr_factory_.GetWeakPtr()));
+  support_host_->SetRequestOpenAppCallbackForTesting(base::BindRepeating(
+      &FakeArcSupport::Open, weak_ptr_factory_.GetWeakPtr()));
 }
 
 FakeArcSupport::~FakeArcSupport() {
diff --git a/chrome/browser/chromeos/lacros/OWNERS b/chrome/browser/chromeos/lacros/OWNERS
new file mode 100644
index 0000000..71cc0b0
--- /dev/null
+++ b/chrome/browser/chromeos/lacros/OWNERS
@@ -0,0 +1 @@
+file://chromeos/LACROS_OWNERS
diff --git a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
index 4022d57..db9d2af 100644
--- a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
@@ -908,7 +908,8 @@
   void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
     MixinBasedInProcessBrowserTest::CreatedBrowserMainParts(parts);
     static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
-        new NativeWindowVisibilityBrowserMainExtraParts(observer_.get()));
+        std::make_unique<NativeWindowVisibilityBrowserMainExtraParts>(
+            observer_.get()));
   }
 
   void TearDownOnMainThread() override {
diff --git a/chrome/browser/chromeos/login/test/local_state_mixin.cc b/chrome/browser/chromeos/login/test/local_state_mixin.cc
index ce9fb2cd..ce78cdc 100644
--- a/chrome/browser/chromeos/login/test/local_state_mixin.cc
+++ b/chrome/browser/chromeos/login/test/local_state_mixin.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chromeos/login/test/local_state_mixin.h"
 
+#include <memory>
+
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_browser_main.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
@@ -37,7 +39,7 @@
     content::BrowserMainParts* browser_main_parts) {
   // |browser_main_parts| take ownership of TestUserRegistrationMainExtra.
   static_cast<ChromeBrowserMainParts*>(browser_main_parts)
-      ->AddParts(new TestMainExtraPart(delegate_));
+      ->AddParts(std::make_unique<TestMainExtraPart>(delegate_));
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
index 8e0d261..fc5c3d4 100644
--- a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
+++ b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.cc
@@ -8,12 +8,14 @@
 #include <utility>
 #include <vector>
 
+#include "ash/public/cpp/login_accelerators.h"
 #include "ash/public/cpp/login_screen.h"
 #include "ash/public/cpp/login_screen_model.h"
 #include "ash/public/cpp/shelf_config.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host_mojo.h"
 #include "chrome/browser/chromeos/login/ui/oobe_dialog_size_utils.h"
+#include "chrome/browser/chromeos/login/ui/webui_accelerator_mapping.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
@@ -41,9 +43,6 @@
 namespace {
 
 constexpr char kGaiaURL[] = "chrome://oobe/gaia-signin";
-constexpr char kAppLaunchBailout[] = "app_launch_bailout";
-constexpr char kAppLaunchNetworkConfig[] = "app_launch_network_config";
-constexpr char kCancel[] = "cancel";
 
 CoreOobeView::DialogPaddingMode ConvertDialogPaddingMode(
     OobeDialogPaddingMode padding) {
@@ -304,12 +303,18 @@
     : controller_(controller) {
   keyboard_observer_.Add(ChromeKeyboardControllerClient::Get());
 
-  accel_map_[ui::Accelerator(
-      ui::VKEY_S, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] = kAppLaunchBailout;
-  accel_map_[ui::Accelerator(ui::VKEY_N,
-                             ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
-      kAppLaunchNetworkConfig;
-  accel_map_[ui::Accelerator(ui::VKEY_ESCAPE, 0)] = kCancel;
+  for (size_t i = 0; i < ash::kLoginAcceleratorDataLength; ++i) {
+    if (ash::kLoginAcceleratorData[i].global)
+      continue;
+    if (!(ash::kLoginAcceleratorData[i].scope &
+          (ash::kScopeLogin | ash::kScopeLock))) {
+      continue;
+    }
+
+    accel_map_[ui::Accelerator(ash::kLoginAcceleratorData[i].keycode,
+                               ash::kLoginAcceleratorData[i].modifiers)] =
+        ash::kLoginAcceleratorData[i].action;
+  }
 
   DCHECK(!dialog_view_ && !widget_);
   // Life cycle of |dialog_view_| is managed by the widget:
@@ -491,7 +496,7 @@
   if (entry == accel_map_.end())
     return false;
 
-  GetOobeUI()->ForwardAccelerator(entry->second);
+  GetOobeUI()->ForwardAccelerator(MapToWebUIAccelerator(entry->second));
   return true;
 }
 
diff --git a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h
index 59a05a2..0a5d715 100644
--- a/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h
+++ b/chrome/browser/chromeos/login/ui/oobe_ui_dialog_delegate.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "ash/public/cpp/login_accelerators.h"
 #include "ash/public/cpp/login_types.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -131,7 +132,7 @@
   ScopedObserver<CaptivePortalWindowProxy, CaptivePortalWindowProxy::Observer>
       captive_portal_observer_{this};
 
-  std::map<ui::Accelerator, std::string> accel_map_;
+  std::map<ui::Accelerator, ash::LoginAcceleratorAction> accel_map_;
   ash::OobeDialogState state_ = ash::OobeDialogState::HIDDEN;
 
   // Whether the captive portal screen should be shown the next time the Gaia
diff --git a/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.cc b/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.cc
new file mode 100644
index 0000000..216dd1d
--- /dev/null
+++ b/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.cc
@@ -0,0 +1,61 @@
+// Copyright 2020 The Chromium 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/login/ui/webui_accelerator_mapping.h"
+
+#include <string>
+
+#include "ash/public/cpp/login_accelerators.h"
+
+namespace chromeos {
+
+namespace {
+
+// These strings must be kept in sync with handleAccelerator()
+// in display_manager.js.
+const char kAccelNameCancel[] = "cancel";
+const char kAccelNameEnableDebugging[] = "debugging";
+const char kAccelNameEnrollment[] = "enrollment";
+const char kAccelNameKioskEnable[] = "kiosk_enable";
+const char kAccelNameVersion[] = "version";
+const char kAccelNameReset[] = "reset";
+const char kAccelNameDeviceRequisition[] = "device_requisition";
+const char kAccelNameDeviceRequisitionRemora[] = "device_requisition_remora";
+const char kAccelNameAppLaunchBailout[] = "app_launch_bailout";
+const char kAccelNameAppLaunchNetworkConfig[] = "app_launch_network_config";
+const char kAccelNameDemoMode[] = "demo_mode";
+const char kAccelSendFeedback[] = "send_feedback";
+
+}  // namespace
+
+std::string MapToWebUIAccelerator(ash::LoginAcceleratorAction action) {
+  switch (action) {
+    case ash::LoginAcceleratorAction::kToggleSystemInfo:
+      return kAccelNameVersion;
+    case ash::LoginAcceleratorAction::kShowFeedback:
+      return kAccelSendFeedback;
+    case ash::LoginAcceleratorAction::kShowResetScreen:
+      return kAccelNameReset;
+    case ash::LoginAcceleratorAction::kAppLaunchBailout:
+      return kAccelNameAppLaunchBailout;
+    case ash::LoginAcceleratorAction::kAppLaunchNetworkConfig:
+      return kAccelNameAppLaunchNetworkConfig;
+    case ash::LoginAcceleratorAction::kCancelScreenAction:
+      return kAccelNameCancel;
+    case ash::LoginAcceleratorAction::kStartEnrollment:
+      return kAccelNameEnrollment;
+    case ash::LoginAcceleratorAction::kEnableConsumerKiosk:
+      return kAccelNameKioskEnable;
+    case ash::LoginAcceleratorAction::kEnableDebugging:
+      return kAccelNameEnableDebugging;
+    case ash::LoginAcceleratorAction::kEditDeviceRequisition:
+      return kAccelNameDeviceRequisition;
+    case ash::LoginAcceleratorAction::kDeviceRequisitionRemora:
+      return kAccelNameDeviceRequisitionRemora;
+    case ash::LoginAcceleratorAction::kStartDemoMode:
+      return kAccelNameDemoMode;
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.h b/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.h
new file mode 100644
index 0000000..a06dbf42
--- /dev/null
+++ b/chrome/browser/chromeos/login/ui/webui_accelerator_mapping.h
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium 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_LOGIN_UI_WEBUI_ACCELERATOR_MAPPING_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_UI_WEBUI_ACCELERATOR_MAPPING_H_
+
+#include <string>
+
+#include "ash/public/cpp/login_accelerators.h"
+
+namespace chromeos {
+
+std::string MapToWebUIAccelerator(ash::LoginAcceleratorAction action);
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_UI_WEBUI_ACCELERATOR_MAPPING_H_
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc
index 7f7a03c..758d0f9 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "ash/public/cpp/ash_features.h"
+#include "ash/public/cpp/login_accelerators.h"
 #include "ash/public/cpp/login_screen.h"
 #include "base/bind.h"
 #include "base/callback.h"
@@ -22,6 +23,7 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host_webui.h"
 #include "chrome/browser/chromeos/login/ui/login_display_webui.h"
 #include "chrome/browser/chromeos/login/ui/web_contents_forced_title.h"
+#include "chrome/browser/chromeos/login/ui/webui_accelerator_mapping.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
@@ -64,22 +66,6 @@
 
 namespace {
 
-// These strings must be kept in sync with handleAccelerator()
-// in display_manager.js.
-const char kAccelNameCancel[] = "cancel";
-const char kAccelNameEnableDebugging[] = "debugging";
-const char kAccelNameEnrollment[] = "enrollment";
-const char kAccelNameKioskEnable[] = "kiosk_enable";
-const char kAccelNameVersion[] = "version";
-const char kAccelNameReset[] = "reset";
-const char kAccelNameDeviceRequisition[] = "device_requisition";
-const char kAccelNameDeviceRequisitionRemora[] = "device_requisition_remora";
-const char kAccelNameAppLaunchBailout[] = "app_launch_bailout";
-const char kAccelNameAppLaunchNetworkConfig[] = "app_launch_network_config";
-const char kAccelNameBootstrappingSlave[] = "bootstrapping_slave";
-const char kAccelNameDemoMode[] = "demo_mode";
-const char kAccelSendFeedback[] = "send_feedback";
-
 // A class to change arrow key traversal behavior when it's alive.
 class ScopedArrowKeyTraversal {
  public:
@@ -120,48 +106,19 @@
   registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
                  content::NotificationService::AllSources());
 
-  accel_map_[ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)] = kAccelNameCancel;
-  accel_map_[ui::Accelerator(ui::VKEY_E,
-                             ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
-      kAccelNameEnrollment;
-  if (KioskAppManager::IsConsumerKioskEnabled()) {
-    accel_map_[ui::Accelerator(ui::VKEY_K,
-                               ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
-        kAccelNameKioskEnable;
+  for (size_t i = 0; i < ash::kLoginAcceleratorDataLength; ++i) {
+    ui::Accelerator accelerator(ash::kLoginAcceleratorData[i].keycode,
+                                ash::kLoginAcceleratorData[i].modifiers);
+    // Show reset conflicts with rotate screen when --ash-dev-shortcuts is
+    // passed. Favor --ash-dev-shortcuts since that is explicitly added.
+    if (ash::kLoginAcceleratorData[i].action ==
+            ash::LoginAcceleratorAction::kEnableConsumerKiosk &&
+        !KioskAppManager::IsConsumerKioskEnabled()) {
+      continue;
+    }
+
+    accel_map_[accelerator] = ash::kLoginAcceleratorData[i].action;
   }
-  accel_map_[ui::Accelerator(ui::VKEY_V, ui::EF_ALT_DOWN)] =
-      kAccelNameVersion;
-  accel_map_[ui::Accelerator(
-      ui::VKEY_R, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
-      kAccelNameReset;
-  accel_map_[ui::Accelerator(ui::VKEY_X,
-      ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
-      kAccelNameEnableDebugging;
-
-  accel_map_[ui::Accelerator(
-      ui::VKEY_D, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
-      kAccelNameDeviceRequisition;
-  accel_map_[
-      ui::Accelerator(ui::VKEY_H, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
-      kAccelNameDeviceRequisitionRemora;
-
-  accel_map_[ui::Accelerator(ui::VKEY_S,
-                             ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
-      kAccelNameAppLaunchBailout;
-
-  accel_map_[ui::Accelerator(ui::VKEY_N,
-                             ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
-      kAccelNameAppLaunchNetworkConfig;
-
-  accel_map_[ui::Accelerator(
-      ui::VKEY_S, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
-      kAccelNameBootstrappingSlave;
-
-  accel_map_[ui::Accelerator(
-      ui::VKEY_D, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] = kAccelNameDemoMode;
-
-  accel_map_[ui::Accelerator(ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)] =
-      kAccelSendFeedback;
 
   for (AccelMap::iterator i(accel_map_.begin()); i != accel_map_.end(); ++i) {
     AddAccelerator(i->first);
@@ -286,7 +243,7 @@
 
   content::WebUI* web_ui = GetWebUI();
   if (web_ui) {
-    base::Value accel_name(entry->second);
+    base::Value accel_name(MapToWebUIAccelerator(entry->second));
     web_ui->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
                                          accel_name);
   }
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.h b/chrome/browser/chromeos/login/ui/webui_login_view.h
index ec85535..8adc46d8 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.h
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <string>
 
+#include "ash/public/cpp/login_accelerators.h"
 #include "ash/public/cpp/system_tray_focus_observer.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -131,7 +132,7 @@
 
  private:
   // Map type for the accelerator-to-identifier map.
-  typedef std::map<ui::Accelerator, std::string> AccelMap;
+  typedef std::map<ui::Accelerator, ash::LoginAcceleratorAction> AccelMap;
 
   // ChromeKeyboardControllerClient::Observer:
   void OnKeyboardVisibilityChanged(bool visible) override;
diff --git a/chrome/browser/chromeos/scheduler_configuration_manager.cc b/chrome/browser/chromeos/scheduler_configuration_manager.cc
index ac1cdc6..fdc1c1ef 100644
--- a/chrome/browser/chromeos/scheduler_configuration_manager.cc
+++ b/chrome/browser/chromeos/scheduler_configuration_manager.cc
@@ -91,10 +91,8 @@
     // Next, if Finch isn't set, see if the command line passed in a default.
     config_name = cmdline_default;
   } else {
-    // If nothing is found, default to core isolation scheduling. Note that
-    // only some kernels support core isolation. debugd checks for support and
-    // reverts to conservative if core isolation is unavailable.
-    config_name = debugd::scheduler_configuration::kCoreIsolationScheduler;
+    // If nothing is found, default to conservative.
+    config_name = debugd::scheduler_configuration::kConservativeScheduler;
   }
 
   // NB: Also send an update when the config gets reset to let the system pick
diff --git a/chrome/browser/chromeos/scheduler_configuration_manager_unittest.cc b/chrome/browser/chromeos/scheduler_configuration_manager_unittest.cc
index 08e4774..0e8a4da5 100644
--- a/chrome/browser/chromeos/scheduler_configuration_manager_unittest.cc
+++ b/chrome/browser/chromeos/scheduler_configuration_manager_unittest.cc
@@ -117,7 +117,7 @@
   manager.AddObserver(this);
 
   task_environment_.RunUntilIdle();
-  EXPECT_EQ(debugd::scheduler_configuration::kCoreIsolationScheduler,
+  EXPECT_EQ(debugd::scheduler_configuration::kConservativeScheduler,
             debug_daemon_client_.scheduler_configuration_name());
   EXPECT_EQ(1u, configuration_set_count_);
 
@@ -144,7 +144,7 @@
   // Dropping the policy as well reverts to the default configuration.
   local_state_.RemoveManagedPref(prefs::kSchedulerConfiguration);
   task_environment_.RunUntilIdle();
-  EXPECT_EQ(debugd::scheduler_configuration::kCoreIsolationScheduler,
+  EXPECT_EQ(debugd::scheduler_configuration::kConservativeScheduler,
             debug_daemon_client_.scheduler_configuration_name());
   EXPECT_EQ(5u, configuration_set_count_);
 }
diff --git a/chrome/browser/content_index/content_index_provider_impl.cc b/chrome/browser/content_index/content_index_provider_impl.cc
index 46bc2953..31e4567 100644
--- a/chrome/browser/content_index/content_index_provider_impl.cc
+++ b/chrome/browser/content_index/content_index_provider_impl.cc
@@ -41,7 +41,7 @@
 using offline_items_collection::LaunchLocation;
 using offline_items_collection::OfflineItem;
 using offline_items_collection::OfflineItemFilter;
-
+using offline_items_collection::OfflineItemSchedule;
 
 namespace {
 
@@ -396,6 +396,12 @@
   NOTREACHED();
 }
 
+void ContentIndexProviderImpl::ChangeSchedule(
+    const ContentId& id,
+    base::Optional<OfflineItemSchedule> schedule) {
+  NOTREACHED();
+}
+
 void ContentIndexProviderImpl::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
 }
diff --git a/chrome/browser/content_index/content_index_provider_impl.h b/chrome/browser/content_index/content_index_provider_impl.h
index 97daf617..f540bcb4 100644
--- a/chrome/browser/content_index/content_index_provider_impl.h
+++ b/chrome/browser/content_index/content_index_provider_impl.h
@@ -66,6 +66,10 @@
   void RenameItem(const offline_items_collection::ContentId& id,
                   const std::string& name,
                   RenameCallback callback) override;
+  void ChangeSchedule(
+      const offline_items_collection::ContentId& id,
+      base::Optional<offline_items_collection::OfflineItemSchedule> schedule)
+      override;
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
 
diff --git a/chrome/browser/downgrade/user_data_downgrade_browsertest.cc b/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
index f33f05a..43de243 100644
--- a/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
+++ b/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
@@ -169,7 +169,8 @@
       // Ensure that the after-startup task to delete User Data has a chance to
       // run.
       static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
-          new RunAllPendingTasksPostMainMessageLoopRunExtraParts());
+          std::make_unique<
+              RunAllPendingTasksPostMainMessageLoopRunExtraParts>());
     }
   }
 
diff --git a/chrome/browser/download/android/download_manager_service.cc b/chrome/browser/download/android/download_manager_service.cc
index 0d47880..8120eabe 100644
--- a/chrome/browser/download/android/download_manager_service.cc
+++ b/chrome/browser/download/android/download_manager_service.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -741,6 +742,29 @@
   item->Rename(base::FilePath(target_name), std::move(callback));
 }
 
+void DownloadManagerService::ChangeSchedule(JNIEnv* env,
+                                            const JavaParamRef<jobject>& obj,
+                                            const JavaParamRef<jstring>& id,
+                                            jboolean only_on_wifi,
+                                            jlong start_time,
+                                            jboolean is_off_the_record) {
+  std::string download_guid = ConvertJavaStringToUTF8(id);
+  download::DownloadItem* item = GetDownload(download_guid, is_off_the_record);
+  if (!item)
+    return;
+
+  base::Optional<DownloadSchedule> download_schedule;
+  if (only_on_wifi) {
+    download_schedule = base::make_optional<DownloadSchedule>(
+        true /*only_on_wifi*/, base::nullopt);
+  } else if (start_time > 0) {
+    download_schedule = base::make_optional<DownloadSchedule>(
+        false /*only_on_wifi*/, base::Time::FromJavaTime(start_time));
+  }
+
+  item->OnDownloadScheduleChanged(std::move(download_schedule));
+}
+
 void DownloadManagerService::CreateInterruptedDownloadForTest(
     JNIEnv* env,
     jobject obj,
diff --git a/chrome/browser/download/android/download_manager_service.h b/chrome/browser/download/android/download_manager_service.h
index edc0a9f5..07dc84e 100644
--- a/chrome/browser/download/android/download_manager_service.h
+++ b/chrome/browser/download/android/download_manager_service.h
@@ -117,6 +117,15 @@
                       const JavaParamRef<jobject>& callback,
                       bool is_off_the_record);
 
+  // Called to change the download schedule of a download item that has GUID
+  // equal to |id|.
+  void ChangeSchedule(JNIEnv* env,
+                      const JavaParamRef<jobject>& obj,
+                      const JavaParamRef<jstring>& id,
+                      jboolean only_on_wifi,
+                      jlong start_time,
+                      jboolean is_off_the_record);
+
   // Returns whether or not the given download can be opened by the browser.
   bool IsDownloadOpenableInBrowser(JNIEnv* env,
                                    jobject obj,
diff --git a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProvider.java b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProvider.java
index a29396cd..c1b1a47 100644
--- a/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProvider.java
+++ b/chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/home/LegacyDownloadProvider.java
@@ -8,6 +8,7 @@
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemSchedule;
 import org.chromium.components.offline_items_collection.ShareCallback;
 import org.chromium.components.offline_items_collection.VisualsCallback;
 
@@ -58,4 +59,7 @@
 
     /** @see OfflineContentProvider#renameItem(ContentId, String, Callback)*/
     void renameItem(OfflineItem item, String name, Callback</*RenameResult*/ Integer> callback);
-}
\ No newline at end of file
+
+    /** @see OfflineContentProvider#changeSchedule(ContentId, OfflineItemSchedule) */
+    void changeSchedule(final OfflineItem item, final OfflineItemSchedule schedule);
+}
diff --git a/chrome/browser/download/download_offline_content_provider.cc b/chrome/browser/download/download_offline_content_provider.cc
index 1f235413..4772ab0 100644
--- a/chrome/browser/download/download_offline_content_provider.cc
+++ b/chrome/browser/download/download_offline_content_provider.cc
@@ -33,6 +33,7 @@
 using OfflineItemState = offline_items_collection::OfflineItemState;
 using OfflineItemProgressUnit =
     offline_items_collection::OfflineItemProgressUnit;
+using offline_items_collection::OfflineItemSchedule;
 using offline_items_collection::OfflineItemShareInfo;
 using OfflineItemVisuals = offline_items_collection::OfflineItemVisuals;
 using UpdateDelta = offline_items_collection::UpdateDelta;
@@ -392,6 +393,25 @@
   item->Rename(base::FilePath(filename), std::move(download_callback));
 }
 
+void DownloadOfflineContentProvider::ChangeSchedule(
+    const ContentId& id,
+    base::Optional<OfflineItemSchedule> schedule) {
+  EnsureDownloadCoreServiceStarted();
+  if (state_ != State::HISTORY_LOADED) {
+    pending_actions_for_full_browser_.push_back(base::BindOnce(
+        &DownloadOfflineContentProvider::ChangeSchedule,
+        weak_ptr_factory_.GetWeakPtr(), id, std::move(schedule)));
+    return;
+  }
+
+  DownloadItem* item = GetDownload(id.id);
+  if (!item)
+    return;
+
+  item->OnDownloadScheduleChanged(
+      OfflineItemUtils::ToDownloadSchedule(schedule));
+}
+
 void DownloadOfflineContentProvider::OnRenameDownloadCallbackDone(
     RenameCallback callback,
     DownloadItem* item,
diff --git a/chrome/browser/download/download_offline_content_provider.h b/chrome/browser/download/download_offline_content_provider.h
index f78da2cb..2998d3f 100644
--- a/chrome/browser/download/download_offline_content_provider.h
+++ b/chrome/browser/download/download_offline_content_provider.h
@@ -20,6 +20,7 @@
 #include "components/offline_items_collection/core/offline_content_provider.h"
 #include "components/offline_items_collection/core/offline_item.h"
 
+// TODO(xingliu): Remove using in the header files.
 using DownloadItem = download::DownloadItem;
 using SimpleDownloadManagerCoordinator =
     download::SimpleDownloadManagerCoordinator;
@@ -75,6 +76,10 @@
   void RenameItem(const ContentId& id,
                   const std::string& name,
                   RenameCallback callback) override;
+  void ChangeSchedule(
+      const offline_items_collection::ContentId& id,
+      base::Optional<offline_items_collection::OfflineItemSchedule> schedule)
+      override;
 
   // Methods that can be run in reduced mode.
   void CancelDownload(const ContentId& id) override;
diff --git a/chrome/browser/download/offline_item_utils.cc b/chrome/browser/download/offline_item_utils.cc
index cc2bd292..a7f4f07 100644
--- a/chrome/browser/download/offline_item_utils.cc
+++ b/chrome/browser/download/offline_item_utils.cc
@@ -19,6 +19,7 @@
 #endif
 
 using DownloadItem = download::DownloadItem;
+using DownloadSchedule = download::DownloadSchedule;
 using ContentId = offline_items_collection::ContentId;
 using OfflineItem = offline_items_collection::OfflineItem;
 using OfflineItemFilter = offline_items_collection::OfflineItemFilter;
@@ -132,11 +133,7 @@
   item.fail_state =
       ConvertDownloadInterruptReasonToFailState(download_item->GetLastReason());
   item.can_rename = download_item->GetState() == DownloadItem::COMPLETE;
-  const auto& download_schedule = download_item->GetDownloadSchedule();
-  if (download_schedule.has_value()) {
-    item.schedule = base::make_optional<OfflineItemSchedule>(
-        download_schedule->only_on_wifi(), download_schedule->start_time());
-  }
+  item.schedule = ToOfflineItemSchedule(download_item->GetDownloadSchedule());
 
   switch (download_item->GetState()) {
     case DownloadItem::IN_PROGRESS:
@@ -347,3 +344,23 @@
       return RenameResult::FAILURE_UNKNOWN;
   }
 }
+
+// static
+base::Optional<DownloadSchedule> OfflineItemUtils::ToDownloadSchedule(
+    base::Optional<OfflineItemSchedule> offline_item_schedule) {
+  if (!offline_item_schedule)
+    return base::nullopt;
+
+  return base::make_optional<DownloadSchedule>(
+      offline_item_schedule->only_on_wifi, offline_item_schedule->start_time);
+}
+
+// static
+base::Optional<OfflineItemSchedule> OfflineItemUtils::ToOfflineItemSchedule(
+    base::Optional<DownloadSchedule> download_schedule) {
+  if (!download_schedule)
+    return base::nullopt;
+
+  return base::make_optional<OfflineItemSchedule>(
+      download_schedule->only_on_wifi(), download_schedule->start_time());
+}
diff --git a/chrome/browser/download/offline_item_utils.h b/chrome/browser/download/offline_item_utils.h
index 60282bc..b926148 100644
--- a/chrome/browser/download/offline_item_utils.h
+++ b/chrome/browser/download/offline_item_utils.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "base/strings/string16.h"
 #include "components/download/public/common/download_item.h"
 #include "components/offline_items_collection/core/offline_item.h"
@@ -47,6 +48,16 @@
   static RenameResult ConvertDownloadRenameResultToRenameResult(
       DownloadRenameResult download_rename_result);
 
+  // Converts OfflineItemSchedule to DownloadSchedule.
+  static base::Optional<download::DownloadSchedule> ToDownloadSchedule(
+      base::Optional<offline_items_collection::OfflineItemSchedule>
+          offline_item_schedule);
+
+  // Converts DownloadSchedule to OfflineItemSchedule.
+  static base::Optional<offline_items_collection::OfflineItemSchedule>
+  ToOfflineItemSchedule(
+      base::Optional<download::DownloadSchedule> download_schedule);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(OfflineItemUtils);
 };
diff --git a/chrome/browser/enterprise/connectors/connectors_manager.cc b/chrome/browser/enterprise/connectors/connectors_manager.cc
index 54658909..519653e 100644
--- a/chrome/browser/enterprise/connectors/connectors_manager.cc
+++ b/chrome/browser/enterprise/connectors/connectors_manager.cc
@@ -7,7 +7,7 @@
 #include <memory>
 
 #include "base/feature_list.h"
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/enterprise/connectors/connectors_prefs.h"
@@ -134,8 +134,8 @@
 
 // static
 ConnectorsManager* ConnectorsManager::GetInstance() {
-  return base::Singleton<ConnectorsManager,
-                         base::LeakySingletonTraits<ConnectorsManager>>::get();
+  static base::NoDestructor<ConnectorsManager> manager;
+  return manager.get();
 }
 
 bool ConnectorsManager::IsConnectorEnabled(AnalysisConnector connector) const {
diff --git a/chrome/browser/enterprise/connectors/connectors_manager.h b/chrome/browser/enterprise/connectors/connectors_manager.h
index 1f2b6cf4..a8347424 100644
--- a/chrome/browser/enterprise/connectors/connectors_manager.h
+++ b/chrome/browser/enterprise/connectors/connectors_manager.h
@@ -19,9 +19,7 @@
 
 namespace base {
 template <typename T>
-struct LeakySingletonTraits;
-template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }
 
 namespace enterprise_connectors {
@@ -75,15 +73,14 @@
   const ReportingConnectorsSettings& GetReportingConnectorsSettingsForTesting()
       const;
 
-  // Helpers to reset the ConnectorManager instance across test since it's a
-  // singleton that would otherwise persist its state.
+  // Helpers to reset the ConnectorManager instance across test since it would
+  // otherwise persist its state.
   void SetUpForTesting();
   void TearDownForTesting();
   void ClearCacheForTesting();
 
  private:
-  friend struct base::LeakySingletonTraits<ConnectorsManager>;
-  friend struct base::DefaultSingletonTraits<ConnectorsManager>;
+  friend class base::NoDestructor<ConnectorsManager>;
 
   // Constructor and destructor are declared as private so callers use
   // GetInstance instead.
diff --git a/chrome/browser/enterprise/reporting/browser_report_generator.cc b/chrome/browser/enterprise/reporting/browser_report_generator.cc
deleted file mode 100644
index 56a788ab..0000000
--- a/chrome/browser/enterprise/reporting/browser_report_generator.cc
+++ /dev/null
@@ -1,50 +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/enterprise/reporting/browser_report_generator.h"
-
-#include <string>
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/version.h"
-#include "build/build_config.h"
-#include "components/policy/core/common/cloud/cloud_policy_util.h"
-#include "components/version_info/channel.h"
-#include "components/version_info/version_info.h"
-#include "content/public/common/webplugininfo.h"
-
-namespace em = ::enterprise_management;
-
-namespace enterprise_reporting {
-
-BrowserReportGenerator::BrowserReportGenerator(
-    std::unique_ptr<BrowserReportGenerator::Delegate> delegate)
-    : delegate_(std::move(delegate)) {}
-
-BrowserReportGenerator::~BrowserReportGenerator() = default;
-
-void BrowserReportGenerator::Generate(ReportCallback callback) {
-  auto report = std::make_unique<em::BrowserReport>();
-  GenerateBasicInfo(report.get());
-  delegate_->GenerateProfileInfo(report.get());
-
-  // std::move is required here because the function completes the report
-  // asynchronously.
-  delegate_->GeneratePluginsIfNeeded(std::move(callback), std::move(report));
-}
-
-void BrowserReportGenerator::GenerateBasicInfo(em::BrowserReport* report) {
-#if !defined(OS_CHROMEOS)
-  report->set_browser_version(version_info::GetVersionNumber());
-  report->set_channel(policy::ConvertToProtoChannel(delegate_->GetChannel()));
-  delegate_->GenerateBuildStateInfo(report);
-#endif
-
-  report->set_executable_path(delegate_->GetExecutablePath());
-}
-
-}  // namespace enterprise_reporting
diff --git a/chrome/browser/enterprise/reporting/browser_report_generator.h b/chrome/browser/enterprise/reporting/browser_report_generator.h
deleted file mode 100644
index 494e4a7..0000000
--- a/chrome/browser/enterprise/reporting/browser_report_generator.h
+++ /dev/null
@@ -1,58 +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_ENTERPRISE_REPORTING_BROWSER_REPORT_GENERATOR_H_
-#define CHROME_BROWSER_ENTERPRISE_REPORTING_BROWSER_REPORT_GENERATOR_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "components/policy/proto/device_management_backend.pb.h"
-#include "components/version_info/channel.h"
-
-namespace enterprise_reporting {
-
-// A report generator that collects Browser related information.
-class BrowserReportGenerator {
- public:
-  using ReportCallback = base::OnceCallback<void(
-      std::unique_ptr<enterprise_management::BrowserReport>)>;
-
-  class Delegate {
-   public:
-    virtual ~Delegate() = default;
-
-    virtual std::string GetExecutablePath() = 0;
-    virtual version_info::Channel GetChannel() = 0;
-    virtual void GenerateBuildStateInfo(
-        enterprise_management::BrowserReport* report) = 0;
-    virtual void GenerateProfileInfo(
-        enterprise_management::BrowserReport* report) = 0;
-    virtual void GeneratePluginsIfNeeded(
-        ReportCallback callback,
-        std::unique_ptr<enterprise_management::BrowserReport> report) = 0;
-  };
-
-  explicit BrowserReportGenerator(std::unique_ptr<Delegate> delegate);
-  ~BrowserReportGenerator();
-
-  // Generates a BrowserReport with the following fields:
-  // - browser_version, channel, executable_path
-  // - user profiles: id, name, is_full_report (always be false).
-  // - plugins: name, version, filename, description.
-  void Generate(ReportCallback callback);
-
- private:
-  std::unique_ptr<Delegate> delegate_;
-
-  // Generates browser_version, channel, executable_path info in the given
-  // report instance.
-  void GenerateBasicInfo(enterprise_management::BrowserReport* report);
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserReportGenerator);
-};
-
-}  // namespace enterprise_reporting
-
-#endif  // CHROME_BROWSER_ENTERPRISE_REPORTING_BROWSER_REPORT_GENERATOR_H_
diff --git a/chrome/browser/enterprise/reporting/browser_report_generator_desktop.h b/chrome/browser/enterprise/reporting/browser_report_generator_desktop.h
index c379585..dc05fd9 100644
--- a/chrome/browser/enterprise/reporting/browser_report_generator_desktop.h
+++ b/chrome/browser/enterprise/reporting/browser_report_generator_desktop.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_ENTERPRISE_REPORTING_BROWSER_REPORT_GENERATOR_DESKTOP_H_
 #define CHROME_BROWSER_ENTERPRISE_REPORTING_BROWSER_REPORT_GENERATOR_DESKTOP_H_
 
-#include "chrome/browser/enterprise/reporting/browser_report_generator.h"
+#include "components/enterprise/browser/reporting/browser_report_generator.h"
 
 #include <memory>
 #include <vector>
diff --git a/chrome/browser/enterprise/reporting/browser_report_generator_unittest.cc b/chrome/browser/enterprise/reporting/browser_report_generator_unittest.cc
index 9ae8c8d6..3752aba 100644
--- a/chrome/browser/enterprise/reporting/browser_report_generator_unittest.cc
+++ b/chrome/browser/enterprise/reporting/browser_report_generator_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/enterprise/reporting/browser_report_generator.h"
+#include "chrome/browser/enterprise/reporting/browser_report_generator_desktop.h"
 
 #include <memory>
 
@@ -12,13 +12,13 @@
 #include "base/test/bind_test_util.h"
 #include "base/version.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/enterprise/reporting/browser_report_generator_desktop.h"
 #include "chrome/browser/enterprise/reporting/profile_report_generator.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/upgrade_detector/build_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/account_id/account_id.h"
+#include "components/enterprise/browser/reporting/browser_report_generator.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/common/webplugininfo.h"
 #include "content/public/test/browser_task_environment.h"
diff --git a/chrome/browser/enterprise/reporting/report_generator.h b/chrome/browser/enterprise/reporting/report_generator.h
index 792d4b3..3ddffda 100644
--- a/chrome/browser/enterprise/reporting/report_generator.h
+++ b/chrome/browser/enterprise/reporting/report_generator.h
@@ -11,8 +11,8 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
-#include "chrome/browser/enterprise/reporting/browser_report_generator.h"
 #include "chrome/browser/enterprise/reporting/report_request_queue_generator.h"
+#include "components/enterprise/browser/reporting/browser_report_generator.h"
 #include "components/enterprise/browser/reporting/report_request_definition.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 
diff --git a/chrome/browser/enterprise/reporting/report_request_queue_generator_unittest.cc b/chrome/browser/enterprise/reporting/report_request_queue_generator_unittest.cc
index c44d5621..49275db6 100644
--- a/chrome/browser/enterprise/reporting/report_request_queue_generator_unittest.cc
+++ b/chrome/browser/enterprise/reporting/report_request_queue_generator_unittest.cc
@@ -11,12 +11,12 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
-#include "chrome/browser/enterprise/reporting/browser_report_generator.h"
 #include "chrome/browser/enterprise/reporting/browser_report_generator_desktop.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
 #include "components/account_id/account_id.h"
+#include "components/enterprise/browser/reporting/browser_report_generator.h"
 #include "components/enterprise/browser/reporting/report_request_definition.h"
 #include "components/policy/core/common/mock_policy_service.h"
 #include "components/policy/core/common/policy_map.h"
diff --git a/chrome/browser/enterprise/reporting/report_scheduler_browsertest.cc b/chrome/browser/enterprise/reporting/report_scheduler_browsertest.cc
index 3e25ce6..1957fdc7 100644
--- a/chrome/browser/enterprise/reporting/report_scheduler_browsertest.cc
+++ b/chrome/browser/enterprise/reporting/report_scheduler_browsertest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
@@ -53,7 +55,7 @@
 
   void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
     static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
-        new ChromeBrowserExtraSetUp(this));
+        std::make_unique<ChromeBrowserExtraSetUp>(this));
   }
 
   void TearDownOnMainThread() override {
diff --git a/chrome/browser/extensions/updater/extension_update_client_base_browsertest.cc b/chrome/browser/extensions/updater/extension_update_client_base_browsertest.cc
index 610ce86..70bbf121 100644
--- a/chrome/browser/extensions/updater/extension_update_client_base_browsertest.cc
+++ b/chrome/browser/extensions/updater/extension_update_client_base_browsertest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/extensions/updater/extension_update_client_base_browsertest.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/optional.h"
 #include "base/path_service.h"
@@ -151,7 +153,7 @@
     content::BrowserMainParts* parts) {
   ExtensionBrowserTest::CreatedBrowserMainParts(parts);
   static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
-      new TestChromeBrowserMainExtraParts(this));
+      std::make_unique<TestChromeBrowserMainExtraParts>(this));
 }
 
 void ExtensionUpdateClientBaseTest::SetUpOnMainThread() {
diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc
index 0940ae09..4ea7d03 100644
--- a/chrome/browser/extensions/window_open_apitest.cc
+++ b/chrome/browser/extensions/window_open_apitest.cc
@@ -164,13 +164,7 @@
   EXPECT_TRUE(WaitForTabsPopupsApps(browser(), 0, 0, 1));
 }
 
-// Disabled on Windows. Often times out or fails: crbug.com/177530
-#if defined(OS_WIN)
-#define MAYBE_PopupBlockingExtension DISABLED_PopupBlockingExtension
-#else
-#define MAYBE_PopupBlockingExtension PopupBlockingExtension
-#endif
-IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, MAYBE_PopupBlockingExtension) {
+IN_PROC_BROWSER_TEST_F(WindowOpenApiTest, PopupBlockingExtension) {
   ASSERT_TRUE(StartEmbeddedTestServer());
 
   ASSERT_TRUE(LoadExtension(
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 4e7ae9f4..6269b57 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -252,7 +252,7 @@
   {
     "name": "audio-worklet-realtime-thread",
     "owners": [ "//third_party/blink/renderer/modules/webaudio/OWNERS" ],
-    "expiry_milestone": 85
+    "expiry_milestone": 90
   },
   {
     "name": "auto-fetch-on-net-error-page",
@@ -610,7 +610,7 @@
     "expiry_milestone": 88
   },
   {
-    "name": "context-menu-performance-info",
+    "name": "context-menu-performance-info-and-remote-hints-fetching",
     "owners": [ "jds" ],
     "expiry_milestone": 90
   },
@@ -3966,6 +3966,10 @@
     "owners": [ "kerrnel", "mnissler" ],
     "expiry_milestone": 88
   },
+  {"name": "schemeful-same-site",
+    "owners": [ "bingler", "chlily" ],
+    "expiry_milestone": 90
+  },
   {
     "name": "scroll-unification",
     "owners": [ "bokan@chromium.org", "input-dev@chromium.org" ],
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 718f312..80f9d23 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1855,6 +1855,12 @@
     "SameSite=Lax. Sites must specify SameSite=None in order to enable "
     "third-party usage.";
 
+const char kSchemefulSameSiteName[] = "Schemeful Same-Site";
+const char kSchemefulSameSiteDescription[] =
+    "Modify the same-site computation such that origins with the same "
+    "registrable domain but different schemes are considered cross-site. This "
+    "change only applies to cookies with the 'SameSite' attribute.";
+
 const char kScrollableTabStripName[] = "Scrollable TabStrip";
 const char kScrollableTabStripDescription[] =
     "Allows users to access tabs by scrolling when they no longer fit in the "
@@ -2499,9 +2505,12 @@
 const char kContextMenuCopyImageDescription[] =
     "Enable copying image to system clipboard via context menu.";
 
-const char kContextMenuPerformanceInfoName[] = "Context menu performance hints";
-const char kContextMenuPerformanceInfoDescription[] =
-    "Show link performance information in the context menu.";
+const char kContextMenuPerformanceInfoAndRemoteHintFetchingName[] =
+    "Context menu performance info and remote hint fetching";
+const char kContextMenuPerformanceInfoAndRemoteHintFetchingDescription[] =
+    "Enables showing link performance information in the context menu and "
+    "allows communicating with Google servers to fetch performance information "
+    "for the main frame URL.";
 
 const char kContextualSearchDebugName[] = "Contextual Search debug";
 const char kContextualSearchDebugDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 7294a7e..eb6e2c5 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1078,6 +1078,9 @@
 extern const char kSameSiteByDefaultCookiesName[];
 extern const char kSameSiteByDefaultCookiesDescription[];
 
+extern const char kSchemefulSameSiteName[];
+extern const char kSchemefulSameSiteDescription[];
+
 extern const char kScrollableTabStripName[];
 extern const char kScrollableTabStripDescription[];
 
@@ -1456,8 +1459,8 @@
 extern const char kContextMenuCopyImageName[];
 extern const char kContextMenuCopyImageDescription[];
 
-extern const char kContextMenuPerformanceInfoName[];
-extern const char kContextMenuPerformanceInfoDescription[];
+extern const char kContextMenuPerformanceInfoAndRemoteHintFetchingName[];
+extern const char kContextMenuPerformanceInfoAndRemoteHintFetchingDescription[];
 
 extern const char kContextualSearchDebugName[];
 extern const char kContextualSearchDebugDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index b25a730..57aa2a73 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/stl_util.h"
 #include "chrome/browser/flags/jni_headers/ChromeFeatureList_jni.h"
+#include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/share/features.h"
 #include "chrome/browser/sharing/shared_clipboard/feature_flags.h"
 #include "chrome/common/chrome_features.h"
@@ -137,7 +138,6 @@
     &kContentIndexingNTP,
     &kContentSuggestionsScrollToLoad,
     &kContextMenuCopyImage,
-    &kContextMenuPerformanceInfo,
     &kContextMenuSearchWithGoogleLens,
     &kContextMenuShopWithGoogleLens,
     &kContextMenuSearchAndShopWithGoogleLens,
@@ -391,9 +391,6 @@
 const base::Feature kContextMenuCopyImage{"ContextMenuCopyImage",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kContextMenuPerformanceInfo{
-    "ContextMenuPerformanceInfo", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kContextMenuSearchWithGoogleLens{
     "ContextMenuSearchWithGoogleLens", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -518,9 +515,6 @@
 const base::Feature kOverlayNewLayout{"OverlayNewLayout",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kPageInfoPerformanceHints{
-    "PageInfoPerformanceHints", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // TODO(rouslan): Remove this. (Currently used in
 // GooglePayPaymentAppFactory.java)
 const base::Feature kPayWithGoogleV1{"PayWithGoogleV1",
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 6cadd52..787d2eb5 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -49,7 +49,6 @@
 extern const base::Feature kContentIndexingDownloadHome;
 extern const base::Feature kContentIndexingNTP;
 extern const base::Feature kContextMenuCopyImage;
-extern const base::Feature kContextMenuPerformanceInfo;
 extern const base::Feature kContextMenuSearchWithGoogleLens;
 extern const base::Feature kContextMenuShopWithGoogleLens;
 extern const base::Feature kContextMenuSearchAndShopWithGoogleLens;
@@ -92,7 +91,6 @@
 extern const base::Feature kOfflineIndicatorV2;
 extern const base::Feature kOmniboxSpareRenderer;
 extern const base::Feature kOverlayNewLayout;
-extern const base::Feature kPageInfoPerformanceHints;
 extern const base::Feature kPayWithGoogleV1;
 extern const base::Feature kPhotoPickerVideoSupport;
 extern const base::Feature kPhotoPickerZoom;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index ee9f200..a2d2f1b 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -253,7 +253,6 @@
     public static final String CONTENT_INDEXING_NTP = "ContentIndexingNTP";
     public static final String CONTENT_INDEXING_DOWNLOAD_HOME = "ContentIndexingDownloadHome";
     public static final String CONTEXT_MENU_COPY_IMAGE = "ContextMenuCopyImage";
-    public static final String CONTEXT_MENU_PERFORMANCE_INFO = "ContextMenuPerformanceInfo";
     public static final String CONTEXT_MENU_SEARCH_WITH_GOOGLE_LENS =
             "ContextMenuSearchWithGoogleLens";
     public static final String CONTEXT_MENU_SHOP_WITH_GOOGLE_LENS = "ContextMenuShopWithGoogleLens";
diff --git a/chrome/browser/history/android/android_history_provider_service.cc b/chrome/browser/history/android/android_history_provider_service.cc
index 52f896ad..43c839e 100644
--- a/chrome/browser/history/android/android_history_provider_service.cc
+++ b/chrome/browser/history/android/android_history_provider_service.cc
@@ -26,13 +26,14 @@
 template <typename ResultType>
 class AndroidProviderTask : public history::HistoryDBTask {
  public:
-  typedef base::Callback<ResultType(history::AndroidProviderBackend*)>
+  typedef base::OnceCallback<ResultType(history::AndroidProviderBackend*)>
       RequestCallback;
-  typedef base::Callback<void(ResultType)> ResultCallback;
+  typedef base::OnceCallback<void(ResultType)> ResultCallback;
 
-  AndroidProviderTask(const RequestCallback& request_cb,
-                      const ResultCallback& result_cb)
-      : request_cb_(request_cb), result_cb_(result_cb), result_(0) {
+  AndroidProviderTask(RequestCallback request_cb, ResultCallback result_cb)
+      : request_cb_(std::move(request_cb)),
+        result_cb_(std::move(result_cb)),
+        result_(0) {
     DCHECK(!request_cb_.is_null());
     DCHECK(!result_cb_.is_null());
   }
@@ -46,11 +47,11 @@
     history::AndroidProviderBackend* android_provider_backend =
       history::AndroidProviderBackend::FromHistoryBackend(history_backend);
     if (android_provider_backend)
-      result_ = request_cb_.Run(android_provider_backend);
+      result_ = std::move(request_cb_).Run(android_provider_backend);
     return true;
   }
 
-  void DoneRunOnMainThread() override { result_cb_.Run(result_); }
+  void DoneRunOnMainThread() override { std::move(result_cb_).Run(result_); }
 
   RequestCallback request_cb_;
   ResultCallback result_cb_;
@@ -61,11 +62,11 @@
 // type deduction.
 template <typename ResultType>
 std::unique_ptr<history::HistoryDBTask> CreateAndroidProviderTask(
-    const base::Callback<ResultType(history::AndroidProviderBackend*)>&
-        request_cb,
-    const base::Callback<void(ResultType)>& result_cb) {
+    base::OnceCallback<ResultType(history::AndroidProviderBackend*)> request_cb,
+    base::OnceCallback<void(ResultType)> result_cb) {
   return std::unique_ptr<history::HistoryDBTask>(
-      new AndroidProviderTask<ResultType>(request_cb, result_cb));
+      new AndroidProviderTask<ResultType>(std::move(request_cb),
+                                          std::move(result_cb)));
 }
 
 // History and bookmarks ----------------------------------------------------
@@ -255,20 +256,20 @@
     const std::string& selection,
     const std::vector<base::string16>& selection_args,
     const std::string& sort_order,
-    const QueryCallback& callback,
+    QueryCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(nullptr);
+    std::move(callback).Run(nullptr);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
       CreateAndroidProviderTask(
-          base::Bind(&QueryHistoryAndBookmarksAdapter, projections, selection,
-                     selection_args, sort_order),
-          callback),
+          base::BindOnce(&QueryHistoryAndBookmarksAdapter, projections,
+                         selection, selection_args, sort_order),
+          std::move(callback)),
       tracker);
 }
 
@@ -277,19 +278,20 @@
     const history::HistoryAndBookmarkRow& row,
     const std::string& selection,
     const std::vector<base::string16>& selection_args,
-    const UpdateCallback& callback,
+    UpdateCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(0);
+    std::move(callback).Run(0);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
-      CreateAndroidProviderTask(base::Bind(&UpdateHistoryAndBookmarksAdapter,
-                                           row, selection, selection_args),
-                                callback),
+      CreateAndroidProviderTask(
+          base::BindOnce(&UpdateHistoryAndBookmarksAdapter, row, selection,
+                         selection_args),
+          std::move(callback)),
       tracker);
 }
 
@@ -297,37 +299,39 @@
 AndroidHistoryProviderService::DeleteHistoryAndBookmarks(
     const std::string& selection,
     const std::vector<base::string16>& selection_args,
-    const DeleteCallback& callback,
+    DeleteCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(0);
+    std::move(callback).Run(0);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
-      CreateAndroidProviderTask(base::Bind(&DeleteHistoryAndBookmarksAdapter,
-                                           selection, selection_args),
-                                callback),
+      CreateAndroidProviderTask(
+          base::BindOnce(&DeleteHistoryAndBookmarksAdapter, selection,
+                         selection_args),
+          std::move(callback)),
       tracker);
 }
 
 base::CancelableTaskTracker::TaskId
 AndroidHistoryProviderService::InsertHistoryAndBookmark(
     const history::HistoryAndBookmarkRow& values,
-    const InsertCallback& callback,
+    InsertCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(0);
+    std::move(callback).Run(0);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
       CreateAndroidProviderTask(
-          base::Bind(&InsertHistoryAndBookmarkAdapter, values), callback),
+          base::BindOnce(&InsertHistoryAndBookmarkAdapter, values),
+          std::move(callback)),
       tracker);
 }
 
@@ -335,19 +339,19 @@
 AndroidHistoryProviderService::DeleteHistory(
     const std::string& selection,
     const std::vector<base::string16>& selection_args,
-    const DeleteCallback& callback,
+    DeleteCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(0);
+    std::move(callback).Run(0);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
       CreateAndroidProviderTask(
-          base::Bind(&DeleteHistoryAdapter, selection, selection_args),
-          callback),
+          base::BindOnce(&DeleteHistoryAdapter, selection, selection_args),
+          std::move(callback)),
       tracker);
 }
 
@@ -356,19 +360,19 @@
     history::AndroidStatement* statement,
     int current_pos,
     int destination,
-    const MoveStatementCallback& callback,
+    MoveStatementCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(current_pos);
+    std::move(callback).Run(current_pos);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
-      CreateAndroidProviderTask(base::Bind(&MoveStatementAdapter, statement,
-                                           current_pos, destination),
-                                callback),
+      CreateAndroidProviderTask(base::BindOnce(&MoveStatementAdapter, statement,
+                                               current_pos, destination),
+                                std::move(callback)),
       tracker);
 }
 
@@ -388,18 +392,18 @@
 base::CancelableTaskTracker::TaskId
 AndroidHistoryProviderService::InsertSearchTerm(
     const history::SearchRow& row,
-    const InsertCallback& callback,
+    InsertCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(0);
+    std::move(callback).Run(0);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
-      CreateAndroidProviderTask(base::Bind(&InsertSearchTermAdapter, row),
-                                callback),
+      CreateAndroidProviderTask(base::BindOnce(&InsertSearchTermAdapter, row),
+                                std::move(callback)),
       tracker);
 }
 
@@ -408,19 +412,19 @@
     const history::SearchRow& row,
     const std::string& selection,
     const std::vector<base::string16>& selection_args,
-    const UpdateCallback& callback,
+    UpdateCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(0);
+    std::move(callback).Run(0);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
-      CreateAndroidProviderTask(
-          base::Bind(&UpdateSearchTermsAdapter, row, selection, selection_args),
-          callback),
+      CreateAndroidProviderTask(base::BindOnce(&UpdateSearchTermsAdapter, row,
+                                               selection, selection_args),
+                                std::move(callback)),
       tracker);
 }
 
@@ -428,19 +432,19 @@
 AndroidHistoryProviderService::DeleteSearchTerms(
     const std::string& selection,
     const std::vector<base::string16>& selection_args,
-    const DeleteCallback& callback,
+    DeleteCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(0);
+    std::move(callback).Run(0);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
       CreateAndroidProviderTask(
-          base::Bind(&DeleteSearchTermsAdapter, selection, selection_args),
-          callback),
+          base::BindOnce(&DeleteSearchTermsAdapter, selection, selection_args),
+          std::move(callback)),
       tracker);
 }
 
@@ -450,20 +454,20 @@
     const std::string& selection,
     const std::vector<base::string16>& selection_args,
     const std::string& sort_order,
-    const QueryCallback& callback,
+    QueryCallback callback,
     base::CancelableTaskTracker* tracker) {
   history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
   if (!hs) {
-    callback.Run(nullptr);
+    std::move(callback).Run(nullptr);
     return base::CancelableTaskTracker::kBadTaskId;
   }
   return hs->ScheduleDBTask(
       FROM_HERE,
       CreateAndroidProviderTask(
-          base::Bind(&QuerySearchTermsAdapter, projections, selection,
-                     selection_args, sort_order),
-          callback),
+          base::BindOnce(&QuerySearchTermsAdapter, projections, selection,
+                         selection_args, sort_order),
+          std::move(callback)),
       tracker);
 }
 
diff --git a/chrome/browser/history/android/android_history_provider_service.h b/chrome/browser/history/android/android_history_provider_service.h
index 8c06ea0..d51a353 100644
--- a/chrome/browser/history/android/android_history_provider_service.h
+++ b/chrome/browser/history/android/android_history_provider_service.h
@@ -32,24 +32,24 @@
 
   // Callback invoked when a method creating an |AndroidStatement| object is
   // complete. The pointer is NULL if the creation failed.
-  typedef base::Callback<void(history::AndroidStatement*)> QueryCallback;
+  typedef base::OnceCallback<void(history::AndroidStatement*)> QueryCallback;
 
   // Callback invoked when a method updating rows in the database complete.
   // The parameter is the number of rows updated or 0 if the update failed.
-  typedef base::Callback<void(int)> UpdateCallback;
+  typedef base::OnceCallback<void(int)> UpdateCallback;
 
   // Callback invoked when a method inserting rows in the database complete.
   // The value is the new row id or 0 if the insertion failed.
-  typedef base::Callback<void(int64_t)> InsertCallback;
+  typedef base::OnceCallback<void(int64_t)> InsertCallback;
 
   // Callback invoked when a method deleting rows in the database complete.
   // The value is the number of rows deleted or 0 if the deletion failed.
-  typedef base::Callback<void(int)> DeleteCallback;
+  typedef base::OnceCallback<void(int)> DeleteCallback;
 
   // Callback invoked when a method moving an |AndroidStatement| is complete.
   // The value passed to the callback is the new position, or in case of
   // failure, the old position.
-  typedef base::Callback<void(int)> MoveStatementCallback;
+  typedef base::OnceCallback<void(int)> MoveStatementCallback;
 
   // History and Bookmarks ----------------------------------------------------
   //
@@ -65,7 +65,7 @@
       const std::string& selection,
       const std::vector<base::string16>& selection_args,
       const std::string& sort_order,
-      const QueryCallback& callback,
+      QueryCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Runs the given update and the number of the row updated is returned to the
@@ -78,7 +78,7 @@
       const history::HistoryAndBookmarkRow& row,
       const std::string& selection,
       const std::vector<base::string16>& selection_args,
-      const UpdateCallback& callback,
+      UpdateCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Deletes the specified rows and invokes the |callback| to return the number
@@ -91,14 +91,14 @@
   base::CancelableTaskTracker::TaskId DeleteHistoryAndBookmarks(
       const std::string& selection,
       const std::vector<base::string16>& selection_args,
-      const DeleteCallback& callback,
+      DeleteCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Inserts the given values into history backend, and invokes the |callback|
   // to return the result.
   base::CancelableTaskTracker::TaskId InsertHistoryAndBookmark(
       const history::HistoryAndBookmarkRow& values,
-      const InsertCallback& callback,
+      InsertCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Deletes the matched history and invokes |callback| to return the number of
@@ -106,7 +106,7 @@
   base::CancelableTaskTracker::TaskId DeleteHistory(
       const std::string& selection,
       const std::vector<base::string16>& selection_args,
-      const DeleteCallback& callback,
+      DeleteCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Statement ----------------------------------------------------------------
@@ -117,7 +117,7 @@
       history::AndroidStatement* statement,
       int current_pos,
       int destination,
-      const MoveStatementCallback& callback,
+      MoveStatementCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Closes the statement in db thread. The AndroidHistoryProviderService takes
@@ -129,7 +129,7 @@
   // to the |callback| on success.
   base::CancelableTaskTracker::TaskId InsertSearchTerm(
       const history::SearchRow& row,
-      const InsertCallback& callback,
+      InsertCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Runs the given update and returns the number of the update rows to the
@@ -142,7 +142,7 @@
       const history::SearchRow& row,
       const std::string& selection,
       const std::vector<base::string16>& selection_args,
-      const UpdateCallback& callback,
+      UpdateCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Deletes the matched rows and the number of deleted rows is returned to
@@ -155,7 +155,7 @@
   base::CancelableTaskTracker::TaskId DeleteSearchTerms(
       const std::string& selection,
       const std::vector<base::string16>& selection_args,
-      const DeleteCallback& callback,
+      DeleteCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Runs the query and invokes the |callback| to return the result.
@@ -170,7 +170,7 @@
       const std::string& selection,
       const std::vector<base::string16>& selection_args,
       const std::string& sort_order,
-      const QueryCallback& callback,
+      QueryCallback callback,
       base::CancelableTaskTracker* tracker);
 
   // Returns the largest Favicon for |favicon_id| and invokes
diff --git a/chrome/browser/history/android/sqlite_cursor.cc b/chrome/browser/history/android/sqlite_cursor.cc
index c833a62..315a1d9 100644
--- a/chrome/browser/history/android/sqlite_cursor.cc
+++ b/chrome/browser/history/android/sqlite_cursor.cc
@@ -186,8 +186,8 @@
     content::GetUIThreadTaskRunner({})->PostTask(
         FROM_HERE, base::BindOnce(&SQLiteCursor::GetFaviconForIDInUIThread,
                                   base::Unretained(this), id,
-                                  base::Bind(&SQLiteCursor::OnFaviconData,
-                                             base::Unretained(this))));
+                                  base::BindOnce(&SQLiteCursor::OnFaviconData,
+                                                 base::Unretained(this))));
 
     if (test_observer_)
       test_observer_->OnPostGetFaviconTask();
@@ -243,9 +243,7 @@
   if (!tracker_.get())
     tracker_.reset(new base::CancelableTaskTracker());
   service_->MoveStatement(
-      statement_,
-      position_,
-      pos,
-      base::Bind(&SQLiteCursor::OnMoved, base::Unretained(this)),
+      statement_, position_, pos,
+      base::BindOnce(&SQLiteCursor::OnMoved, base::Unretained(this)),
       tracker_.get());
 }
diff --git a/chrome/browser/lite_video/lite_video_keyed_service_browsertest.cc b/chrome/browser/lite_video/lite_video_keyed_service_browsertest.cc
index 0d1892cc8..95c064750 100644
--- a/chrome/browser/lite_video/lite_video_keyed_service_browsertest.cc
+++ b/chrome/browser/lite_video/lite_video_keyed_service_browsertest.cc
@@ -51,11 +51,12 @@
   int total = 0;
   while (true) {
     base::ThreadPoolInstance::Get()->FlushForTesting();
-    base::RunLoop().RunUntilIdle();
-
     total = GetTotalHistogramSamples(histogram_tester, histogram_name);
     if (total >= count)
       return total;
+    content::FetchHistogramsFromChildProcesses();
+    metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+    base::RunLoop().RunUntilIdle();
   }
 }
 
@@ -111,6 +112,8 @@
   void SetUpOnMainThread() override {
     content::NetworkConnectionChangeSimulator().SetConnectionType(
         network::mojom::ConnectionType::CONNECTION_4G);
+    SetEffectiveConnectionType(
+        net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_4G);
     InProcessBrowserTest::SetUpOnMainThread();
   }
 
@@ -118,6 +121,14 @@
     cmd->AppendSwitch("enable-spdy-proxy-auth");
   }
 
+  // Sets the effective connection type that the Network Quality Tracker will
+  // report.
+  void SetEffectiveConnectionType(
+      net::EffectiveConnectionType effective_connection_type) {
+    g_browser_process->network_quality_tracker()
+        ->ReportEffectiveConnectionTypeForTesting(effective_connection_type);
+  }
+
   lite_video::LiteVideoDecider* lite_video_decider() {
     return LiteVideoKeyedServiceFactory::GetForProfile(browser()->profile())
         ->lite_video_decider();
@@ -156,8 +167,18 @@
   histogram_tester()->ExpectTotalCount("LiteVideo.Navigation.HasHint", 0);
 }
 
+// Fails occasionally on ChromeOS. http://crbug.com/1102563
+#if defined(OS_CHROMEOS)
+#define MAYBE_LiteVideoCanApplyLiteVideo_NoHintForHost \
+  DISABLED_LiteVideoCanApplyLiteVideo_NoHintForHost
+#else
+#define MAYBE_LiteVideoCanApplyLiteVideo_NoHintForHost \
+  LiteVideoCanApplyLiteVideo_NoHintForHost
+#endif
 IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
-                       LiteVideoCanApplyLiteVideo_NoHintForHost) {
+                       MAYBE_LiteVideoCanApplyLiteVideo_NoHintForHost) {
+  SetEffectiveConnectionType(
+      net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_4G);
   WaitForBlocklistToBeLoaded();
   EXPECT_TRUE(
       LiteVideoKeyedServiceFactory::GetForProfile(browser()->profile()));
@@ -179,6 +200,8 @@
 
 IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
                        LiteVideoCanApplyLiteVideo_HasHint) {
+  SetEffectiveConnectionType(
+      net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_4G);
   WaitForBlocklistToBeLoaded();
   EXPECT_TRUE(
       LiteVideoKeyedServiceFactory::GetForProfile(browser()->profile()));
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
index 28d6e847..e7c9b028 100644
--- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
+++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -655,7 +655,7 @@
 namespace chrome {
 
 void AddMetricsExtraParts(ChromeBrowserMainParts* main_parts) {
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsMetrics());
+  main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsMetrics>());
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/metrics/metrics_reporting_state_browsertest.cc b/chrome/browser/metrics/metrics_reporting_state_browsertest.cc
index cbc5245..919f204c 100644
--- a/chrome/browser/metrics/metrics_reporting_state_browsertest.cc
+++ b/chrome/browser/metrics/metrics_reporting_state_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/metrics/metrics_reporting_state.h"
 
+#include <memory>
 #include <string>
 
 #include "base/bind.h"
@@ -80,7 +81,7 @@
     ChromeMetricsServiceAccessor::SetForceIsMetricsReportingEnabledPrefLookup(
         true);
     static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
-        new ChromeBrowserMainExtraPartsChecker(
+        std::make_unique<ChromeBrowserMainExtraPartsChecker>(
             is_metrics_reporting_enabled_initial_value()));
   }
 
diff --git a/chrome/browser/nearby_sharing/fast_initiation_manager.cc b/chrome/browser/nearby_sharing/fast_initiation_manager.cc
index fcfc4cc..9b554fb 100644
--- a/chrome/browser/nearby_sharing/fast_initiation_manager.cc
+++ b/chrome/browser/nearby_sharing/fast_initiation_manager.cc
@@ -17,6 +17,10 @@
 #include "device/bluetooth/bluetooth_advertisement.h"
 
 namespace {
+enum class FastInitVersion : uint8_t {
+  kV1 = 0,
+};
+
 #if defined(CHROME_OS)
 constexpr base::TimeDelta kMinFastInitAdvertisingInterval =
     base::TimeDelta::FromMilliseconds(100);
@@ -33,6 +37,14 @@
 constexpr const char kNearbySharingFastInitiationServiceUuid[] =
     "0000fe2c-0000-1000-8000-00805f9b34fb";
 const uint8_t kNearbySharingFastPairId[] = {0xfc, 0x12, 0x8e};
+const FastInitVersion kVersion = FastInitVersion::kV1;
+const uint8_t kVersionBitmask = 0b111;
+const uint8_t kTypeBitmask = 0b111;
+
+// TODO(crbug.com/1099846): This value comes from Android, but we may need to
+// find a more appropriate power setting for Chrome OS devices.
+const int8_t kAdjustedTxPower = -66;
+
 }  // namespace
 
 // static
@@ -64,7 +76,13 @@
   StopAdvertising(base::DoNothing());
 }
 
+void FastInitiationManager::AdvertisementReleased(
+    device::BluetoothAdvertisement* advertisement) {
+  StopAdvertising(base::DoNothing());
+}
+
 void FastInitiationManager::StartAdvertising(
+    FastInitType type,
     base::OnceCallback<void()> callback,
     base::OnceCallback<void()> error_callback) {
   DCHECK(adapter_->IsPresent() && adapter_->IsPowered());
@@ -80,11 +98,11 @@
   adapter_->SetAdvertisingInterval(
       kMinFastInitAdvertisingInterval, kMaxFastInitAdvertisingInterval,
       base::Bind(&FastInitiationManager::OnSetAdvertisingInterval,
-                 weak_ptr_factory_.GetWeakPtr()),
+                 weak_ptr_factory_.GetWeakPtr(), type),
       base::Bind(&FastInitiationManager::OnSetAdvertisingIntervalError,
-                 weak_ptr_factory_.GetWeakPtr()));
+                 weak_ptr_factory_.GetWeakPtr(), type));
 #else
-  RegisterAdvertisement();
+  RegisterAdvertisement(type);
 #endif
 }
 
@@ -109,22 +127,20 @@
 #endif
 }
 
-void FastInitiationManager::AdvertisementReleased(
-    device::BluetoothAdvertisement* advertisement) {
-  // TODO(hansenmichael): Handle advertisement released appropriately.
-}
-
-void FastInitiationManager::OnSetAdvertisingInterval() {
-  RegisterAdvertisement();
+void FastInitiationManager::OnSetAdvertisingInterval(
+    FastInitiationManager::FastInitType type) {
+  RegisterAdvertisement(type);
 }
 
 void FastInitiationManager::OnSetAdvertisingIntervalError(
+    FastInitiationManager::FastInitType type,
     device::BluetoothAdvertisement::ErrorCode code) {
   LOG(WARNING) << "SetAdvertisingInterval() failed with error code = " << code;
-  RegisterAdvertisement();
+  RegisterAdvertisement(type);
 }
 
-void FastInitiationManager::RegisterAdvertisement() {
+void FastInitiationManager::RegisterAdvertisement(
+    FastInitiationManager::FastInitType type) {
   auto advertisement_data =
       std::make_unique<device::BluetoothAdvertisement::Data>(
           device::BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST);
@@ -137,7 +153,8 @@
       std::make_unique<device::BluetoothAdvertisement::ServiceData>();
   auto payload = std::vector<uint8_t>(std::begin(kNearbySharingFastPairId),
                                       std::end(kNearbySharingFastPairId));
-  payload.push_back(GenerateFastInitV1Metadata());
+  auto metadata = GenerateFastInitV1Metadata(type);
+  payload.insert(std::end(payload), std::begin(metadata), std::end(metadata));
   service_data->insert(std::pair<std::string, std::vector<uint8_t>>(
       kNearbySharingFastInitiationServiceUuid, payload));
   advertisement_data->set_service_data(std::move(service_data));
@@ -197,11 +214,20 @@
       << "FastInitiationManager::StopAdvertising() failed with error code = "
       << error_code;
   advertisement_.reset();
-  stop_callback_.Reset();
+  std::move(stop_callback_).Run();
 }
 
-uint8_t FastInitiationManager::GenerateFastInitV1Metadata() {
-  // TODO(hansenmichael): Include 'version', |type|, and |adjusted_tx_power|
-  // bits.
-  return 0x00;
+std::vector<uint8_t> FastInitiationManager::GenerateFastInitV1Metadata(
+    FastInitiationManager::FastInitType type) {
+  std::vector<uint8_t> metadata;
+  uint8_t versionConverted = (static_cast<uint8_t>(kVersion) & kVersionBitmask)
+                             << 5;
+  uint8_t typeConverted = (static_cast<uint8_t>(type) & kTypeBitmask) << 2;
+
+  // Note: the last two bits of this first byte correspond to 'uwb_enable' and
+  // 'reserved'. The Chrome implementation does not support UWB (Ultra wideband)
+  // and the 'reserved' bit is currently unused, so both are left empty.
+  metadata.push_back(versionConverted | typeConverted);
+  metadata.push_back(kAdjustedTxPower);
+  return metadata;
 }
diff --git a/chrome/browser/nearby_sharing/fast_initiation_manager.h b/chrome/browser/nearby_sharing/fast_initiation_manager.h
index 2f95fa50..f387c5e 100644
--- a/chrome/browser/nearby_sharing/fast_initiation_manager.h
+++ b/chrome/browser/nearby_sharing/fast_initiation_manager.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_NEARBY_SHARING_FAST_INITIATION_MANAGER_H_
 
 #include <memory>
+#include <vector>
 
 #include "base/memory/weak_ptr.h"
 #include "device/bluetooth/bluetooth_adapter.h"
@@ -15,8 +16,13 @@
 // 0xFC128E along with 2 additional bytes of metadata at the end. Some remote
 // devices background scan for Fast Initiation advertisements, as a signal to
 // begin advertising via Nearby Connections.
-class FastInitiationManager : device::BluetoothAdvertisement::Observer {
+class FastInitiationManager : public device::BluetoothAdvertisement::Observer {
  public:
+  enum class FastInitType : uint8_t {
+    kNotify = 0,
+    kSilent = 1,
+  };
+
   class Factory {
    public:
     Factory() = default;
@@ -44,7 +50,8 @@
   FastInitiationManager& operator=(const FastInitiationManager&) = delete;
 
   // Begin broadcasting Fast Initiation advertisement.
-  virtual void StartAdvertising(base::OnceCallback<void()> callback,
+  virtual void StartAdvertising(FastInitType type,
+                                base::OnceCallback<void()> callback,
                                 base::OnceCallback<void()> error_callback);
 
   // Stop broadcasting Fast Initiation advertisement.
@@ -55,10 +62,11 @@
   void AdvertisementReleased(
       device::BluetoothAdvertisement* advertisement) override;
 
-  void OnSetAdvertisingInterval();
+  void OnSetAdvertisingInterval(FastInitType type);
   void OnSetAdvertisingIntervalError(
+      FastInitType type,
       device::BluetoothAdvertisement::ErrorCode code);
-  void RegisterAdvertisement();
+  void RegisterAdvertisement(FastInitType type);
   void OnRegisterAdvertisement(
       scoped_refptr<device::BluetoothAdvertisement> advertisement);
   void OnRegisterAdvertisementError(
@@ -70,7 +78,11 @@
   void OnUnregisterAdvertisement();
   void OnUnregisterAdvertisementError(
       device::BluetoothAdvertisement::ErrorCode error_code);
-  uint8_t GenerateFastInitV1Metadata();
+
+  // Fast Init V1 metadata has 2 bytes, in format
+  // [ version (3 bits) | type (3 bits) | uwb_enable (1 bit) | reserved (1 bit),
+  // adjusted_tx_power (1 byte) ].
+  std::vector<uint8_t> GenerateFastInitV1Metadata(FastInitType type);
 
   scoped_refptr<device::BluetoothAdapter> adapter_;
   scoped_refptr<device::BluetoothAdvertisement> advertisement_;
diff --git a/chrome/browser/nearby_sharing/fast_initiation_manager_unittest.cc b/chrome/browser/nearby_sharing/fast_initiation_manager_unittest.cc
index ba3d88a..8bfd87f 100644
--- a/chrome/browser/nearby_sharing/fast_initiation_manager_unittest.cc
+++ b/chrome/browser/nearby_sharing/fast_initiation_manager_unittest.cc
@@ -29,6 +29,14 @@
 const int64_t kDefaultAdvertisingInterval = 0;
 #endif
 
+// Metadata bytes translate to 0b00000000 and 0b10111110, indicating "version
+// 0", "type 0 (notify)", and "transmission power of -66".
+const uint8_t kFastInitMetadataTypeNotify[] = {0x00, 0xBE};
+
+// Metadata bytes translate to 0b00000100 and 0b10111110, indicating "version
+// 0", "type 1 (silent)", and "transmission power of -66".
+const uint8_t kFastInitMetadataTypeSilent[] = {0x04, 0xBE};
+
 }  // namespace
 
 struct RegisterAdvertisementArgs {
@@ -82,6 +90,27 @@
   ~MockBluetoothAdapterWithAdvertisements() override = default;
 };
 
+class FakeBluetoothAdvertisement : public device::BluetoothAdvertisement {
+ public:
+  // device::BluetoothAdvertisement:
+  void Unregister(const SuccessCallback& success_callback,
+                  const ErrorCallback& error_callback) override {
+    success_callback.Run();
+  }
+
+  bool HasObserver(Observer* observer) {
+    return observers_.HasObserver(observer);
+  }
+
+  void ReleaseAdvertisement() {
+    for (auto& observer : observers_)
+      observer.AdvertisementReleased(this);
+  }
+
+ protected:
+  ~FakeBluetoothAdvertisement() override = default;
+};
+
 class NearbySharingFastInitiationManagerTest : public testing::Test {
  public:
   NearbySharingFastInitiationManagerTest(
@@ -107,20 +136,15 @@
 
     fast_initiation_manager_ =
         std::make_unique<FastInitiationManager>(mock_adapter_);
-
-    called_on_start_advertising_ = false;
-    called_on_start_advertising_error_ = false;
-    called_on_stop_advertising_ = false;
   }
 
   void OnAdapterRegisterAdvertisement(RegisterAdvertisementArgs* args) {
     register_args_ = base::WrapUnique(args);
   }
 
-  uint8_t GenerateFastInitV1Metadata() { return 0x00; }
-
-  void StartAdvertising() {
+  void StartAdvertising(FastInitiationManager::FastInitType type) {
     fast_initiation_manager_->StartAdvertising(
+        type,
         base::BindOnce(
             &NearbySharingFastInitiationManagerTest::OnStartAdvertising,
             base::Unretained(this)),
@@ -131,11 +155,22 @@
         std::make_unique<device::BluetoothAdvertisement::UUIDList>();
     service_uuid_list->push_back(kNearbySharingFastInitiationServiceUuid);
     EXPECT_EQ(*service_uuid_list, register_args_->service_uuids);
-    auto payload = std::vector<uint8_t>(std::begin(kNearbySharingFastPairId),
-                                        std::end(kNearbySharingFastPairId));
-    payload.push_back(GenerateFastInitV1Metadata());
+
+    auto expected_payload =
+        std::vector<uint8_t>(std::begin(kNearbySharingFastPairId),
+                             std::end(kNearbySharingFastPairId));
+    if (type == FastInitiationManager::FastInitType::kNotify) {
+      expected_payload.insert(std::end(expected_payload),
+                              std::begin(kFastInitMetadataTypeNotify),
+                              std::end(kFastInitMetadataTypeNotify));
+    } else {
+      expected_payload.insert(std::end(expected_payload),
+                              std::begin(kFastInitMetadataTypeSilent),
+                              std::end(kFastInitMetadataTypeSilent));
+    }
+
     EXPECT_EQ(
-        payload,
+        expected_payload,
         register_args_->service_data[kNearbySharingFastInitiationServiceUuid]);
   }
 
@@ -176,21 +211,41 @@
   scoped_refptr<NiceMock<MockBluetoothAdapterWithAdvertisements>> mock_adapter_;
   std::unique_ptr<FastInitiationManager> fast_initiation_manager_;
   std::unique_ptr<RegisterAdvertisementArgs> register_args_;
-  bool called_on_start_advertising_;
-  bool called_on_start_advertising_error_;
-  bool called_on_stop_advertising_;
+  bool called_on_start_advertising_ = false;
+  bool called_on_start_advertising_error_ = false;
+  bool called_on_stop_advertising_ = false;
   size_t set_advertising_interval_call_count_ = 0u;
   int64_t last_advertising_interval_min_ = 0;
   int64_t last_advertising_interval_max_ = 0;
 };
 
-TEST_F(NearbySharingFastInitiationManagerTest, TestStartAdvertising_Success) {
-  StartAdvertising();
-  register_args_->callback.Run(
-      base::MakeRefCounted<device::MockBluetoothAdvertisement>());
+TEST_F(NearbySharingFastInitiationManagerTest,
+       TestStartAdvertising_Success_TypeNotify) {
+  StartAdvertising(FastInitiationManager::FastInitType::kNotify);
+  auto fake_advertisement = base::MakeRefCounted<FakeBluetoothAdvertisement>();
+  register_args_->callback.Run(fake_advertisement);
+
   EXPECT_TRUE(called_on_start_advertising());
   EXPECT_FALSE(called_on_start_advertising_error());
   EXPECT_FALSE(called_on_stop_advertising());
+  EXPECT_TRUE(fake_advertisement->HasObserver(fast_initiation_manager_.get()));
+#if defined(CHROME_OS)
+  EXPECT_EQ(1u, set_advertising_interval_call_count());
+  EXPECT_EQ(kFastInitAdvertisingInterval, last_advertising_interval_min());
+  EXPECT_EQ(kFastInitAdvertisingInterval, last_advertising_interval_max());
+#endif
+}
+
+TEST_F(NearbySharingFastInitiationManagerTest,
+       TestStartAdvertising_Success_TypeSilent) {
+  StartAdvertising(FastInitiationManager::FastInitType::kSilent);
+  auto fake_advertisement = base::MakeRefCounted<FakeBluetoothAdvertisement>();
+  register_args_->callback.Run(fake_advertisement);
+
+  EXPECT_TRUE(called_on_start_advertising());
+  EXPECT_FALSE(called_on_start_advertising_error());
+  EXPECT_FALSE(called_on_stop_advertising());
+  EXPECT_TRUE(fake_advertisement->HasObserver(fast_initiation_manager_.get()));
 #if defined(CHROME_OS)
   EXPECT_EQ(1u, set_advertising_interval_call_count());
   EXPECT_EQ(kFastInitAdvertisingInterval, last_advertising_interval_min());
@@ -199,9 +254,10 @@
 }
 
 TEST_F(NearbySharingFastInitiationManagerTest, TestStartAdvertising_Error) {
-  StartAdvertising();
+  StartAdvertising(FastInitiationManager::FastInitType::kNotify);
   register_args_->error_callback.Run(device::BluetoothAdvertisement::ErrorCode::
                                          INVALID_ADVERTISEMENT_ERROR_CODE);
+
   EXPECT_FALSE(called_on_start_advertising());
   EXPECT_TRUE(called_on_start_advertising_error());
   EXPECT_FALSE(called_on_stop_advertising());
@@ -213,9 +269,10 @@
 }
 
 TEST_F(NearbySharingFastInitiationManagerTest, TestStopAdvertising) {
-  StartAdvertising();
-  register_args_->callback.Run(
-      base::MakeRefCounted<device::MockBluetoothAdvertisement>());
+  StartAdvertising(FastInitiationManager::FastInitType::kNotify);
+  auto fake_advertisement = base::MakeRefCounted<FakeBluetoothAdvertisement>();
+  register_args_->callback.Run(fake_advertisement);
+
 #if defined(CHROME_OS)
   EXPECT_EQ(1u, set_advertising_interval_call_count());
   EXPECT_EQ(kFastInitAdvertisingInterval, last_advertising_interval_min());
@@ -233,3 +290,23 @@
   EXPECT_EQ(kDefaultAdvertisingInterval, last_advertising_interval_max());
 #endif
 }
+
+TEST_F(NearbySharingFastInitiationManagerTest, TestAdvertisementReleased) {
+  StartAdvertising(FastInitiationManager::FastInitType::kNotify);
+  auto fake_advertisement = base::MakeRefCounted<FakeBluetoothAdvertisement>();
+  register_args_->callback.Run(fake_advertisement);
+
+  EXPECT_TRUE(fake_advertisement->HasObserver(fast_initiation_manager_.get()));
+
+  fake_advertisement->ReleaseAdvertisement();
+
+  EXPECT_TRUE(called_on_start_advertising());
+  EXPECT_FALSE(called_on_start_advertising_error());
+  EXPECT_FALSE(called_on_stop_advertising());
+  EXPECT_FALSE(fake_advertisement->HasObserver(fast_initiation_manager_.get()));
+#if defined(CHROME_OS)
+  EXPECT_EQ(2u, set_advertising_interval_call_count());
+  EXPECT_EQ(kDefaultAdvertisingInterval, last_advertising_interval_min());
+  EXPECT_EQ(kDefaultAdvertisingInterval, last_advertising_interval_max());
+#endif
+}
diff --git a/chrome/browser/nearby_sharing/nearby_notification_handler.cc b/chrome/browser/nearby_sharing/nearby_notification_handler.cc
new file mode 100644
index 0000000..ecd1a094
--- /dev/null
+++ b/chrome/browser/nearby_sharing/nearby_notification_handler.cc
@@ -0,0 +1,38 @@
+// Copyright 2020 The Chromium 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/nearby_sharing/nearby_notification_handler.h"
+
+#include <utility>
+
+#include "base/callback.h"
+
+NearbyNotificationHandler::NearbyNotificationHandler() = default;
+
+NearbyNotificationHandler::~NearbyNotificationHandler() = default;
+
+void NearbyNotificationHandler::OnClick(
+    Profile* profile,
+    const GURL& origin,
+    const std::string& notification_id,
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply,
+    base::OnceClosure completed_closure) {
+  // TODO(crbug.com/1102348): Route to NearbySharingService.
+  std::move(completed_closure).Run();
+}
+
+void NearbyNotificationHandler::OnClose(Profile* profile,
+                                        const GURL& origin,
+                                        const std::string& notification_id,
+                                        bool by_user,
+                                        base::OnceClosure completed_closure) {
+  // TODO(crbug.com/1102348): Route to NearbySharingService.
+  std::move(completed_closure).Run();
+}
+
+void NearbyNotificationHandler::OpenSettings(Profile* profile,
+                                             const GURL& origin) {
+  // TODO(crbug.com/1102348): Route to NearbySharingService.
+}
diff --git a/chrome/browser/nearby_sharing/nearby_notification_handler.h b/chrome/browser/nearby_sharing/nearby_notification_handler.h
new file mode 100644
index 0000000..7d2a7aa
--- /dev/null
+++ b/chrome/browser/nearby_sharing/nearby_notification_handler.h
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium 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_NEARBY_SHARING_NEARBY_NOTIFICATION_HANDLER_H_
+#define CHROME_BROWSER_NEARBY_SHARING_NEARBY_NOTIFICATION_HANDLER_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/notifications/notification_handler.h"
+#include "url/gurl.h"
+
+class Profile;
+
+// Handles NEARBY_SHARE notification actions.
+class NearbyNotificationHandler : public NotificationHandler {
+ public:
+  NearbyNotificationHandler();
+  NearbyNotificationHandler(const NearbyNotificationHandler&) = delete;
+  NearbyNotificationHandler& operator=(const NearbyNotificationHandler&) =
+      delete;
+  ~NearbyNotificationHandler() override;
+
+  // NotificationHandler:
+  void OnClick(Profile* profile,
+               const GURL& origin,
+               const std::string& notification_id,
+               const base::Optional<int>& action_index,
+               const base::Optional<base::string16>& reply,
+               base::OnceClosure completed_closure) override;
+  void OnClose(Profile* profile,
+               const GURL& origin,
+               const std::string& notification_id,
+               bool by_user,
+               base::OnceClosure completed_closure) override;
+  void OpenSettings(Profile* profile, const GURL& origin) override;
+};
+
+#endif  // CHROME_BROWSER_NEARBY_SHARING_NEARBY_NOTIFICATION_HANDLER_H_
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager.cc b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
new file mode 100644
index 0000000..fa4e645
--- /dev/null
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
@@ -0,0 +1,124 @@
+// Copyright 2020 The Chromium 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/nearby_sharing/nearby_notification_manager.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/notifications/notification_display_service.h"
+#include "chrome/browser/notifications/notification_display_service_factory.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/message_center/public/cpp/notification.h"
+#include "ui/message_center/public/cpp/notification_types.h"
+#include "ui/strings/grit/ui_strings.h"
+
+namespace {
+
+constexpr char kNearbyNotificationId[] = "chrome://nearby";
+constexpr char kNearbyNotifier[] = "nearby";
+
+FileAttachment::Type GetCommonFileAttachmentType(
+    const std::vector<FileAttachment>& files) {
+  if (files.empty())
+    return FileAttachment::Type::kUnknown;
+
+  FileAttachment::Type type = files[0].type();
+  for (size_t i = 1; i < files.size(); ++i) {
+    if (files[i].type() != type)
+      return FileAttachment::Type::kUnknown;
+  }
+  return type;
+}
+
+TextAttachment::Type GetCommonTextAttachmentType(
+    const std::vector<TextAttachment>& texts) {
+  if (texts.empty())
+    return TextAttachment::Type::kText;
+
+  TextAttachment::Type type = texts[0].type();
+  for (size_t i = 1; i < texts.size(); ++i) {
+    if (texts[i].type() != type)
+      return TextAttachment::Type::kText;
+  }
+  return type;
+}
+
+base::string16 GetUnknownAttachmentsString(size_t count) {
+  // TODO(crbug.com/1102348): Provide translated string.
+  return base::string16();
+}
+
+base::string16 GetFileAttachmentsString(
+    const std::vector<FileAttachment>& files) {
+  // TODO(crbug.com/1102348): Add translated special cases for file types.
+  switch (GetCommonFileAttachmentType(files)) {
+    default:
+      return GetUnknownAttachmentsString(files.size());
+  }
+}
+
+base::string16 GetTextAttachmentsString(
+    const std::vector<TextAttachment>& texts) {
+  // TODO(crbug.com/1102348): Add translated special cases for text types.
+  switch (GetCommonTextAttachmentType(texts)) {
+    default:
+      return GetUnknownAttachmentsString(texts.size());
+  }
+}
+
+base::string16 GetAttachmentsString(const ShareTarget& share_target) {
+  size_t file_count = share_target.file_attachments().size();
+  size_t text_count = share_target.text_attachments().size();
+
+  if (file_count > 0 && text_count == 0)
+    return GetFileAttachmentsString(share_target.file_attachments());
+
+  if (text_count > 0 && file_count == 0)
+    return GetTextAttachmentsString(share_target.text_attachments());
+
+  return GetUnknownAttachmentsString(file_count + text_count);
+}
+
+}  // namespace
+
+NearbyNotificationManager::NearbyNotificationManager(Profile* profile)
+    : profile_(profile) {}
+
+NearbyNotificationManager::~NearbyNotificationManager() = default;
+
+void NearbyNotificationManager::ShowProgress(
+    const ShareTarget& share_target,
+    const TransferMetadata& transfer_metadata) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  message_center::RichNotificationData rich_notification_data;
+  rich_notification_data.never_timeout = true;
+
+  message_center::Notification notification(
+      message_center::NOTIFICATION_TYPE_PROGRESS, kNearbyNotificationId,
+      // TODO(crbug.com/1102348): Provide translated title.
+      /*title=*/GetAttachmentsString(share_target),
+      /*message=*/base::string16(),
+      /*icon=*/gfx::Image(),
+      // TODO(crbug.com/1102348): Provide translated source.
+      /*display_source=*/base::string16(),
+      /*origin_url=*/GURL(),
+      message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
+                                 kNearbyNotifier),
+      rich_notification_data,
+      /*delegate=*/nullptr);
+
+  // TODO(crbug.com/1102348): Set Nearby Share icon.
+  notification.set_progress(100.0 * transfer_metadata.progress());
+
+  std::vector<message_center::ButtonInfo> notification_actions;
+  notification_actions.emplace_back(l10n_util::GetStringUTF16(IDS_APP_CANCEL));
+  notification.set_buttons(notification_actions);
+
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->Display(
+      NotificationHandler::Type::NEARBY_SHARE, notification,
+      /*metadata=*/nullptr);
+}
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager.h b/chrome/browser/nearby_sharing/nearby_notification_manager.h
new file mode 100644
index 0000000..c2827f6
--- /dev/null
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium 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_NEARBY_SHARING_NEARBY_NOTIFICATION_MANAGER_H_
+#define CHROME_BROWSER_NEARBY_SHARING_NEARBY_NOTIFICATION_MANAGER_H_
+
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "chrome/browser/nearby_sharing/share_target.h"
+#include "chrome/browser/nearby_sharing/transfer_metadata.h"
+
+class Profile;
+
+// Manages notifications shown for Nearby Share. Only a single notification will
+// be shown as simultaneous connections are not supported. All methods should be
+// called from the UI thread.
+class NearbyNotificationManager {
+ public:
+  explicit NearbyNotificationManager(Profile* profile);
+  ~NearbyNotificationManager();
+
+  void ShowProgress(const ShareTarget& share_target,
+                    const TransferMetadata& transfer_metadata);
+
+ private:
+  Profile* profile_;
+};
+
+#endif  // CHROME_BROWSER_NEARBY_SHARING_NEARBY_NOTIFICATION_MANAGER_H_
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
new file mode 100644
index 0000000..47954fd9
--- /dev/null
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright 2020 The Chromium 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/nearby_sharing/nearby_notification_manager.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/browser_features.h"
+#include "chrome/browser/nearby_sharing/share_target.h"
+#include "chrome/browser/nearby_sharing/transfer_metadata.h"
+#include "chrome/browser/notifications/notification_display_service_tester.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/strings/grit/ui_strings.h"
+
+namespace {
+
+class ShareTargetBuilder {
+ public:
+  ShareTargetBuilder() = default;
+  ~ShareTargetBuilder() = default;
+
+  ShareTargetBuilder& set_device_name(const std::string& device_name) {
+    device_name_ = device_name;
+    return *this;
+  }
+
+  ShareTargetBuilder& add_attachment(TextAttachment attachment) {
+    text_attachments_.push_back(std::move(attachment));
+    return *this;
+  }
+
+  ShareTargetBuilder& add_attachment(FileAttachment attachment) {
+    file_attachments_.push_back(std::move(attachment));
+    return *this;
+  }
+
+  ShareTarget build() const {
+    return ShareTarget(device_name_,
+                       /*image_url=*/GURL(), ShareTarget::Type::kPhone,
+                       text_attachments_, file_attachments_,
+                       /*is_incoming=*/false,
+                       /*full_name=*/base::nullopt,
+                       /*is_known=*/false);
+  }
+
+ private:
+  std::string device_name_;
+  std::vector<TextAttachment> text_attachments_;
+  std::vector<FileAttachment> file_attachments_;
+};
+
+class TransferMetadataBuilder {
+ public:
+  TransferMetadataBuilder() = default;
+  ~TransferMetadataBuilder() = default;
+
+  TransferMetadataBuilder& set_progress(double progress) {
+    progress_ = progress;
+    return *this;
+  }
+
+  TransferMetadata build() const {
+    return TransferMetadata(TransferMetadata::Status::kInProgress, progress_,
+                            /*token=*/base::nullopt,
+                            /*is_original=*/false,
+                            /*is_final_status=*/false);
+  }
+
+ private:
+  double progress_ = 0;
+};
+
+class NearbyNotificationManagerTest : public testing::Test {
+ public:
+  NearbyNotificationManagerTest() {
+    scoped_feature_list_.InitAndEnableFeature(features::kNearbySharing);
+    notification_tester_ =
+        std::make_unique<NotificationDisplayServiceTester>(&profile_);
+  }
+  ~NearbyNotificationManagerTest() override = default;
+
+  NearbyNotificationManager* manager() { return &manager_; }
+
+  std::vector<message_center::Notification> GetDisplayedNotifications() {
+    return notification_tester_->GetDisplayedNotificationsForType(
+        NotificationHandler::Type::NEARBY_SHARE);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  content::BrowserTaskEnvironment task_environment_;
+  TestingProfile profile_;
+  std::unique_ptr<NotificationDisplayServiceTester> notification_tester_;
+  NearbyNotificationManager manager_{&profile_};
+};
+
+}  // namespace
+
+TEST_F(NearbyNotificationManagerTest, ShowProgress_ShowsNotification) {
+  ShareTarget share_target = ShareTargetBuilder().build();
+  TransferMetadata transfer_metadata = TransferMetadataBuilder().build();
+
+  manager()->ShowProgress(share_target, transfer_metadata);
+
+  std::vector<message_center::Notification> notifications =
+      GetDisplayedNotifications();
+  ASSERT_EQ(1u, notifications.size());
+
+  const message_center::Notification& notification = notifications[0];
+  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, notification.type());
+  EXPECT_EQ(base::string16(), notification.message());
+  EXPECT_TRUE(notification.icon().IsEmpty());
+  EXPECT_EQ(GURL(), notification.origin_url());
+  EXPECT_TRUE(notification.never_timeout());
+  EXPECT_FALSE(notification.renotify());
+
+  const std::vector<message_center::ButtonInfo>& buttons =
+      notification.buttons();
+  ASSERT_EQ(1u, buttons.size());
+
+  const message_center::ButtonInfo& cancel_button = buttons[0];
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_APP_CANCEL), cancel_button.title);
+}
+
+TEST_F(NearbyNotificationManagerTest, ShowProgress_ShowsProgress) {
+  double progress = 0.75;
+
+  ShareTarget share_target = ShareTargetBuilder().build();
+  TransferMetadata transfer_metadata =
+      TransferMetadataBuilder().set_progress(progress).build();
+
+  manager()->ShowProgress(share_target, transfer_metadata);
+
+  message_center::Notification notification = GetDisplayedNotifications()[0];
+  EXPECT_EQ(100.0 * progress, notification.progress());
+}
+
+TEST_F(NearbyNotificationManagerTest, ShowProgress_UpdatesProgress) {
+  ShareTarget share_target = ShareTargetBuilder().build();
+  TransferMetadataBuilder transfer_metadata_builder;
+  transfer_metadata_builder.set_progress(0.75);
+
+  manager()->ShowProgress(share_target, transfer_metadata_builder.build());
+
+  double progress = 0.5;
+  transfer_metadata_builder.set_progress(progress);
+  manager()->ShowProgress(share_target, transfer_metadata_builder.build());
+
+  std::vector<message_center::Notification> notifications =
+      GetDisplayedNotifications();
+  ASSERT_EQ(1u, notifications.size());
+
+  const message_center::Notification& notification = notifications[0];
+  EXPECT_EQ(100.0 * progress, notification.progress());
+}
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
index 0cfc447..7d2e938 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.cc
@@ -113,7 +113,8 @@
     std::unique_ptr<NearbyConnectionsManager> nearby_connections_manager)
     : prefs_(prefs),
       profile_(profile),
-      nearby_connections_manager_(std::move(nearby_connections_manager)) {
+      nearby_connections_manager_(std::move(nearby_connections_manager)),
+      nearby_notification_manager_(profile) {
   DCHECK(prefs_);
   DCHECK(profile_);
   DCHECK(nearby_connections_manager_);
@@ -394,7 +395,11 @@
 
   fast_initiation_manager_ =
       FastInitiationManager::Factory::Create(bluetooth_adapter_);
+
+  // TODO(crbug.com/1100686): Determine whether to call StartAdvertising() with
+  // kNotify or kSilent.
   fast_initiation_manager_->StartAdvertising(
+      FastInitiationManager::FastInitType::kNotify,
       base::BindOnce(
           &NearbySharingServiceImpl::OnStartFastInitiationAdvertising,
           weak_ptr_factory_.GetWeakPtr()),
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
index 95c2984..a6d9eaf0 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl.h
@@ -15,6 +15,7 @@
 #include "base/scoped_observer.h"
 #include "chrome/browser/nearby_sharing/nearby_connections_manager.h"
 #include "chrome/browser/nearby_sharing/nearby_constants.h"
+#include "chrome/browser/nearby_sharing/nearby_notification_manager.h"
 #include "chrome/browser/nearby_sharing/nearby_process_manager.h"
 #include "chrome/browser/nearby_sharing/nearby_sharing_service.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -111,6 +112,7 @@
   std::unique_ptr<FastInitiationManager> fast_initiation_manager_;
   StatusCodesCallback register_send_surface_callback_;
   StatusCodesCallback unregister_send_surface_callback_;
+  NearbyNotificationManager nearby_notification_manager_;
 
   // A list of foreground receivers.
   base::ObserverList<TransferUpdateCallback> foreground_receive_callbacks_;
diff --git a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
index d1debce..cf106d0 100644
--- a/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc
@@ -49,7 +49,8 @@
     std::move(on_destroy_callback_).Run();
   }
 
-  void StartAdvertising(base::OnceCallback<void()> callback,
+  void StartAdvertising(FastInitType type,
+                        base::OnceCallback<void()> callback,
                         base::OnceCallback<void()> error_callback) override {
     ++start_advertising_call_count_;
     if (should_succeed_on_start_)
diff --git a/chrome/browser/nearby_sharing/share_target.h b/chrome/browser/nearby_sharing/share_target.h
index 8df29a5..8ccb609 100644
--- a/chrome/browser/nearby_sharing/share_target.h
+++ b/chrome/browser/nearby_sharing/share_target.h
@@ -30,25 +30,25 @@
   ShareTarget(const ShareTarget&);
   ShareTarget& operator=(const ShareTarget&);
 
-  int id() { return id_; }
-  const std::string& device_name() { return device_name_; }
+  int id() const { return id_; }
+  const std::string& device_name() const { return device_name_; }
 
   // Returns a Uri that points to an image of the ShareTarget, if one exists.
-  const base::Optional<GURL>& image_url() { return image_url_; }
+  const base::Optional<GURL>& image_url() const { return image_url_; }
 
-  Type type() { return type_; }
-  const std::vector<TextAttachment>& text_attachments() {
+  Type type() const { return type_; }
+  const std::vector<TextAttachment>& text_attachments() const {
     return text_attachments_;
   }
-  const std::vector<FileAttachment>& file_attachments() {
+  const std::vector<FileAttachment>& file_attachments() const {
     return file_attachments_;
   }
-  bool is_incoming() { return is_incoming_; }
-  const base::Optional<std::string>& full_name() { return full_name_; }
+  bool is_incoming() const { return is_incoming_; }
+  const base::Optional<std::string>& full_name() const { return full_name_; }
 
   // Returns True if local device has the PublicCertificate the remote device is
   // advertising.
-  bool is_known() { return is_known_; }
+  bool is_known() const { return is_known_; }
 
  private:
   int id_;
diff --git a/chrome/browser/nearby_sharing/transfer_metadata.h b/chrome/browser/nearby_sharing/transfer_metadata.h
index 6b82fba..39772961 100644
--- a/chrome/browser/nearby_sharing/transfer_metadata.h
+++ b/chrome/browser/nearby_sharing/transfer_metadata.h
@@ -43,18 +43,18 @@
   TransferMetadata(const TransferMetadata&);
   TransferMetadata& operator=(const TransferMetadata&);
 
-  Status status() { return status_; }
-  float progress() { return progress_; }
+  Status status() const { return status_; }
+  float progress() const { return progress_; }
 
   // Represents the UKey2 token from Nearby Connection. base::nullopt if no
   // UKey2 comparison is needed for this transfer.
-  const base::Optional<std::string>& token() { return token_; }
+  const base::Optional<std::string>& token() const { return token_; }
 
   // True if this |TransferMetadata| has not been seen.
-  bool is_original() { return is_original_; }
+  bool is_original() const { return is_original_; }
 
   // True if this |TransferMetadata| is the last status for this transfer.
-  bool is_final_status() { return is_final_status_; }
+  bool is_final_status() const { return is_final_status_; }
 
  private:
   Status status_;
diff --git a/chrome/browser/net/variations_http_headers_browsertest.cc b/chrome/browser/net/variations_http_headers_browsertest.cc
index d96eaa2a..8cad5008 100644
--- a/chrome/browser/net/variations_http_headers_browsertest.cc
+++ b/chrome/browser/net/variations_http_headers_browsertest.cc
@@ -5,6 +5,7 @@
 #include "components/variations/net/variations_http_headers.h"
 
 #include <map>
+#include <memory>
 
 #include "base/bind.h"
 #include "base/macros.h"
@@ -80,7 +81,7 @@
 
   void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
     static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
-        new VariationHeaderSetter());
+        std::make_unique<VariationHeaderSetter>());
   }
 
   void SetUp() override {
diff --git a/chrome/browser/notifications/notification_display_service_impl.cc b/chrome/browser/notifications/notification_display_service_impl.cc
index 85d20f18..f7fb6f2b 100644
--- a/chrome/browser/notifications/notification_display_service_impl.cc
+++ b/chrome/browser/notifications/notification_display_service_impl.cc
@@ -8,17 +8,18 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
+#include "chrome/browser/browser_features.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/notifications/non_persistent_notification_handler.h"
 #include "chrome/browser/notifications/notification_display_service_factory.h"
 #include "chrome/browser/notifications/notification_platform_bridge.h"
 #include "chrome/browser/notifications/persistent_notification_handler.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sharing/sharing_notification_handler.h"
 #include "chrome/browser/updates/announcement_notification/announcement_notification_handler.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
@@ -37,7 +38,9 @@
 #endif
 
 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
+#include "chrome/browser/nearby_sharing/nearby_notification_handler.h"
 #include "chrome/browser/send_tab_to_self/desktop_notification_handler.h"
+#include "chrome/browser/sharing/sharing_notification_handler.h"
 #endif
 
 #if defined(OS_WIN)
@@ -166,6 +169,11 @@
                            std::make_unique<SharingNotificationHandler>());
     AddNotificationHandler(NotificationHandler::Type::ANNOUNCEMENT,
                            std::make_unique<AnnouncementNotificationHandler>());
+
+    if (base::FeatureList::IsEnabled(features::kNearbySharing)) {
+      AddNotificationHandler(NotificationHandler::Type::NEARBY_SHARE,
+                             std::make_unique<NearbyNotificationHandler>());
+    }
 #endif
   }
 
diff --git a/chrome/browser/notifications/notification_handler.h b/chrome/browser/notifications/notification_handler.h
index 1363f59f..78264f0c 100644
--- a/chrome/browser/notifications/notification_handler.h
+++ b/chrome/browser/notifications/notification_handler.h
@@ -37,7 +37,8 @@
     //                          // user via a notification.
     SHARING = 6,
     ANNOUNCEMENT = 7,
-    MAX = ANNOUNCEMENT,
+    NEARBY_SHARE = 8,
+    MAX = NEARBY_SHARE,
   };
 
   virtual ~NotificationHandler();
diff --git a/chrome/browser/optimization_guide/optimization_guide_permissions_util.cc b/chrome/browser/optimization_guide/optimization_guide_permissions_util.cc
index 107c75e..231577c 100644
--- a/chrome/browser/optimization_guide/optimization_guide_permissions_util.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_permissions_util.cc
@@ -6,6 +6,8 @@
 
 #include <memory>
 
+#include "base/feature_list.h"
+#include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -63,6 +65,9 @@
   if (!optimization_guide::features::IsRemoteFetchingEnabled())
     return false;
 
+  if (IsRemoteFetchingExplicitlyAllowedForPerformanceInfo())
+    return true;
+
   if (IsUserDataSaverEnabledAndAllowedToFetchFromRemoteService(profile))
     return true;
 
diff --git a/chrome/browser/optimization_guide/optimization_guide_permissions_util_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_permissions_util_unittest.cc
index db91d35..7af04d41 100644
--- a/chrome/browser/optimization_guide/optimization_guide_permissions_util_unittest.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_permissions_util_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/unified_consent/unified_consent_service_factory.h"
@@ -189,12 +190,27 @@
 }
 
 TEST_F(OptimizationGuidePermissionsUtilTest,
+       IsUserPermittedToFetchHintsPerformanceInfoFlagExplicitlyAllows) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitWithFeatures(
+      {optimization_guide::features::kRemoteOptimizationGuideFetching,
+       kContextMenuPerformanceInfoAndRemoteHintFetching},
+      {});
+  SetDataSaverEnabled(false);
+  SetSyncServiceEnabled(false);
+
+  EXPECT_FALSE(profile()->IsOffTheRecord());
+  EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(profile()));
+}
+
+TEST_F(OptimizationGuidePermissionsUtilTest,
        IsUserPermittedToFetchHintsAllConsentsEnabledIncognitoProfile) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitWithFeatures(
       {optimization_guide::features::kRemoteOptimizationGuideFetching,
        optimization_guide::features::
-           kRemoteOptimizationGuideFetchingAnonymousDataConsent},
+           kRemoteOptimizationGuideFetchingAnonymousDataConsent,
+       kContextMenuPerformanceInfoAndRemoteHintFetching},
       {});
   SetDataSaverEnabled(true);
   SetInfobarSeen(true);
diff --git a/chrome/browser/optimization_guide/prediction/decision_tree_prediction_model.cc b/chrome/browser/optimization_guide/prediction/decision_tree_prediction_model.cc
deleted file mode 100644
index 96f733d..0000000
--- a/chrome/browser/optimization_guide/prediction/decision_tree_prediction_model.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/optimization_guide/prediction/decision_tree_prediction_model.h"
-
-#include <utility>
-
-namespace optimization_guide {
-
-DecisionTreePredictionModel::DecisionTreePredictionModel(
-    std::unique_ptr<optimization_guide::proto::PredictionModel>
-        prediction_model)
-    : PredictionModel(std::move(prediction_model)) {}
-
-DecisionTreePredictionModel::~DecisionTreePredictionModel() = default;
-
-bool DecisionTreePredictionModel::ValidatePredictionModel() const {
-  // Only the top-level ensemble or decision tree must have a threshold. Any
-  // submodels of an ensemble will have model weights but no threshold.
-  if (!model_->has_threshold())
-    return false;
-  return ValidateModel(*model_.get());
-}
-
-bool DecisionTreePredictionModel::ValidateModel(
-    const proto::Model& model) const {
-  if (model.has_ensemble()) {
-    return ValidateEnsembleModel(model.ensemble());
-  }
-  if (model.has_decision_tree()) {
-    return ValidateDecisionTree(model.decision_tree());
-  }
-  return false;
-}
-
-bool DecisionTreePredictionModel::ValidateEnsembleModel(
-    const proto::Ensemble& ensemble) const {
-  if (ensemble.members_size() == 0)
-    return false;
-
-  for (const auto& member : ensemble.members()) {
-    if (!ValidateModel(member.submodel())) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool DecisionTreePredictionModel::ValidateDecisionTree(
-    const proto::DecisionTree& tree) const {
-  if (tree.nodes_size() == 0)
-    return false;
-  return ValidateTreeNode(tree, tree.nodes(0), 0);
-}
-
-bool DecisionTreePredictionModel::ValidateLeaf(const proto::Leaf& leaf) const {
-  return leaf.has_vector() && leaf.vector().value_size() == 1 &&
-         leaf.vector().value(0).has_double_value();
-}
-
-bool DecisionTreePredictionModel::ValidateInequalityTest(
-    const proto::InequalityTest& inequality_test) const {
-  if (!inequality_test.has_threshold())
-    return false;
-  if (!inequality_test.threshold().has_float_value())
-    return false;
-  if (!inequality_test.has_feature_id())
-    return false;
-  if (!inequality_test.feature_id().has_id())
-    return false;
-  if (!inequality_test.has_type())
-    return false;
-  return true;
-}
-
-bool DecisionTreePredictionModel::ValidateTreeNode(
-    const proto::DecisionTree& tree,
-    const proto::TreeNode& node,
-    const int& node_index) const {
-  if (node.has_leaf())
-    return ValidateLeaf(node.leaf());
-
-  if (!node.has_binary_node())
-    return false;
-
-  proto::BinaryNode binary_node = node.binary_node();
-  if (!binary_node.has_inequality_left_child_test())
-    return false;
-
-  if (!ValidateInequalityTest(binary_node.inequality_left_child_test()))
-    return false;
-
-  if (!binary_node.left_child_id().has_value())
-    return false;
-  if (!binary_node.right_child_id().has_value())
-    return false;
-
-  if (binary_node.left_child_id().value() >= tree.nodes_size())
-    return false;
-  if (binary_node.right_child_id().value() >= tree.nodes_size())
-    return false;
-
-  // Assure that no parent has an child index less than itself in order to
-  // prevent loops.
-  if (node_index >= binary_node.left_child_id().value())
-    return false;
-  if (node_index >= binary_node.right_child_id().value())
-    return false;
-
-  if (!ValidateTreeNode(tree, tree.nodes(binary_node.left_child_id().value()),
-                        binary_node.left_child_id().value())) {
-    return false;
-  }
-  if (!ValidateTreeNode(tree, tree.nodes(binary_node.right_child_id().value()),
-                        binary_node.right_child_id().value())) {
-    return false;
-  }
-  return true;
-}
-
-optimization_guide::OptimizationTargetDecision
-DecisionTreePredictionModel::Predict(
-    const base::flat_map<std::string, float>& model_features,
-    double* prediction_score) {
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  *prediction_score = 0.0;
-  // TODO(mcrouse): Add metrics to record if the model evaluation fails.
-  if (!EvaluateModel(*model_.get(), model_features, prediction_score))
-    return optimization_guide::OptimizationTargetDecision::kUnknown;
-  if (*prediction_score > model_->threshold().value())
-    return optimization_guide::OptimizationTargetDecision::kPageLoadMatches;
-  return optimization_guide::OptimizationTargetDecision::kPageLoadDoesNotMatch;
-}
-
-bool DecisionTreePredictionModel::TraverseTree(
-    const proto::DecisionTree& tree,
-    const proto::TreeNode& node,
-    const base::flat_map<std::string, float>& model_features,
-    double* result) {
-  if (node.has_leaf()) {
-    *result = node.leaf().vector().value(0).double_value();
-    return true;
-  }
-
-  proto::BinaryNode binary_node = node.binary_node();
-  float threshold =
-      binary_node.inequality_left_child_test().threshold().float_value();
-  std::string feature_name =
-      binary_node.inequality_left_child_test().feature_id().id().value();
-  auto it = model_features.find(feature_name);
-  if (it == model_features.end())
-    return false;
-  switch (binary_node.inequality_left_child_test().type()) {
-    case proto::InequalityTest::LESS_OR_EQUAL:
-      if (it->second <= threshold)
-        return TraverseTree(tree,
-                            tree.nodes(binary_node.left_child_id().value()),
-                            model_features, result);
-      return TraverseTree(tree,
-                          tree.nodes(binary_node.right_child_id().value()),
-                          model_features, result);
-    case proto::InequalityTest::LESS_THAN:
-      if (it->second < threshold)
-        return TraverseTree(tree,
-                            tree.nodes(binary_node.left_child_id().value()),
-                            model_features, result);
-      return TraverseTree(tree,
-                          tree.nodes(binary_node.right_child_id().value()),
-                          model_features, result);
-    case proto::InequalityTest::GREATER_OR_EQUAL:
-      if (it->second >= threshold)
-        return TraverseTree(tree,
-                            tree.nodes(binary_node.left_child_id().value()),
-                            model_features, result);
-      return TraverseTree(tree,
-                          tree.nodes(binary_node.right_child_id().value()),
-                          model_features, result);
-    case proto::InequalityTest::GREATER_THAN:
-      if (it->second > threshold)
-        return TraverseTree(tree,
-                            tree.nodes(binary_node.left_child_id().value()),
-                            model_features, result);
-      return TraverseTree(tree,
-                          tree.nodes(binary_node.right_child_id().value()),
-                          model_features, result);
-    default:
-      return false;
-  }
-  return false;
-}
-
-bool DecisionTreePredictionModel::EvaluateDecisionTree(
-    const proto::DecisionTree& tree,
-    const base::flat_map<std::string, float>& model_features,
-    double* result) {
-  if (TraverseTree(tree, tree.nodes(0), model_features, result)) {
-    *result *= tree.weight();
-    return true;
-  }
-  return false;
-}
-
-bool DecisionTreePredictionModel::EvaluateEnsembleModel(
-    const proto::Ensemble& ensemble,
-    const base::flat_map<std::string, float>& model_features,
-    double* result) {
-  if (ensemble.members_size() == 0)
-    return false;
-
-  double score = 0.0;
-  for (const auto& member : ensemble.members()) {
-    if (!EvaluateModel(member.submodel(), model_features, &score)) {
-      *result = 0.0;
-      return false;
-    }
-
-    *result += score;
-  }
-  *result = *result / ensemble.members_size();
-  return true;
-}
-
-bool DecisionTreePredictionModel::EvaluateModel(
-    const proto::Model& model,
-    const base::flat_map<std::string, float>& model_features,
-    double* result) {
-  DCHECK(result);
-  // Clear the result value.
-  *result = 0.0;
-
-  if (model.has_ensemble()) {
-    return EvaluateEnsembleModel(model.ensemble(), model_features, result);
-  }
-  if (model.has_decision_tree()) {
-    return EvaluateDecisionTree(model.decision_tree(), model_features, result);
-  }
-  return false;
-}
-
-}  // namespace optimization_guide
diff --git a/chrome/browser/optimization_guide/prediction/decision_tree_prediction_model.h b/chrome/browser/optimization_guide/prediction/decision_tree_prediction_model.h
deleted file mode 100644
index 986e025..0000000
--- a/chrome/browser/optimization_guide/prediction/decision_tree_prediction_model.h
+++ /dev/null
@@ -1,101 +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_OPTIMIZATION_GUIDE_PREDICTION_DECISION_TREE_PREDICTION_MODEL_H_
-#define CHROME_BROWSER_OPTIMIZATION_GUIDE_PREDICTION_DECISION_TREE_PREDICTION_MODEL_H_
-
-#include <memory>
-#include <string>
-
-#include "base/containers/flat_map.h"
-#include "base/containers/flat_set.h"
-#include "base/macros.h"
-#include "base/sequence_checker.h"
-#include "chrome/browser/optimization_guide/prediction/prediction_model.h"
-#include "components/optimization_guide/proto/models.pb.h"
-
-namespace optimization_guide {
-
-// A concrete PredictionModel capable of evaluating the decision tree model type
-// supported by the optimization guide.
-class DecisionTreePredictionModel : public PredictionModel {
- public:
-  explicit DecisionTreePredictionModel(
-      std::unique_ptr<optimization_guide::proto::PredictionModel>
-          prediction_model);
-
-  ~DecisionTreePredictionModel() override;
-
-  // PredictionModel implementation:
-  optimization_guide::OptimizationTargetDecision Predict(
-      const base::flat_map<std::string, float>& model_features,
-      double* prediction_score) override;
-
- private:
-  // Evaluates the provided model, either an ensemble or decision tree model,
-  // with the |model_features| and stores the output in |result|. Returns false
-  // if evaluation fails.
-  bool EvaluateModel(const proto::Model& model,
-                     const base::flat_map<std::string, float>& model_features,
-                     double* result);
-
-  // Evaluates the decision tree model with the |model_features| and
-  // stores the output in |result|. Returns false if the evaluation fails.
-  bool EvaluateDecisionTree(
-      const proto::DecisionTree& tree,
-      const base::flat_map<std::string, float>& model_features,
-      double* result);
-
-  // Evaluates an ensemble model with the |model_features| and
-  // stores the output in |result|. Returns false if the evaluation fails.
-  bool EvaluateEnsembleModel(
-      const proto::Ensemble& ensemble,
-      const base::flat_map<std::string, float>& model_features,
-      double* result);
-
-  // Performs a depth first traversal the  |tree| based on |model_features|
-  // and stores the value of the leaf in |result|. Returns false if the
-  // traversal or node evaluation fails.
-  bool TraverseTree(const proto::DecisionTree& tree,
-                    const proto::TreeNode& node,
-                    const base::flat_map<std::string, float>& model_features,
-                    double* result);
-
-  // PredictionModel implementation:
-  bool ValidatePredictionModel() const override;
-
-  // Validates a model or submodel of an ensemble. Returns
-  // false if the model is invalid.
-  bool ValidateModel(const proto::Model& model) const;
-
-  // Validates an ensemble model. Returns false if the ensemble
-  // if invalid.
-  bool ValidateEnsembleModel(const proto::Ensemble& ensemble) const;
-
-  // Validates a decision tree model. Returns false if the
-  // decision tree model is invalid.
-  bool ValidateDecisionTree(const proto::DecisionTree& tree) const;
-
-  // Validates a leaf. Returns false if the leaf is invalid.
-  bool ValidateLeaf(const proto::Leaf& leaf) const;
-
-  // Validates an inequality test. Returns false if the
-  // inequality test is invalid.
-  bool ValidateInequalityTest(
-      const proto::InequalityTest& inequality_test) const;
-
-  // Validates each node of a decision tree by traversing every
-  // node of the |tree|. Returns false if any part of the tree is invalid.
-  bool ValidateTreeNode(const proto::DecisionTree& tree,
-                        const proto::TreeNode& node,
-                        const int& node_index) const;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  DISALLOW_COPY_AND_ASSIGN(DecisionTreePredictionModel);
-};
-
-}  // namespace optimization_guide
-
-#endif  // CHROME_BROWSER_OPTIMIZATION_GUIDE_PREDICTION_DECISION_TREE_PREDICTION_MODEL_H_
diff --git a/chrome/browser/optimization_guide/prediction/decision_tree_prediction_model_unittest.cc b/chrome/browser/optimization_guide/prediction/decision_tree_prediction_model_unittest.cc
deleted file mode 100644
index 29fece2..0000000
--- a/chrome/browser/optimization_guide/prediction/decision_tree_prediction_model_unittest.cc
+++ /dev/null
@@ -1,482 +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 <memory>
-#include <utility>
-
-#include "base/containers/flat_map.h"
-#include "base/containers/flat_set.h"
-#include "chrome/browser/optimization_guide/prediction/decision_tree_prediction_model.h"
-#include "chrome/browser/optimization_guide/prediction/prediction_model.h"
-#include "components/optimization_guide/proto/models.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace optimization_guide {
-
-std::unique_ptr<proto::PredictionModel> GetValidDecisionTreePredictionModel() {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      std::make_unique<proto::PredictionModel>();
-  prediction_model->mutable_model()->mutable_threshold()->set_value(5.0);
-
-  proto::DecisionTree decision_tree_model = proto::DecisionTree();
-  decision_tree_model.set_weight(2.0);
-
-  proto::TreeNode* tree_node = decision_tree_model.add_nodes();
-  tree_node->mutable_node_id()->set_value(0);
-  tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(1);
-  tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(2);
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->mutable_feature_id()
-      ->mutable_id()
-      ->set_value("agg1");
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->mutable_threshold()
-      ->set_float_value(1.0);
-
-  tree_node = decision_tree_model.add_nodes();
-  tree_node->mutable_node_id()->set_value(1);
-  tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
-      2.);
-
-  tree_node = decision_tree_model.add_nodes();
-  tree_node->mutable_node_id()->set_value(2);
-  tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
-      4.);
-
-  *prediction_model->mutable_model()->mutable_decision_tree() =
-      decision_tree_model;
-  return prediction_model;
-}
-
-std::unique_ptr<proto::PredictionModel> GetValidEnsemblePredictionModel() {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      std::make_unique<proto::PredictionModel>();
-  prediction_model->mutable_model()->mutable_threshold()->set_value(5.0);
-  proto::Ensemble ensemble = proto::Ensemble();
-  *ensemble.add_members()->mutable_submodel() =
-      *GetValidDecisionTreePredictionModel()->mutable_model();
-
-  *ensemble.add_members()->mutable_submodel() =
-      *GetValidDecisionTreePredictionModel()->mutable_model();
-
-  *prediction_model->mutable_model()->mutable_ensemble() = ensemble;
-  return prediction_model;
-}
-
-TEST(DecisionTreePredictionModel, ValidDecisionTreeModel) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_TRUE(model);
-
-  double prediction_score;
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
-            model->Predict({{"agg1", 1.0}}, &prediction_score));
-  EXPECT_EQ(4., prediction_score);
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
-            model->Predict({{"agg1", 2.0}}, &prediction_score));
-  EXPECT_EQ(8., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, InequalityLessThan) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()
-      ->mutable_decision_tree()
-      ->mutable_nodes(0)
-      ->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->set_type(proto::InequalityTest::LESS_THAN);
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_TRUE(model);
-
-  double prediction_score;
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
-            model->Predict({{"agg1", 0.5}}, &prediction_score));
-  EXPECT_EQ(4., prediction_score);
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
-            model->Predict({{"agg1", 2.0}}, &prediction_score));
-  EXPECT_EQ(8., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, InequalityGreaterOrEqual) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()
-      ->mutable_decision_tree()
-      ->mutable_nodes(0)
-      ->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->set_type(proto::InequalityTest::GREATER_OR_EQUAL);
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_TRUE(model);
-
-  double prediction_score;
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
-            model->Predict({{"agg1", 0.5}}, &prediction_score));
-  EXPECT_EQ(8., prediction_score);
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
-            model->Predict({{"agg1", 1.0}}, &prediction_score));
-  EXPECT_EQ(4., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, InequalityGreaterThan) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()
-      ->mutable_decision_tree()
-      ->mutable_nodes(0)
-      ->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->set_type(proto::InequalityTest::GREATER_THAN);
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_TRUE(model);
-
-  double prediction_score;
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
-            model->Predict({{"agg1", 0.5}}, &prediction_score));
-  EXPECT_EQ(8., prediction_score);
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
-            model->Predict({{"agg1", 2.0}}, &prediction_score));
-  EXPECT_EQ(4., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, MissingInequalityTest) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()
-      ->mutable_decision_tree()
-      ->mutable_nodes(0)
-      ->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->Clear();
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, NoDecisionTreeThreshold) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()->clear_threshold();
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, EmptyTree) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()->mutable_decision_tree()->clear_nodes();
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, ModelFeatureNotInFeatureMap) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()->mutable_decision_tree()->clear_nodes();
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeMissingLeaf) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()
-      ->mutable_decision_tree()
-      ->mutable_nodes(1)
-      ->mutable_leaf()
-      ->Clear();
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeLeftChildIndexInvalid) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()
-      ->mutable_decision_tree()
-      ->mutable_nodes(0)
-      ->mutable_binary_node()
-      ->mutable_left_child_id()
-      ->set_value(3);
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeRightChildIndexInvalid) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  prediction_model->mutable_model()
-      ->mutable_decision_tree()
-      ->mutable_nodes(0)
-      ->mutable_binary_node()
-      ->mutable_right_child_id()
-      ->set_value(3);
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeWithLoopOnLeftChild) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  proto::TreeNode* tree_node =
-      prediction_model->mutable_model()->mutable_decision_tree()->mutable_nodes(
-          1);
-
-  tree_node->mutable_node_id()->set_value(0);
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->mutable_feature_id()
-      ->mutable_id()
-      ->set_value("agg1");
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->mutable_threshold()
-      ->set_float_value(1.0);
-
-  tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(0);
-  tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(2);
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeWithLoopOnRightChild) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidDecisionTreePredictionModel();
-
-  proto::TreeNode* tree_node =
-      prediction_model->mutable_model()->mutable_decision_tree()->mutable_nodes(
-          1);
-
-  tree_node->mutable_node_id()->set_value(0);
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->mutable_feature_id()
-      ->mutable_id()
-      ->set_value("agg1");
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->mutable_threshold()
-      ->set_float_value(1.0);
-
-  tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(2);
-  tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(0);
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, ValidEnsembleModel) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidEnsemblePredictionModel();
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_TRUE(model);
-
-  double prediction_score;
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
-            model->Predict({{"agg1", 1.0}}, &prediction_score));
-  EXPECT_EQ(4., prediction_score);
-  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
-            model->Predict({{"agg1", 2.0}}, &prediction_score));
-  EXPECT_EQ(8., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, EnsembleWithNoMembers) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      GetValidEnsemblePredictionModel();
-  prediction_model->mutable_model()
-      ->mutable_ensemble()
-      ->mutable_members()
-      ->Clear();
-
-  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-}  // namespace optimization_guide
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager.cc b/chrome/browser/optimization_guide/prediction/prediction_manager.cc
index 4d2ec02..cabf14e 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/optimization_guide/optimization_guide_session_statistic.h"
 #include "chrome/browser/optimization_guide/optimization_guide_test_util.h"
 #include "chrome/browser/optimization_guide/optimization_guide_util.h"
-#include "chrome/browser/optimization_guide/prediction/prediction_model.h"
 #include "chrome/browser/optimization_guide/prediction/prediction_model_fetcher.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
@@ -36,6 +35,7 @@
 #include "components/optimization_guide/optimization_guide_prefs.h"
 #include "components/optimization_guide/optimization_guide_store.h"
 #include "components/optimization_guide/optimization_guide_switches.h"
+#include "components/optimization_guide/prediction_model.h"
 #include "components/optimization_guide/store_update_data.h"
 #include "components/optimization_guide/top_host_provider.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc b/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc
index 58f645a..895d16b 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/optimization_guide/optimization_guide_navigation_data.h"
 #include "chrome/browser/optimization_guide/optimization_guide_util.h"
 #include "chrome/browser/optimization_guide/optimization_guide_web_contents_observer.h"
-#include "chrome/browser/optimization_guide/prediction/prediction_model.h"
 #include "chrome/browser/optimization_guide/prediction/prediction_model_fetcher.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/leveldb_proto/testing/fake_db.h"
@@ -26,6 +25,7 @@
 #include "components/optimization_guide/optimization_guide_service.h"
 #include "components/optimization_guide/optimization_guide_store.h"
 #include "components/optimization_guide/optimization_guide_switches.h"
+#include "components/optimization_guide/prediction_model.h"
 #include "components/optimization_guide/proto/hint_cache.pb.h"
 #include "components/optimization_guide/proto/models.pb.h"
 #include "components/optimization_guide/proto_database_provider_test_base.h"
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model.cc b/chrome/browser/optimization_guide/prediction/prediction_model.cc
deleted file mode 100644
index 4a1fa0d..0000000
--- a/chrome/browser/optimization_guide/prediction/prediction_model.cc
+++ /dev/null
@@ -1,104 +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/optimization_guide/prediction/prediction_model.h"
-
-#include <utility>
-
-#include "chrome/browser/optimization_guide/prediction/decision_tree_prediction_model.h"
-
-namespace optimization_guide {
-
-// static
-std::unique_ptr<PredictionModel> PredictionModel::Create(
-    std::unique_ptr<optimization_guide::proto::PredictionModel>
-        prediction_model) {
-  // TODO(crbug/1009123): Add a histogram to record if the provided model is
-  // constructed successfully or not.
-  // TODO(crbug/1009123): Adding timing metrics around initialization due to
-  // potential validation overhead.
-  if (!prediction_model->has_model())
-    return nullptr;
-
-  if (!prediction_model->has_model_info())
-    return nullptr;
-
-  if (!prediction_model->model_info().has_version())
-    return nullptr;
-
-  // Enforce that only one ModelType is specified for the PredictionModel.
-  if (prediction_model->model_info().supported_model_types_size() != 1) {
-    return nullptr;
-  }
-
-  // Check that the client supports this type of model and is not an unknown
-  // type.
-  if (!optimization_guide::proto::ModelType_IsValid(
-          prediction_model->model_info().supported_model_types(0)) ||
-      prediction_model->model_info().supported_model_types(0) ==
-          optimization_guide::proto::ModelType::MODEL_TYPE_UNKNOWN) {
-    return nullptr;
-  }
-
-  // Check that the client supports the model features for |prediction model|.
-  for (const auto& model_feature :
-       prediction_model->model_info().supported_model_features()) {
-    if (!optimization_guide::proto::ClientModelFeature_IsValid(model_feature) ||
-        model_feature == optimization_guide::proto::ClientModelFeature::
-                             CLIENT_MODEL_FEATURE_UNKNOWN)
-      return nullptr;
-  }
-
-  std::unique_ptr<PredictionModel> model;
-  // The Decision Tree model type is currently the only supported model type.
-  if (prediction_model->model_info().supported_model_types(0) !=
-      optimization_guide::proto::ModelType::MODEL_TYPE_DECISION_TREE) {
-    return nullptr;
-  }
-  model = std::make_unique<DecisionTreePredictionModel>(
-      std::move(prediction_model));
-
-  // Any constructed model must be validated for correctness according to its
-  // model type before being returned.
-  if (!model->ValidatePredictionModel())
-    return nullptr;
-
-  return model;
-}
-
-PredictionModel::PredictionModel(
-    std::unique_ptr<optimization_guide::proto::PredictionModel>
-        prediction_model) {
-  version_ = prediction_model->model_info().version();
-  model_features_.reserve(
-      prediction_model->model_info().supported_model_features_size() +
-      prediction_model->model_info().supported_host_model_features_size());
-  // Insert all the client model features for the owned |model_|.
-  for (const auto& client_model_feature :
-       prediction_model->model_info().supported_model_features()) {
-    model_features_.emplace(optimization_guide::proto::ClientModelFeature_Name(
-        client_model_feature));
-  }
-  // Insert all the host model features for the owned |model_|.
-  for (const auto& host_model_feature :
-       prediction_model->model_info().supported_host_model_features()) {
-    model_features_.emplace(host_model_feature);
-  }
-  model_ = std::make_unique<optimization_guide::proto::Model>(
-      prediction_model->model());
-}
-
-int64_t PredictionModel::GetVersion() const {
-  SEQUENCE_CHECKER(sequence_checker_);
-  return version_;
-}
-
-base::flat_set<std::string> PredictionModel::GetModelFeatures() const {
-  SEQUENCE_CHECKER(sequence_checker_);
-  return model_features_;
-}
-
-PredictionModel::~PredictionModel() = default;
-
-}  // namespace optimization_guide
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model.h b/chrome/browser/optimization_guide/prediction/prediction_model.h
deleted file mode 100644
index eed99be..0000000
--- a/chrome/browser/optimization_guide/prediction/prediction_model.h
+++ /dev/null
@@ -1,76 +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_OPTIMIZATION_GUIDE_PREDICTION_PREDICTION_MODEL_H_
-#define CHROME_BROWSER_OPTIMIZATION_GUIDE_PREDICTION_PREDICTION_MODEL_H_
-
-#include <stdint.h>
-#include <memory>
-#include <string>
-
-#include "base/containers/flat_map.h"
-#include "base/containers/flat_set.h"
-#include "base/macros.h"
-#include "base/sequence_checker.h"
-#include "components/optimization_guide/optimization_guide_enums.h"
-#include "components/optimization_guide/proto/models.pb.h"
-
-namespace optimization_guide {
-
-// A PredictionModel supported by the optimization guide that makes an
-// OptimizationTargetDecision by evaluating a prediction model.
-class PredictionModel {
- public:
-  virtual ~PredictionModel();
-
-  // Creates an Prediction model of the correct ModelType specified in
-  // |prediction_model|. The validation overhead of this factory can be high and
-  // should should be called in the background.
-  static std::unique_ptr<PredictionModel> Create(
-      std::unique_ptr<optimization_guide::proto::PredictionModel>
-          prediction_model);
-
-  // Returns the OptimizationTargetDecision by evaluating the |model_|
-  // using the provided |model_features|. |prediction_score| will be populated
-  // with the score output by the model.
-  virtual optimization_guide::OptimizationTargetDecision Predict(
-      const base::flat_map<std::string, float>& model_features,
-      double* prediction_score) = 0;
-
-  // Provide the version of the |model_| by |this|.
-  int64_t GetVersion() const;
-
-  // Provide the model features required for evaluation of the |model_| by
-  // |this|.
-  base::flat_set<std::string> GetModelFeatures() const;
-
- protected:
-  PredictionModel(std::unique_ptr<optimization_guide::proto::PredictionModel>
-                      prediction_model);
-
-  // The in-memory model used for prediction.
-  std::unique_ptr<optimization_guide::proto::Model> model_;
-
- private:
-  // Determines if the |model_| is complete and can be successfully evaluated by
-  // |this|.
-  virtual bool ValidatePredictionModel() const = 0;
-
-  // The information that describes the |model_|
-  std::unique_ptr<optimization_guide::proto::ModelInfo> model_info_;
-
-  // The set of features required by the |model_| to be evaluated.
-  base::flat_set<std::string> model_features_;
-
-  // The version of the |model_|.
-  int64_t version_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  DISALLOW_COPY_AND_ASSIGN(PredictionModel);
-};
-
-}  // namespace optimization_guide
-
-#endif  // CHROME_BROWSER_OPTIMIZATION_GUIDE_PREDICTION_PREDICTION_MODEL_H_
diff --git a/chrome/browser/optimization_guide/prediction/prediction_model_unittest.cc b/chrome/browser/optimization_guide/prediction/prediction_model_unittest.cc
deleted file mode 100644
index b90d254..0000000
--- a/chrome/browser/optimization_guide/prediction/prediction_model_unittest.cc
+++ /dev/null
@@ -1,174 +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/optimization_guide/prediction/prediction_model.h"
-
-#include <utility>
-
-#include "components/optimization_guide/proto/models.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace optimization_guide {
-
-TEST(PredictionModelTest, ValidPredictionModel) {
-  std::unique_ptr<proto::PredictionModel> prediction_model =
-      std::make_unique<proto::PredictionModel>();
-  prediction_model->mutable_model()->mutable_threshold()->set_value(5.0);
-
-  proto::DecisionTree decision_tree_model = proto::DecisionTree();
-  decision_tree_model.set_weight(2.0);
-
-  proto::TreeNode* tree_node = decision_tree_model.add_nodes();
-  tree_node->mutable_node_id()->set_value(0);
-  tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(1);
-  tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(2);
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->mutable_feature_id()
-      ->mutable_id()
-      ->set_value("agg1");
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
-  tree_node->mutable_binary_node()
-      ->mutable_inequality_left_child_test()
-      ->mutable_threshold()
-      ->set_float_value(1.0);
-
-  tree_node = decision_tree_model.add_nodes();
-  tree_node->mutable_node_id()->set_value(1);
-  tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
-      2.);
-
-  tree_node = decision_tree_model.add_nodes();
-  tree_node->mutable_node_id()->set_value(2);
-  tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
-      4.);
-
-  *prediction_model->mutable_model()->mutable_decision_tree() =
-      decision_tree_model;
-
-  optimization_guide::proto::ModelInfo* model_info =
-      prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      optimization_guide::proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_features(
-      optimization_guide::proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
-  model_info->add_supported_host_model_features("agg1");
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-
-  EXPECT_EQ(1, model->GetVersion());
-  EXPECT_EQ(2u, model->GetModelFeatures().size());
-  EXPECT_TRUE(model->GetModelFeatures().count("agg1"));
-  EXPECT_TRUE(model->GetModelFeatures().count(
-      "CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE"));
-}
-
-TEST(PredictionModelTest, NoModel) {
-  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
-      std::make_unique<optimization_guide::proto::PredictionModel>();
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(PredictionModelTest, NoModelVersion) {
-  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
-      std::make_unique<optimization_guide::proto::PredictionModel>();
-
-  optimization_guide::proto::DecisionTree* decision_tree_model =
-      prediction_model->mutable_model()->mutable_decision_tree();
-  decision_tree_model->set_weight(2.0);
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(PredictionModelTest, NoModelType) {
-  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
-      std::make_unique<optimization_guide::proto::PredictionModel>();
-
-  optimization_guide::proto::DecisionTree* decision_tree_model =
-      prediction_model->mutable_model()->mutable_decision_tree();
-  decision_tree_model->set_weight(2.0);
-
-  optimization_guide::proto::ModelInfo* model_info =
-      prediction_model->mutable_model_info();
-  model_info->set_version(1);
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(PredictionModelTest, UnknownModelType) {
-  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
-      std::make_unique<optimization_guide::proto::PredictionModel>();
-
-  optimization_guide::proto::DecisionTree* decision_tree_model =
-      prediction_model->mutable_model()->mutable_decision_tree();
-  decision_tree_model->set_weight(2.0);
-
-  optimization_guide::proto::ModelInfo* model_info =
-      prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      optimization_guide::proto::ModelType::MODEL_TYPE_UNKNOWN);
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(PredictionModelTest, MultipleModelTypes) {
-  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
-      std::make_unique<optimization_guide::proto::PredictionModel>();
-
-  optimization_guide::proto::DecisionTree* decision_tree_model =
-      prediction_model->mutable_model()->mutable_decision_tree();
-  decision_tree_model->set_weight(2.0);
-
-  optimization_guide::proto::ModelInfo* model_info =
-      prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      optimization_guide::proto::ModelType::MODEL_TYPE_DECISION_TREE);
-  model_info->add_supported_model_types(
-      optimization_guide::proto::ModelType::MODEL_TYPE_UNKNOWN);
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-TEST(PredictionModelTest, UnknownModelClientFeature) {
-  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
-      std::make_unique<optimization_guide::proto::PredictionModel>();
-
-  optimization_guide::proto::DecisionTree* decision_tree_model =
-      prediction_model->mutable_model()->mutable_decision_tree();
-  decision_tree_model->set_weight(2.0);
-
-  optimization_guide::proto::ModelInfo* model_info =
-      prediction_model->mutable_model_info();
-  model_info->set_version(1);
-  model_info->add_supported_model_types(
-      optimization_guide::proto::ModelType::MODEL_TYPE_DECISION_TREE);
-
-  model_info->add_supported_model_features(
-      optimization_guide::proto::ClientModelFeature::
-          CLIENT_MODEL_FEATURE_UNKNOWN);
-
-  std::unique_ptr<PredictionModel> model =
-      PredictionModel::Create(std::move(prediction_model));
-  EXPECT_FALSE(model);
-}
-
-}  // namespace optimization_guide
diff --git a/chrome/browser/performance_hints/android/java/src/org/chromium/chrome/browser/performance_hints/PerformanceHintsObserver.java b/chrome/browser/performance_hints/android/java/src/org/chromium/chrome/browser/performance_hints/PerformanceHintsObserver.java
index 1766701c..43b5946 100644
--- a/chrome/browser/performance_hints/android/java/src/org/chromium/chrome/browser/performance_hints/PerformanceHintsObserver.java
+++ b/chrome/browser/performance_hints/android/java/src/org/chromium/chrome/browser/performance_hints/PerformanceHintsObserver.java
@@ -32,10 +32,15 @@
         return PerformanceHintsObserverJni.get().getPerformanceClassForURL(webContents, url);
     }
 
+    public static boolean isContextMenuPerformanceInfoEnabled() {
+        return PerformanceHintsObserverJni.get().isContextMenuPerformanceInfoEnabled();
+    }
+
     private PerformanceHintsObserver() {}
 
     @NativeMethods
-    interface Natives {
+    public interface Natives {
         int getPerformanceClassForURL(WebContents webContents, String url);
+        boolean isContextMenuPerformanceInfoEnabled();
     }
 }
diff --git a/chrome/browser/performance_hints/performance_hints_features.cc b/chrome/browser/performance_hints/performance_hints_features.cc
new file mode 100644
index 0000000..fd2406c
--- /dev/null
+++ b/chrome/browser/performance_hints/performance_hints_features.cc
@@ -0,0 +1,62 @@
+// Copyright 2020 The Chromium 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/performance_hints/performance_hints_features.h"
+
+#include "base/metrics/field_trial_params.h"
+
+const base::Feature kPerformanceHintsObserver{
+    "PerformanceHintsObserver", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPerformanceHintsTreatUnknownAsFast{
+    "PerformanceHintsTreatUnknownAsFast", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kPerformanceHintsHandleRewrites{
+    "PerformanceHintsHandleRewrites", base::FEATURE_ENABLED_BY_DEFAULT};
+constexpr base::FeatureParam<std::string> kRewriteConfig{
+    &kPerformanceHintsHandleRewrites, "rewrite_config",
+    "www.google.com/url?url"};
+
+constexpr base::FeatureParam<bool> kUseFastHostHints{
+    &kPerformanceHintsObserver, "use_fast_host_hints", true};
+
+const base::Feature kContextMenuPerformanceInfo{
+    "ContextMenuPerformanceInfo", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kContextMenuPerformanceInfoAndRemoteHintFetching{
+    "ContextMenuPerformanceInfoAndRemoteHintFetching",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kPageInfoPerformanceHints{
+    "PageInfoPerformanceHints", base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsPerformanceHintsObserverEnabled() {
+  return base::FeatureList::IsEnabled(kPageInfoPerformanceHints) ||
+         IsContextMenuPerformanceInfoEnabled() ||
+         base::FeatureList::IsEnabled(kPerformanceHintsObserver);
+}
+
+bool ShouldTreatUnknownAsFast() {
+  return base::FeatureList::IsEnabled(kPerformanceHintsTreatUnknownAsFast);
+}
+
+bool ShouldHandleRewrites() {
+  return base::FeatureList::IsEnabled(kPerformanceHintsHandleRewrites);
+}
+
+std::string GetRewriteConfigString() {
+  return kRewriteConfig.Get();
+}
+
+bool AreFastHostHintsEnabled() {
+  return kUseFastHostHints.Get();
+}
+
+bool IsContextMenuPerformanceInfoEnabled() {
+  return base::FeatureList::IsEnabled(kContextMenuPerformanceInfo) ||
+         base::FeatureList::IsEnabled(
+             kContextMenuPerformanceInfoAndRemoteHintFetching);
+}
+
+bool IsRemoteFetchingExplicitlyAllowedForPerformanceInfo() {
+  return base::FeatureList::IsEnabled(
+      kContextMenuPerformanceInfoAndRemoteHintFetching);
+}
diff --git a/chrome/browser/performance_hints/performance_hints_features.h b/chrome/browser/performance_hints/performance_hints_features.h
new file mode 100644
index 0000000..346a4da8
--- /dev/null
+++ b/chrome/browser/performance_hints/performance_hints_features.h
@@ -0,0 +1,52 @@
+// Copyright 2020 The Chromium 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_PERFORMANCE_HINTS_PERFORMANCE_HINTS_FEATURES_H_
+#define CHROME_BROWSER_PERFORMANCE_HINTS_PERFORMANCE_HINTS_FEATURES_H_
+
+#include <string>
+
+#include "base/feature_list.h"
+
+// Exposed for chrome://flags.
+extern const base::Feature kPageInfoPerformanceHints;
+
+// Exposed for testing.
+extern const base::Feature kPerformanceHintsObserver;
+extern const base::Feature kPerformanceHintsTreatUnknownAsFast;
+extern const base::Feature kPerformanceHintsHandleRewrites;
+extern const base::Feature kContextMenuPerformanceInfo;
+extern const base::Feature kContextMenuPerformanceInfoAndRemoteHintFetching;
+
+// Returns true if PerformanceHintsObserver should be added as a tab helper and
+// fetch performance hints.
+bool IsPerformanceHintsObserverEnabled();
+
+// Returns true if hints of PERFORMANCE_UNKNOWN should be overridden to
+// PERFORMANCE_FAST.
+//
+// This does not affect the value that is recorded via UMA.
+bool ShouldTreatUnknownAsFast();
+
+// Returns true if PerformanceHintsRewriteHandler should be used to detect
+// rewritten URLs and revert them to their original form.
+bool ShouldHandleRewrites();
+
+// Returns the config string to be used by PerformanceHintsRewriteHandler.
+//
+// Contains rewritten URL patterns that should be replaced with a URL contained
+// in their query params.
+std::string GetRewriteConfigString();
+
+// Returns true if FAST_HOST_HINTS should be checked if available.
+bool AreFastHostHintsEnabled();
+
+// Returns true if performance info should be shown in the context menu.
+bool IsContextMenuPerformanceInfoEnabled();
+
+// Returns true if a feature that explicitly allows remote fetching has been
+// enabled.
+bool IsRemoteFetchingExplicitlyAllowedForPerformanceInfo();
+
+#endif  // CHROME_BROWSER_PERFORMANCE_HINTS_PERFORMANCE_HINTS_FEATURES_H_
diff --git a/chrome/browser/performance_hints/performance_hints_observer.cc b/chrome/browser/performance_hints/performance_hints_observer.cc
index 4792a48..237f5bb 100644
--- a/chrome/browser/performance_hints/performance_hints_observer.cc
+++ b/chrome/browser/performance_hints/performance_hints_observer.cc
@@ -6,7 +6,6 @@
 
 #include <string>
 
-#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/strcat.h"
@@ -14,6 +13,7 @@
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/optimization_guide/optimization_guide_permissions_util.h"
+#include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/optimization_guide/optimization_guide_decider.h"
 #include "components/optimization_guide/url_pattern_with_wildcards.h"
@@ -91,19 +91,12 @@
       web_contents, GURL(base::android::ConvertJavaStringToUTF8(url)),
       /*record_metrics=*/false);
 }
-#endif  // OS_ANDROID
 
-const base::Feature kPerformanceHintsObserver{
-    "PerformanceHintsObserver", base::FEATURE_DISABLED_BY_DEFAULT};
-constexpr base::FeatureParam<bool> kUseFastHostHints{
-    &kPerformanceHintsObserver, "use_fast_host_hints", true};
-const base::Feature kPerformanceHintsTreatUnknownAsFast{
-    "PerformanceHintsTreatUnknownAsFast", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kPerformanceHintsHandleRewrites{
-    "PerformanceHintsHandleRewrites", base::FEATURE_ENABLED_BY_DEFAULT};
-constexpr base::FeatureParam<std::string> kRewriteConfig{
-    &kPerformanceHintsHandleRewrites, "rewrite_config",
-    "www.google.com/url?url"};
+static jboolean
+JNI_PerformanceHintsObserver_IsContextMenuPerformanceInfoEnabled(JNIEnv* env) {
+  return IsContextMenuPerformanceInfoEnabled();
+}
+#endif  // OS_ANDROID
 
 PerformanceHintsObserver::PerformanceHintsObserver(
     content::WebContents* web_contents)
@@ -113,15 +106,15 @@
           Profile::FromBrowserContext(web_contents->GetBrowserContext()));
   std::vector<optimization_guide::proto::OptimizationType> opts;
   opts.push_back(optimization_guide::proto::PERFORMANCE_HINTS);
-  if (kUseFastHostHints.Get()) {
+  if (AreFastHostHintsEnabled()) {
     opts.push_back(optimization_guide::proto::FAST_HOST_HINTS);
   }
   if (optimization_guide_decider_) {
     optimization_guide_decider_->RegisterOptimizationTypes(opts);
   }
 
-  rewrite_handler_ =
-      PerformanceHintsRewriteHandler::FromConfigString(kRewriteConfig.Get());
+  rewrite_handler_ = PerformanceHintsRewriteHandler::FromConfigString(
+      GetRewriteConfigString());
 }
 
 PerformanceHintsObserver::~PerformanceHintsObserver() {
@@ -186,7 +179,7 @@
   }
 
   if (performance_class == PerformanceClass::PERFORMANCE_UNKNOWN &&
-      base::FeatureList::IsEnabled(kPerformanceHintsTreatUnknownAsFast)) {
+      ShouldTreatUnknownAsFast()) {
     // If we couldn't get the hint or we didn't expect it on this page, give it
     // the benefit of the doubt.
     return PerformanceClass::PERFORMANCE_FAST;
@@ -220,7 +213,7 @@
   }
 
   base::Optional<GURL> maybe_rewritten;
-  if (base::FeatureList::IsEnabled(kPerformanceHintsHandleRewrites)) {
+  if (ShouldHandleRewrites()) {
     maybe_rewritten = rewrite_handler_.HandleRewriteIfNecessary(url);
     result.rewritten = maybe_rewritten.has_value();
     if (maybe_rewritten && (!maybe_rewritten->is_valid() ||
@@ -247,7 +240,7 @@
   sources.emplace_back(HintLookupSource::kPageHint,
                        base::BindOnce(&PerformanceHintsObserver::PageHintForURL,
                                       base::Unretained(this)));
-  if (kUseFastHostHints.Get()) {
+  if (AreFastHostHintsEnabled()) {
     sources.emplace_back(
         HintLookupSource::kFastHostHint,
         base::BindOnce(&PerformanceHintsObserver::FastHostHintForURL,
diff --git a/chrome/browser/performance_hints/performance_hints_observer.h b/chrome/browser/performance_hints/performance_hints_observer.h
index fad7f83..3cf4736f 100644
--- a/chrome/browser/performance_hints/performance_hints_observer.h
+++ b/chrome/browser/performance_hints/performance_hints_observer.h
@@ -35,17 +35,6 @@
 
 class GURL;
 
-// If enabled, PerformanceHintsObserver will be added as a tab helper and will
-// fetch performance hints.
-extern const base::Feature kPerformanceHintsObserver;
-// If enabled, hints of PERFORMANCE_UNKNOWN will be overridden to
-// PERFORMANCE_FAST. This does not affect the value that is recorded via UMA.
-extern const base::Feature kPerformanceHintsTreatUnknownAsFast;
-// If enabled, PerformanceHintsRewriteHandler will be used to detect rewritten
-// URLs (specified by the rewrite_config param) and revert them to their
-// original form.
-extern const base::Feature kPerformanceHintsHandleRewrites;
-
 // Provides an interface to access PerformanceHints for the associated
 // WebContents and links within it.
 class PerformanceHintsObserver
diff --git a/chrome/browser/performance_hints/performance_hints_observer_unittest.cc b/chrome/browser/performance_hints/performance_hints_observer_unittest.cc
index 9e9b7075..3e6e324c 100644
--- a/chrome/browser/performance_hints/performance_hints_observer_unittest.cc
+++ b/chrome/browser/performance_hints/performance_hints_observer_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
+#include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/optimization_guide/optimization_guide_features.h"
diff --git a/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc b/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
index 1a130bb..754abdbdb 100644
--- a/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
+++ b/chrome/browser/policy/cloud/chrome_browser_cloud_management_browsertest.cc
@@ -483,7 +483,7 @@
 
   void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
     static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
-        new ChromeBrowserExtraSetUp(&observer_));
+        std::make_unique<ChromeBrowserExtraSetUp>(&observer_));
   }
 
   void VerifyEnrollmentResult() {
diff --git a/chrome/browser/policy/messaging_layer/public/report_client.cc b/chrome/browser/policy/messaging_layer/public/report_client.cc
index aa265cf2..80848da 100644
--- a/chrome/browser/policy/messaging_layer/public/report_client.cc
+++ b/chrome/browser/policy/messaging_layer/public/report_client.cc
@@ -9,6 +9,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/no_destructor.h"
+#include "base/path_service.h"
 #include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h"
 #include "chrome/browser/policy/messaging_layer/public/report_queue.h"
 #include "chrome/browser/policy/messaging_layer/public/report_queue_configuration.h"
@@ -16,14 +17,42 @@
 #include "chrome/browser/policy/messaging_layer/util/status.h"
 #include "chrome/browser/policy/messaging_layer/util/status_macros.h"
 #include "chrome/browser/policy/messaging_layer/util/statusor.h"
+#include "chrome/common/chrome_paths.h"
 
 namespace reporting {
 
-using base::MakeRefCounted;
+namespace {
+
+const base::FilePath::CharType kReportingDirectory[] =
+    FILE_PATH_LITERAL("reporting");
+
+}  // namespace
+
+class ReportingClient::UploadClient : public Storage::UploaderInterface {
+ public:
+  static StatusOr<std::unique_ptr<Storage::UploaderInterface>> Build(
+      Priority priority) {
+    // Cannot use make_unique, since constructor is private.
+    return base::WrapUnique(new UploadClient());
+  }
+
+  void ProcessBlob(Priority priority,
+                   StatusOr<base::span<const uint8_t>> blob,
+                   base::OnceCallback<void(bool)> processed_cb) override {
+    std::move(processed_cb).Run(false);  // Do not proceed.
+  }
+
+  void Completed(Priority priority, Status status) override {
+    LOG(ERROR) << "Not implemented yet, status=" << status;
+  }
+
+ private:
+  UploadClient() = default;
+};
 
 ReportingClient::ReportingClient(scoped_refptr<StorageModule> storage)
     : storage_(std::move(storage)),
-      encryption_(MakeRefCounted<EncryptionModule>()) {}
+      encryption_(base::MakeRefCounted<EncryptionModule>()) {}
 
 ReportingClient::~ReportingClient() = default;
 
@@ -47,9 +76,29 @@
 // this create function will need to be updated to check for
 // successful creation of the EncryptionModule too.
 StatusOr<std::unique_ptr<ReportingClient>> ReportingClient::Create() {
-  ASSIGN_OR_RETURN(scoped_refptr<StorageModule> storage,
-                   StorageModule::Create());
-  auto client = base::WrapUnique<ReportingClient>(new ReportingClient(storage));
+  base::FilePath user_data_dir;
+  if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
+    return Status(error::FAILED_PRECONDITION, "Could not retrieve base path");
+  }
+  base::FilePath reporting_path = user_data_dir.Append(kReportingDirectory);
+  base::WaitableEvent done(base::WaitableEvent::ResetPolicy::MANUAL,
+                           base::WaitableEvent::InitialState::NOT_SIGNALED);
+  StatusOr<scoped_refptr<StorageModule>> storage_result;
+  StorageModule::Create(
+      Storage::Options().set_directory(reporting_path),
+      base::BindRepeating(&ReportingClient::UploadClient::Build),
+      base::BindOnce(
+          [](StatusOr<scoped_refptr<StorageModule>>* result,
+             base::WaitableEvent* done,
+             StatusOr<scoped_refptr<StorageModule>> storage) {
+            *result = std::move(storage);
+            done->Signal();
+          },
+          base::Unretained(&storage_result), base::Unretained(&done)));
+  done.Wait();
+  RETURN_IF_ERROR(storage_result.status());
+  auto client = base::WrapUnique<ReportingClient>(
+      new ReportingClient(std::move(storage_result.ValueOrDie())));
   return client;
 }
 
diff --git a/chrome/browser/policy/messaging_layer/public/report_client.h b/chrome/browser/policy/messaging_layer/public/report_client.h
index b4987eab..d110378 100644
--- a/chrome/browser/policy/messaging_layer/public/report_client.h
+++ b/chrome/browser/policy/messaging_layer/public/report_client.h
@@ -47,6 +47,9 @@
       std::unique_ptr<ReportQueueConfiguration> config);
 
  private:
+  // Client for Upload operation.
+  class UploadClient;
+
   explicit ReportingClient(scoped_refptr<StorageModule> storage);
 
   static StatusOr<ReportingClient*> GetInstance();
diff --git a/chrome/browser/policy/messaging_layer/storage/storage.cc b/chrome/browser/policy/messaging_layer/storage/storage.cc
index 7046d14..d1a2446 100644
--- a/chrome/browser/policy/messaging_layer/storage/storage.cc
+++ b/chrome/browser/policy/messaging_layer/storage/storage.cc
@@ -7,6 +7,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/callback.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_module.cc b/chrome/browser/policy/messaging_layer/storage/storage_module.cc
index 3e190798..17d5fee 100644
--- a/chrome/browser/policy/messaging_layer/storage/storage_module.cc
+++ b/chrome/browser/policy/messaging_layer/storage/storage_module.cc
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
 #include <utility>
 
+#include "base/bind.h"
 #include "base/callback.h"
-#include "base/no_destructor.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/policy/messaging_layer/storage/storage.h"
 #include "chrome/browser/policy/messaging_layer/storage/storage_module.h"
 #include "chrome/browser/policy/messaging_layer/util/status.h"
 #include "chrome/browser/policy/messaging_layer/util/statusor.h"
@@ -26,11 +29,28 @@
 }
 
 // static
-StatusOr<scoped_refptr<StorageModule>> StorageModule::Create() {
+void StorageModule::Create(
+    const Storage::Options& options,
+    Storage::StartUploadCb start_upload_cb,
+    base::OnceCallback<void(StatusOr<scoped_refptr<StorageModule>>)> callback) {
   scoped_refptr<StorageModule> instance =
       // Cannot base::MakeRefCounted, since constructor is protected.
       base::WrapRefCounted(new StorageModule());
-  return instance;
+  Storage::Create(
+      options, start_upload_cb,
+      base::BindOnce(
+          [](scoped_refptr<StorageModule> instance,
+             base::OnceCallback<void(StatusOr<scoped_refptr<StorageModule>>)>
+                 callback,
+             StatusOr<scoped_refptr<Storage>> storage) {
+            if (!storage.ok()) {
+              std::move(callback).Run(storage.status());
+              return;
+            }
+            instance->storage_ = std::move(storage.ValueOrDie());
+            std::move(callback).Run(std::move(instance));
+          },
+          std::move(instance), std::move(callback)));
 }
 
 }  // namespace reporting
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_module.h b/chrome/browser/policy/messaging_layer/storage/storage_module.h
index 678bdb4..7a1cc3c 100644
--- a/chrome/browser/policy/messaging_layer/storage/storage_module.h
+++ b/chrome/browser/policy/messaging_layer/storage/storage_module.h
@@ -9,6 +9,7 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
+#include "chrome/browser/policy/messaging_layer/storage/storage.h"
 #include "chrome/browser/policy/messaging_layer/util/status.h"
 #include "chrome/browser/policy/messaging_layer/util/statusor.h"
 #include "components/policy/proto/record.pb.h"
@@ -20,7 +21,11 @@
 class StorageModule : public base::RefCountedThreadSafe<StorageModule> {
  public:
   // Factory method creates |StorageModule| object.
-  static StatusOr<scoped_refptr<StorageModule>> Create();
+  static void Create(
+      const Storage::Options& options,
+      Storage::StartUploadCb start_upload_cb,
+      base::OnceCallback<void(StatusOr<scoped_refptr<StorageModule>>)>
+          callback);
 
   StorageModule(const StorageModule& other) = delete;
   StorageModule& operator=(const StorageModule& other) = delete;
@@ -40,6 +45,10 @@
 
  private:
   friend base::RefCountedThreadSafe<StorageModule>;
+
+  // Storage backend (currently only Storage).
+  // TODO(b/160334561): make it a pluggable interface.
+  scoped_refptr<Storage> storage_;
 };
 
 }  // namespace reporting
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_queue.cc b/chrome/browser/policy/messaging_layer/storage/storage_queue.cc
index 4aea17c..8512059 100644
--- a/chrome/browser/policy/messaging_layer/storage/storage_queue.cc
+++ b/chrome/browser/policy/messaging_layer/storage/storage_queue.cc
@@ -13,6 +13,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
diff --git a/chrome/browser/policy/messaging_layer/storage/test_storage_module.h b/chrome/browser/policy/messaging_layer/storage/test_storage_module.h
index 9f44cc44..394531a 100644
--- a/chrome/browser/policy/messaging_layer/storage/test_storage_module.h
+++ b/chrome/browser/policy/messaging_layer/storage/test_storage_module.h
@@ -20,6 +20,8 @@
 
 class TestStorageModule : public StorageModule {
  public:
+  // As opposed to the production |StorageModule|, test module does not need to
+  // call factory method - it is created directly by constructor.
   TestStorageModule();
 
   MOCK_METHOD(void,
diff --git a/chrome/browser/policy/policy_initialization_browsertest.cc b/chrome/browser/policy/policy_initialization_browsertest.cc
index 0160634..6030863 100644
--- a/chrome/browser/policy/policy_initialization_browsertest.cc
+++ b/chrome/browser/policy/policy_initialization_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 <memory>
 #include <string>
 
 #include "base/macros.h"
@@ -65,7 +66,7 @@
   }
   void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
     static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
-        new ChromeBrowserMainExtraPartsPolicyValueChecker());
+        std::make_unique<ChromeBrowserMainExtraPartsPolicyValueChecker>());
   }
 
  private:
diff --git a/chrome/browser/predictors/loading_data_collector.cc b/chrome/browser/predictors/loading_data_collector.cc
index 830828d..e531759 100644
--- a/chrome/browser/predictors/loading_data_collector.cc
+++ b/chrome/browser/predictors/loading_data_collector.cc
@@ -97,6 +97,8 @@
     : ukm_source_id(navigation_id.ukm_source_id),
       main_frame_url(navigation_id.main_frame_url),
       initial_url(navigation_id.main_frame_url),
+      navigation_started(navigation_id.creation_time),
+      navigation_committed(base::TimeTicks::Max()),
       first_contentful_paint(base::TimeTicks::Max()) {}
 
 PageRequestSummary::PageRequestSummary(const PageRequestSummary& other) =
@@ -180,6 +182,7 @@
     summary = std::make_unique<PageRequestSummary>(new_navigation_id);
     summary->initial_url = old_navigation_id.main_frame_url;
   }
+  summary->navigation_committed = base::TimeTicks::Now();
 
   inflight_navigations_.emplace(new_navigation_id, std::move(summary));
 }
diff --git a/chrome/browser/predictors/loading_data_collector.h b/chrome/browser/predictors/loading_data_collector.h
index 40df73f3..e615f85 100644
--- a/chrome/browser/predictors/loading_data_collector.h
+++ b/chrome/browser/predictors/loading_data_collector.h
@@ -48,6 +48,8 @@
   ukm::SourceId ukm_source_id;
   GURL main_frame_url;
   GURL initial_url;
+  base::TimeTicks navigation_started;
+  base::TimeTicks navigation_committed;
   base::TimeTicks first_contentful_paint;
 
   // Map of origin -> OriginRequestSummary. Only one instance of each origin
diff --git a/chrome/browser/predictors/loading_data_collector_unittest.cc b/chrome/browser/predictors/loading_data_collector_unittest.cc
index e2f49e7..28a6110 100644
--- a/chrome/browser/predictors/loading_data_collector_unittest.cc
+++ b/chrome/browser/predictors/loading_data_collector_unittest.cc
@@ -205,6 +205,10 @@
   collector_->RecordFinishNavigation(navigation_id, navigation_id,
                                      /* is_error_page */ false);
   EXPECT_EQ(1U, collector_->inflight_navigations_.size());
+  // Ensure that the finish time of the navigation is recorded.
+  EXPECT_NE(
+      collector_->inflight_navigations_.begin()->second->navigation_committed,
+      base::TimeTicks::Max());
 
   std::vector<blink::mojom::ResourceLoadInfoPtr> resources;
   resources.push_back(CreateResourceLoadInfo("http://www.google.com"));
diff --git a/chrome/browser/predictors/loading_predictor_tab_helper.cc b/chrome/browser/predictors/loading_predictor_tab_helper.cc
index 4d87f914..ee961d83 100644
--- a/chrome/browser/predictors/loading_predictor_tab_helper.cc
+++ b/chrome/browser/predictors/loading_predictor_tab_helper.cc
@@ -331,6 +331,8 @@
   }
 
   last_optimization_guide_prediction_->decision = decision;
+  last_optimization_guide_prediction_->optimization_guide_prediction_arrived =
+      base::TimeTicks::Now();
 
   if (decision != optimization_guide::OptimizationGuideDecision::kTrue)
     return;
diff --git a/chrome/browser/predictors/loading_stats_collector.cc b/chrome/browser/predictors/loading_stats_collector.cc
index 5a0915b..d9b08066 100644
--- a/chrome/browser/predictors/loading_stats_collector.cc
+++ b/chrome/browser/predictors/loading_stats_collector.cc
@@ -192,6 +192,13 @@
   if (optimization_guide_prediction) {
     builder.SetOptimizationGuidePredictionDecision(
         static_cast<int64_t>(optimization_guide_prediction->decision));
+    if (optimization_guide_prediction->optimization_guide_prediction_arrived) {
+      builder.SetNavigationStartToOptimizationGuidePredictionArrived(
+          (optimization_guide_prediction->optimization_guide_prediction_arrived
+               .value() -
+           summary.navigation_started)
+              .InMilliseconds());
+    }
     if (!optimization_guide_prediction->preconnect_prediction.requests
              .empty()) {
       size_t correctly_predicted_origins = ReportPreconnectPredictionAccuracy(
@@ -227,8 +234,15 @@
     preconnect_stats_.erase(it);
   }
 
-  if (recorded_ukm)
+  if (recorded_ukm) {
+    // Only record nav start to commit if we had any predictions.
+    if (summary.navigation_committed != base::TimeTicks::Max()) {
+      builder.SetNavigationStartToNavigationCommit(
+          (summary.navigation_committed - summary.navigation_started)
+              .InMilliseconds());
+    }
     builder.Record(ukm::UkmRecorder::Get());
+  }
 }
 
 void LoadingStatsCollector::CleanupAbandonedStats() {
diff --git a/chrome/browser/predictors/loading_stats_collector_unittest.cc b/chrome/browser/predictors/loading_stats_collector_unittest.cc
index 2669861..17edf14 100644
--- a/chrome/browser/predictors/loading_stats_collector_unittest.cc
+++ b/chrome/browser/predictors/loading_stats_collector_unittest.cc
@@ -129,8 +129,10 @@
       gen(1), network::mojom::RequestDestination::kScript));
   resources.push_back(CreateResourceLoadInfo(
       gen(100), network::mojom::RequestDestination::kScript));
+  base::TimeTicks now = base::TimeTicks::Now();
   PageRequestSummary summary =
-      CreatePageRequestSummary(main_frame_url, main_frame_url, resources);
+      CreatePageRequestSummary(main_frame_url, main_frame_url, resources, now);
+  summary.navigation_committed = now + base::TimeDelta::FromMilliseconds(3);
 
   stats_collector_->RecordPageRequestSummary(summary, base::nullopt);
 
@@ -158,6 +160,10 @@
       ukm::builders::LoadingPredictor::
           kLocalPredictionCorrectlyPredictedOriginsName,
       2);
+  ukm_recorder_->ExpectEntryMetric(
+      entry,
+      ukm::builders::LoadingPredictor::kNavigationStartToNavigationCommitName,
+      3);
   // Make sure optimization guide metrics are not recorded.
   EXPECT_FALSE(ukm_recorder_->EntryHasMetric(
       entry, ukm::builders::LoadingPredictor::
@@ -194,6 +200,9 @@
       OptimizationGuidePrediction();
   optimization_guide_prediction->decision =
       optimization_guide::OptimizationGuideDecision::kTrue;
+  base::TimeTicks now = base::TimeTicks::Now();
+  optimization_guide_prediction->optimization_guide_prediction_arrived =
+      now + base::TimeDelta::FromMilliseconds(3);
   optimization_guide_prediction->preconnect_prediction =
       CreatePreconnectPrediction(
           GURL(main_frame_url).host(), false,
@@ -214,7 +223,7 @@
   resources.push_back(CreateResourceLoadInfo(
       gen(100), network::mojom::RequestDestination::kScript));
   PageRequestSummary summary =
-      CreatePageRequestSummary(main_frame_url, main_frame_url, resources);
+      CreatePageRequestSummary(main_frame_url, main_frame_url, resources, now);
 
   stats_collector_->RecordPageRequestSummary(summary,
                                              optimization_guide_prediction);
@@ -243,6 +252,11 @@
           optimization_guide::OptimizationGuideDecision::kTrue));
   ukm_recorder_->ExpectEntryMetric(
       entry,
+      ukm::builders::LoadingPredictor::
+          kNavigationStartToOptimizationGuidePredictionArrivedName,
+      3);
+  ukm_recorder_->ExpectEntryMetric(
+      entry,
       ukm::builders::LoadingPredictor::kOptimizationGuidePredictionOriginsName,
       4);
   ukm_recorder_->ExpectEntryMetric(
@@ -362,8 +376,10 @@
   resources.push_back(
       CreateResourceLoadInfo("http://cdn.google.com/script.js",
                              network::mojom::RequestDestination::kScript));
+  base::TimeTicks now = base::TimeTicks::Now();
   PageRequestSummary summary =
-      CreatePageRequestSummary(main_frame_url, main_frame_url, resources);
+      CreatePageRequestSummary(main_frame_url, main_frame_url, resources, now);
+  summary.navigation_committed = now + base::TimeDelta::FromMilliseconds(3);
   stats_collector_->RecordPageRequestSummary(summary, base::nullopt);
 
   // No histograms should be recorded.
@@ -375,6 +391,11 @@
       internal::kLoadingPredictorPreresolveCount, 0);
   histogram_tester_->ExpectTotalCount(
       internal::kLoadingPredictorPreconnectCount, 0);
+  // UKM should not be recorded since we did not have predictions for the
+  // navigation.
+  auto entries = ukm_recorder_->GetEntriesByName(
+      ukm::builders::LoadingPredictor::kEntryName);
+  EXPECT_EQ(0u, entries.size());
 }
 
 // Tests that the preconnect won't divide by zero if preconnect stats contain
diff --git a/chrome/browser/predictors/loading_test_util.cc b/chrome/browser/predictors/loading_test_util.cc
index 63fdf102..3339bde 100644
--- a/chrome/browser/predictors/loading_test_util.cc
+++ b/chrome/browser/predictors/loading_test_util.cc
@@ -95,9 +95,11 @@
 PageRequestSummary CreatePageRequestSummary(
     const std::string& main_frame_url,
     const std::string& initial_url,
-    const std::vector<blink::mojom::ResourceLoadInfoPtr>& resource_load_infos) {
+    const std::vector<blink::mojom::ResourceLoadInfoPtr>& resource_load_infos,
+    base::TimeTicks navigation_started) {
   NavigationID navigation_id;
   navigation_id.main_frame_url = GURL(main_frame_url);
+  navigation_id.creation_time = navigation_started;
   PageRequestSummary summary(navigation_id);
   summary.initial_url = GURL(initial_url);
   for (const auto& resource_load_info : resource_load_infos)
diff --git a/chrome/browser/predictors/loading_test_util.h b/chrome/browser/predictors/loading_test_util.h
index 5ee5e14..7981a9f 100644
--- a/chrome/browser/predictors/loading_test_util.h
+++ b/chrome/browser/predictors/loading_test_util.h
@@ -69,7 +69,8 @@
 PageRequestSummary CreatePageRequestSummary(
     const std::string& main_frame_url,
     const std::string& initial_url,
-    const std::vector<blink::mojom::ResourceLoadInfoPtr>& resource_load_infos);
+    const std::vector<blink::mojom::ResourceLoadInfoPtr>& resource_load_infos,
+    base::TimeTicks navigation_started = base::TimeTicks::Now());
 
 blink::mojom::ResourceLoadInfoPtr CreateResourceLoadInfo(
     const std::string& url,
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h
index 682399a..a4cef88 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -122,6 +122,7 @@
   optimization_guide::OptimizationGuideDecision decision;
   PreconnectPrediction preconnect_prediction;
   std::vector<GURL> predicted_subresources;
+  base::Optional<base::TimeTicks> optimization_guide_prediction_arrived;
 };
 
 // Contains logic for learning what can be prefetched and for kicking off
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index c9a91fb..dd7bc12 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -423,13 +423,6 @@
     public static final String FLAGS_CACHED_START_SURFACE_ENABLED = "start_surface_enabled";
 
     /**
-     * Whether or not the start surface single pane is enabled.
-     * Default value is false.
-     */
-    public static final String START_SURFACE_SINGLE_PANE_ENABLED_KEY =
-            "start_surface_single_pane_enabled";
-
-    /**
      * Key to cache whether SWAP_PIXEL_FORMAT_TO_FIX_CONVERT_FROM_TRANSLUCENT is enabled.
      */
     public static final String FLAGS_CACHED_SWAP_PIXEL_FORMAT_TO_FIX_CONVERT_FROM_TRANSLUCENT =
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
index 79d5363a..e33f936 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
@@ -62,6 +62,7 @@
                 "physical_web",
                 "physical_web_sharing",
                 "sole_integration_enabled",
+                "start_surface_single_pane_enabled",
                 "tab_persistent_store_task_runner_enabled",
                 "webapk_number_of_uninstalls",
                 "website_settings_filter"
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java
index b0a8ee75..8868f83 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/GrandfatheredChromePreferenceKeys.java
@@ -170,7 +170,6 @@
                 ChromePreferenceKeys.SIGNIN_PROMO_PERSONALIZED_DECLINED,
                 ChromePreferenceKeys.SIGNIN_PROMO_SETTINGS_PERSONALIZED_DISMISSED,
                 ChromePreferenceKeys.SNAPSHOT_DATABASE_REMOVED,
-                ChromePreferenceKeys.START_SURFACE_SINGLE_PANE_ENABLED_KEY,
                 ChromePreferenceKeys.SURVEY_DATE_LAST_ROLLED,
                 ChromePreferenceKeys.SURVEY_INFO_BAR_DISPLAYED,
                 ChromePreferenceKeys.SYNC_SESSIONS_UUID,
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 8b937632..63f3732 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -183,7 +183,7 @@
 namespace chrome {
 
 void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsProfiles());
+  main_parts->AddParts(std::make_unique<ChromeBrowserMainExtraPartsProfiles>());
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
index 7081eef..7c524de 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel.js
@@ -11,17 +11,19 @@
 goog.require('AnnotationsUI');
 goog.require('BackgroundKeyboardHandler');
 goog.require('BrailleCommandData');
+goog.require('ChromeVoxKbHandler');
 goog.require('ChromeVoxState');
+goog.require('CommandStore');
 goog.require('EventSourceType');
 goog.require('GestureCommandData');
 goog.require('ISearchUI');
+goog.require('LocaleOutputHelper');
 goog.require('Msgs');
 goog.require('PanelCommand');
 goog.require('PanelMenu');
 goog.require('PanelMenuItem');
 goog.require('Tutorial');
-goog.require('ChromeVoxKbHandler');
-goog.require('CommandStore');
+goog.require('UserAnnotationHandler');
 
 /**
  * Class to manage the panel.
@@ -59,6 +61,7 @@
     // part of |Background| construction).
     new ChromeVoxState();
     UserAnnotationHandler.init();
+    LocaleOutputHelper.init();
 
     /** @type {Element} @private */
     Panel.speechContainer_ = $('speech-container');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js
index 1b2326e..df37f23 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/panel/panel_test.js
@@ -111,6 +111,13 @@
       <a href="#">banana</a>
     `;
   }
+
+  get internationalButtonDoc() {
+    return `
+      <button lang="en">Test</button>
+      <button lang="es">Prueba</button>
+    `;
+  }
 };
 
 TEST_F('ChromeVoxPanelTest', 'ActivateMenu', function() {
@@ -193,3 +200,20 @@
         await this.waitForMenu('panel_menu_jump');
       }, {isAsync: true});
 });
+
+TEST_F('ChromeVoxPanelTest', 'InternationalFormControlsMenu', function() {
+  this.runWithLoadedTree(this.internationalButtonDoc, async function(root) {
+    // Turn on language switching and set available voice list.
+    localStorage['languageSwitching'] = 'true';
+    this.getPanelWindow().LocaleOutputHelper.instance.availableVoices_ =
+        [{'lang': 'en-US'}, {'lang': 'es-ES'}];
+    CommandHandler.onCommand('showFormsList');
+    await this.waitForMenu('panel_menu_form_controls');
+    this.fireMockEvent('ArrowDown')();
+    this.assertActiveMenuItem(
+        'panel_menu_form_controls', 'español: Prueba Button');
+    this.fireMockEvent('ArrowUp')();
+    this.assertActiveMenuItem(
+        'panel_menu_form_controls', 'English: Test Button');
+  }, {isAsync: true});
+});
diff --git a/chrome/browser/resources/nearby_internals/.eslintrc.js b/chrome/browser/resources/nearby_internals/.eslintrc.js
new file mode 100644
index 0000000..18f6e95
--- /dev/null
+++ b/chrome/browser/resources/nearby_internals/.eslintrc.js
@@ -0,0 +1,11 @@
+// Copyright 2020 The Chromium 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.exports = {
+  'env': {
+    'browser': true,
+    'es6': true,
+  },
+  'rules': {'eqeqeq': ['error', 'always', {'null': 'ignore'}]},
+};
diff --git a/chrome/browser/resources/nearby_internals/BUILD.gn b/chrome/browser/resources/nearby_internals/BUILD.gn
index 660785ed..0146dfc 100644
--- a/chrome/browser/resources/nearby_internals/BUILD.gn
+++ b/chrome/browser/resources/nearby_internals/BUILD.gn
@@ -8,14 +8,20 @@
 js_type_check("closure_compile") {
   is_polymer3 = true
   deps = [
+    ":log_object",
     ":logging_tab",
     ":nearby_internals",
+    ":nearby_logs_browser_proxy",
+    ":types",
   ]
 }
 
 js_library("nearby_internals") {
   deps = [
+    ":log_object",
     ":logging_tab",
+    ":nearby_logs_browser_proxy",
+    ":types",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/js:cr.m",
   ]
@@ -23,13 +29,41 @@
 
 js_library("logging_tab") {
   deps = [
+    ":log_object",
+    ":nearby_logs_browser_proxy",
+    ":types",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js:web_ui_listener_behavior.m",
+  ]
+}
+
+js_library("log_object") {
+  deps = [
+    ":nearby_logs_browser_proxy",
+    ":types",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
 }
 
+js_library("nearby_logs_browser_proxy") {
+  deps = [
+    ":types",
+    "//ui/webui/resources/js:cr.m",
+  ]
+}
+
+js_library("types") {
+}
+
+js_library("shared_style") {
+}
+
 html_to_js("web_components") {
   js_files = [
+    "log_object.js",
     "logging_tab.js",
     "nearby_internals.js",
+    "shared_style.js",
   ]
 }
diff --git a/chrome/browser/resources/nearby_internals/log_object.html b/chrome/browser/resources/nearby_internals/log_object.html
new file mode 100644
index 0000000..39b2490
--- /dev/null
+++ b/chrome/browser/resources/nearby_internals/log_object.html
@@ -0,0 +1,45 @@
+<style>
+  :host {
+    --large-font-size: 120%;
+  }
+
+  .warning-log {
+    background-color: rgb(255, 252, 239);
+    color: rgb(49, 34, 0);
+    font-size: var(--large-font-size);
+  }
+
+  .error-log {
+    background-color: rgb(255, 241, 241);
+    color: rgb(239, 0, 0);
+    font-size: var(--large-font-size);
+  }
+
+  #item-metadata {
+    color: #888;
+    display: flex;
+    font-size: 10px;
+    margin-bottom: 4px;
+    padding: 6px;
+  }
+
+  #flex {
+    flex: 1;
+  }
+
+  #text {
+    display: inline-block;
+    margin: 3px;
+    padding: 5px;
+    text-align: left;
+    width: 100%;
+  }
+</style>
+<div id="item" severity="[[item.severity]]">
+  <p id="text">[[item.text]]</p>
+  <div id="item-metadata">
+    <span>[[item.time]]</span>
+    <div id="flex"></div>
+    <span>[[item.file]]:[[item.line]]</span>
+  </div>
+</div>
diff --git a/chrome/browser/resources/nearby_internals/log_object.js b/chrome/browser/resources/nearby_internals/log_object.js
new file mode 100644
index 0000000..281c4d9
--- /dev/null
+++ b/chrome/browser/resources/nearby_internals/log_object.js
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium 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 {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {Severity} from './types.js';
+
+Polymer({
+  is: 'log-object',
+
+  _template: html`{__html_template__}`,
+
+  properties: {
+    /**
+     * Underlying LogMessage data for this item. Contains read-only fields
+     * from the NearbyShare backend, as well as fields computed by logging tab.
+     * Type: {!LogMessage}
+     */
+    item: {
+      type: Object,
+      observer: 'itemChanged_',
+    },
+  },
+
+  /**
+   * Sets the log message style based on severity level.
+   * @private
+   */
+  itemChanged_() {
+    switch (this.item.severity) {
+      case Severity.WARNING:
+        this.$['item'].classList.add('warning-log');
+        break;
+      case Severity.ERROR:
+        this.$['item'].classList.add('error-log');
+        break;
+      default:
+        break;
+    }
+  },
+});
diff --git a/chrome/browser/resources/nearby_internals/logging_tab.html b/chrome/browser/resources/nearby_internals/logging_tab.html
index 2c4bb6df..3bfb9b6 100644
--- a/chrome/browser/resources/nearby_internals/logging_tab.html
+++ b/chrome/browser/resources/nearby_internals/logging_tab.html
@@ -1 +1,35 @@
-<h1>Logs page coming soon.</h1>
+<style include="shared-style">
+  :host {
+    --standard-border: 1px solid black;
+  }
+
+  #logs-list {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+  }
+
+  log-object {
+    border-top: var(--standard-border);
+    border-right: var(--standard-border);
+    border-left: var(--standard-border);
+  }
+
+  log-object:last-child {
+    border-bottom: var(--standard-border);
+  }
+</style>
+<cr-button disabled="[[!logList_.length]]" class="internals-button"
+    on-click="onSaveLogsButtonClicked_">
+  Save Logs
+</cr-button>
+<cr-button disabled="[[!logList_.length]]" class="internals-button"
+    on-click="onClearLogsButtonClicked_">
+  Clear Logs
+</cr-button>
+<iron-list items="[[logList_]]" as="log" id="logs-list">
+  <template>
+    <log-object item="[[log]]">
+    </log-object>
+  </template>
+</iron-list>
diff --git a/chrome/browser/resources/nearby_internals/logging_tab.js b/chrome/browser/resources/nearby_internals/logging_tab.js
index 0a33963..52e5d75 100644
--- a/chrome/browser/resources/nearby_internals/logging_tab.js
+++ b/chrome/browser/resources/nearby_internals/logging_tab.js
@@ -2,10 +2,162 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import './log_object.js';
+import './shared_style.js';
+import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {NearbyLogsBrowserProxy} from './nearby_logs_browser_proxy.js';
+import {LogMessage, Severity} from './types.js';
+
+/**
+ * Converts log message to string format for saved download file.
+ * @param {!LogMessage} log
+ * @return {string}
+ */
+function logToSavedString_(log) {
+  // Convert to string value for |line.severity|.
+  let severity;
+  switch (log.severity) {
+    case Severity.INFO:
+      severity = 'INFO';
+      break;
+    case Severity.WARNING:
+      severity = 'WARNING';
+      break;
+    case Severity.ERROR:
+      severity = 'ERROR';
+      break;
+    case Severity.VERBOSE:
+      severity = 'VERBOSE';
+      break;
+  }
+
+  // Reduce the file path to just the file name for logging simplification.
+  const file = log.file.substring(log.file.lastIndexOf('/') + 1);
+
+  return `[${log.time} ${severity} ${file} (${log.line})] ${log.text}`;
+}
 
 Polymer({
   is: 'logging-tab',
 
   _template: html`{__html_template__}`,
+
+  behaviors: [
+    WebUIListenerBehavior,
+  ],
+
+  properties: {
+
+    /**
+     * @private {!Array<!LogMessage>}
+     */
+    logList_: {
+      type: Array,
+      value: [],
+    },
+  },
+
+  /** @private {?NearbyLogsBrowserProxy}*/
+  browserProxy_: null,
+
+  /**
+   * Initialize |browserProxy_| and |logList_|.
+   * @override
+   */
+  created() {
+    this.browserProxy_ = NearbyLogsBrowserProxy.getInstance();
+  },
+
+  /**
+   * When the page is initialized, notify the C++ layer and load in the
+   * contents of its log buffer. Initialize WebUI Listeners.
+   * @override
+   */
+  attached() {
+    this.addWebUIListener(
+        'log-message-added', log => this.onLogMessageAdded_(log));
+    this.addWebUIListener(
+        'log-buffer-cleared', () => this.onWebUILogBufferCleared_());
+    this.browserProxy_.getLogMessages().then(
+        logs => this.parseAndAddLogs_(logs));
+  },
+
+  /**
+   * Clears javascript logs displayed, but c++ log buffer remains.
+   * @private
+   */
+  onClearLogsButtonClicked_() {
+    this.clearLogBuffer_();
+  },
+
+  /**
+   * Saves and downloads javascript logs that appear on the page.
+   * @private
+   */
+  onSaveLogsButtonClicked_() {
+    const blob = new Blob(
+        this.getSerializedLogStrings_(), {type: 'text/plain;charset=utf-8'});
+    const url = URL.createObjectURL(blob);
+
+    const anchorElement = document.createElement('a');
+    anchorElement.href = url;
+    anchorElement.download =
+        'nearby_internals_logs_' + new Date().toJSON() + '.txt';
+    document.body.appendChild(anchorElement);
+    anchorElement.click();
+
+    window.setTimeout(function() {
+      document.body.removeChild(anchorElement);
+      window.URL.revokeObjectURL(url);
+    }, 0);
+  },
+
+  /**
+   * Iterates through log messages in |logList_| and prepares them for download.
+   * @private
+   * @return
+   */
+  getSerializedLogStrings_() {
+    return this.logList_.map(logToSavedString_);
+  },
+
+  /**
+   * Adds a log message to the javascript log list displayed. Called from the
+   * C++ WebUI handler when a log message is added to the log buffer.
+   * @param {!Array<!LogMessage>} log
+   * @private
+   */
+  onLogMessageAdded_(log) {
+    this.parseAndAddLogs_([log]);
+  },
+
+  /**
+   * Called in response to WebUI handler clearing log buffer.
+   * @private
+   */
+  onWebUILogBufferCleared_() {
+    this.clearLogBuffer_();
+  },
+
+  /**
+   * Parses an array of log messages and adds to the javascript list.
+   * @param {!Array<!LogMessage>} logs
+   * @private
+   */
+  parseAndAddLogs_(logs) {
+    logs.unshift('logList_');
+    this.push.apply(this, logs);
+  },
+
+  /**
+   * Clears the javascript log buffer.
+   * @private
+   */
+  clearLogBuffer_() {
+    this.logList_ = [];
+  },
 });
diff --git a/chrome/browser/resources/nearby_internals/nearby_internals.html b/chrome/browser/resources/nearby_internals/nearby_internals.html
index 31b14f8..8b4d4b5 100644
--- a/chrome/browser/resources/nearby_internals/nearby_internals.html
+++ b/chrome/browser/resources/nearby_internals/nearby_internals.html
@@ -20,11 +20,10 @@
   }
 
   iron-pages > * {
-    display: flex;
+    display: block;
     height: 100%;
     overflow: auto;
   }
-
 </style>
 <app-header>
   <app-toolbar>Nearby Share Internals</app-toolbar>
diff --git a/chrome/browser/resources/nearby_internals/nearby_internals.js b/chrome/browser/resources/nearby_internals/nearby_internals.js
index fa8f28c8..493ecd5 100644
--- a/chrome/browser/resources/nearby_internals/nearby_internals.js
+++ b/chrome/browser/resources/nearby_internals/nearby_internals.js
@@ -7,6 +7,7 @@
 import 'chrome://resources/polymer/v3_0/iron-pages/iron-pages.js';
 import './logging_tab.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {NearbyLogsBrowserProxy} from './nearby_logs_browser_proxy.js';
 
 Polymer({
   is: 'nearby-internals',
@@ -34,6 +35,7 @@
       value: () => ['Logs'],
       readonly: true,
     },
+
   },
 
   /**
diff --git a/chrome/browser/resources/nearby_internals/nearby_internals_resources.grd b/chrome/browser/resources/nearby_internals/nearby_internals_resources.grd
index 527c745..296ad46 100644
--- a/chrome/browser/resources/nearby_internals/nearby_internals_resources.grd
+++ b/chrome/browser/resources/nearby_internals/nearby_internals_resources.grd
@@ -11,10 +11,17 @@
     <output filename="nearby_internals_resources.pak" type="data_package" />
   </outputs>
   <release seq="1">
-    <includes>
+   <includes>
+      <include name="IDR_NEARBY_INTERNALS_TYPES_JS"
+               file="types.js"
+               type="BINDATA"/>
       <include name="IDR_NEARBY_INTERNALS_INDEX_HTML"
                file="index.html"
                type="BINDATA"/>
+      <include name="IDR_NEARBY_INTERNALS_LOG_OBJECT_JS"
+               file="${root_gen_dir}\chrome\browser\resources\nearby_internals\log_object.js"
+               use_base_dir="false"
+               type="BINDATA"/>
       <include name="IDR_NEARBY_INTERNALS_LOGGING_TAB_JS"
                file="${root_gen_dir}\chrome\browser\resources\nearby_internals\logging_tab.js"
                use_base_dir="false"
@@ -23,6 +30,13 @@
                file="${root_gen_dir}\chrome\browser\resources\nearby_internals\nearby_internals.js"
                use_base_dir="false"
                type="BINDATA"/>
+      <include name="IDR_NEARBY_INTERNALS_NEARBY_LOGS_BROWSER_PROXY_JS"
+               file="nearby_logs_browser_proxy.js"
+               type="BINDATA"/>
+      <include name="IDR_NEARBY_INTERNALS_SHARED_STYLE_JS"
+               file="${root_gen_dir}\chrome\browser\resources\nearby_internals\shared_style.js"
+               use_base_dir="false"
+               type="BINDATA"/>
     </includes>
   </release>
 </grit>
diff --git a/chrome/browser/resources/nearby_internals/nearby_logs_browser_proxy.js b/chrome/browser/resources/nearby_internals/nearby_logs_browser_proxy.js
new file mode 100644
index 0000000..d962138
--- /dev/null
+++ b/chrome/browser/resources/nearby_internals/nearby_logs_browser_proxy.js
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium 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 {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {LogMessage} from './types.js';
+
+/**
+ * JavaScript hooks into the native WebUI handler to pass LogMessages to the
+ * logging tab.
+ */
+export class NearbyLogsBrowserProxy {
+  /**
+   * @return {!Promise<!Array<!LogMessage>>}
+   */
+  getLogMessages() {
+    return sendWithPromise('getLogMessages');
+  }
+}
+
+addSingletonGetter(NearbyLogsBrowserProxy);
diff --git a/chrome/browser/resources/nearby_internals/shared_style.html b/chrome/browser/resources/nearby_internals/shared_style.html
new file mode 100644
index 0000000..30ec9f47
--- /dev/null
+++ b/chrome/browser/resources/nearby_internals/shared_style.html
@@ -0,0 +1,14 @@
+<template>
+  <style include="cr-shared-style">
+    :host {
+      cursor: default;
+      font-family: Roboto, Roboto, sans-serif;
+    }
+
+    .internals-button {
+      background-color: rgb(0, 134, 179);
+      color: white;
+      margin: 5px;
+    }
+  </style>
+</template>
diff --git a/chrome/browser/resources/nearby_internals/shared_style.js b/chrome/browser/resources/nearby_internals/shared_style.js
new file mode 100644
index 0000000..ce15f967
--- /dev/null
+++ b/chrome/browser/resources/nearby_internals/shared_style.js
@@ -0,0 +1,10 @@
+// Copyright 2020 The Chromium 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 'chrome://resources/cr_elements/shared_style_css.m.js';
+const template = document.createElement('template');
+template.innerHTML = `
+<dom-module id="shared-style">{__html_template__}</dom-module>
+`;
+document.body.appendChild(template.content.cloneNode(true));
diff --git a/chrome/browser/resources/nearby_internals/types.js b/chrome/browser/resources/nearby_internals/types.js
new file mode 100644
index 0000000..e21b162a
--- /dev/null
+++ b/chrome/browser/resources/nearby_internals/types.js
@@ -0,0 +1,27 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * Severity enum based on LogMessage format. Needs to stay in sync with the
+ * NearbyInternalsLogsHandler.
+ * @enum {number}
+ */
+export const Severity = {
+  INFO: 0,
+  WARNING: 1,
+  ERROR: 2,
+  VERBOSE: 3
+};
+
+/**
+ * The type of log message object. The definition is based on
+ * chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.cc:
+ * LogMessageToDictionary()
+ * @typedef {{text: string,
+ *            time: string,
+ *            file: string,
+ *            line: number,
+ *            severity: Severity}}
+ */
+export let LogMessage;
diff --git a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html
index 3b154e4..6b82610 100644
--- a/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html
+++ b/chrome/browser/resources/print_preview/ui/destination_dropdown_cros.html
@@ -9,6 +9,7 @@
   }
 
   cr-input::part(input) {
+    cursor: pointer;
     opacity: 1;
     padding-inline-end: 32px;
     padding-inline-start: 8px;
@@ -74,6 +75,7 @@
     background: none;
     border: none;
     box-sizing: border-box;
+    cursor: pointer;
     font: inherit;
     min-height: 32px;
     padding: 0 8px;
@@ -101,6 +103,10 @@
   .printer-display-name {
     padding-inline-start: 8px;
   }
+
+  #pre-input-box {
+    cursor: pointer;
+  }
 </style>
 <cr-input id="dropdownInput" on-keydown="onKeyDown_"
     value="[[value.displayName]]" disabled="[[disabled]]" readonly>
diff --git a/chrome/browser/resources/print_preview/ui/destination_select_cros.js b/chrome/browser/resources/print_preview/ui/destination_select_cros.js
index accf66c5..71c0b628 100644
--- a/chrome/browser/resources/print_preview/ui/destination_select_cros.js
+++ b/chrome/browser/resources/print_preview/ui/destination_select_cros.js
@@ -388,9 +388,7 @@
    */
   getErrorString_: function(printerStatusReason) {
     const errorTextKey = ERROR_STRING_KEY_MAP.get(printerStatusReason);
-    return errorTextKey ?
-        this.i18n(errorTextKey, this.destination.displayName) :
-        '';
+    return errorTextKey ? this.i18n(errorTextKey) : '';
   },
 
   /**
diff --git a/chrome/browser/sessions/session_common_utils.h b/chrome/browser/sessions/session_common_utils.h
index 08df1c8..6d7c1845 100644
--- a/chrome/browser/sessions/session_common_utils.h
+++ b/chrome/browser/sessions/session_common_utils.h
@@ -12,8 +12,8 @@
 class GURL;
 
 // Returns whether sessions code should track a URL for restoring in the context
-// of //chrome. In particular, blacklists chrome://quit and chrome://restart to
-// avoid quit or restart loops.
+// of //chrome. In particular, does not allow chrome://quit and
+// chrome://restart to avoid quit or restart loops.
 bool ShouldTrackURLForRestore(const GURL& url);
 
 // Returns the current navigation index from the tab. If current navigation's
diff --git a/chrome/browser/sessions/session_service_unittest.cc b/chrome/browser/sessions/session_service_unittest.cc
index 8d1cda8..718e1e6 100644
--- a/chrome/browser/sessions/session_service_unittest.cc
+++ b/chrome/browser/sessions/session_service_unittest.cc
@@ -1117,8 +1117,8 @@
   EXPECT_EQ(window2_id, active_window_id);
 }
 
-// Makes sure we don't track blacklisted URLs.
-TEST_F(SessionServiceTest, IgnoreBlacklistedUrls) {
+// Makes sure sessions doesn't track certain urls.
+TEST_F(SessionServiceTest, IgnoreBlockedUrls) {
   SessionID tab_id = SessionID::NewUnique();
 
   SerializedNavigationEntry nav1 =
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 490fc9d..dab44a0 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1316,6 +1316,8 @@
       "webui/media_router/media_router_internals_webui_message_handler.cc",
       "webui/media_router/media_router_internals_webui_message_handler.h",
       "webui/media_router/web_contents_display_observer.h",
+      "webui/nearby_internals/nearby_internals_logs_handler.cc",
+      "webui/nearby_internals/nearby_internals_logs_handler.h",
       "webui/nearby_internals/nearby_internals_ui.cc",
       "webui/nearby_internals/nearby_internals_ui.h",
       "webui/nearby_share/nearby_share_dialog_ui.cc",
@@ -1489,6 +1491,7 @@
       "//device/bluetooth",
       "//device/bluetooth/strings:strings_grit",
       "//device/fido",
+      "//ppapi/c",
       "//services/device/public/mojom",
       "//services/metrics/public/cpp:metrics_cpp",
       "//services/preferences/public/mojom:mojom",
diff --git a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuAdapterRenderTest.java b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuAdapterRenderTest.java
index 76984b2..ff5e73b 100644
--- a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuAdapterRenderTest.java
+++ b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuAdapterRenderTest.java
@@ -66,7 +66,8 @@
     }
 
     @Rule
-    public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
 
     @Override
     public void setUpTest() throws Exception {
diff --git a/chrome/browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller.cc
index c93394a..305761f 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller.h"
 
 #include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
 #include "chrome/browser/ui/passwords/passwords_model_delegate.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
@@ -83,9 +84,22 @@
 }
 
 void PostSaveCompromisedBubbleController::OnAccepted() {
+  using password_manager::PasswordCheckReferrer;
   checked_clicked_ = true;
+  PasswordCheckReferrer referrer;
+  switch (type_) {
+    case BubbleType::kPasswordUpdatedSafeState:
+      NOTREACHED();
+      return;
+    case BubbleType::kPasswordUpdatedWithMoreToFix:
+      referrer = PasswordCheckReferrer::kMoreToFixBubble;
+      break;
+    case BubbleType::kUnsafeState:
+      referrer = PasswordCheckReferrer::kUnsafeStateBubble;
+      break;
+  }
   if (delegate_)
-    delegate_->NavigateToPasswordCheckup();
+    delegate_->NavigateToPasswordCheckup(referrer);
 }
 
 base::string16 PostSaveCompromisedBubbleController::GetTitle() const {
diff --git a/chrome/browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller_unittest.cc
index 7a64597..7b655208 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller_unittest.cc
@@ -110,7 +110,9 @@
   base::HistogramTester histogram_tester;
   CreateController(password_manager::ui::PASSWORD_UPDATED_MORE_TO_FIX);
 
-  EXPECT_CALL(*delegate(), NavigateToPasswordCheckup());
+  EXPECT_CALL(*delegate(),
+              NavigateToPasswordCheckup(
+                  password_manager::PasswordCheckReferrer::kMoreToFixBubble));
   controller()->OnAccepted();
   ResetController();
   histogram_tester.ExpectUniqueSample(kCheckedHistogram, true, 1);
@@ -148,7 +150,9 @@
   base::HistogramTester histogram_tester;
   CreateController(password_manager::ui::PASSWORD_UPDATED_UNSAFE_STATE);
 
-  EXPECT_CALL(*delegate(), NavigateToPasswordCheckup());
+  EXPECT_CALL(*delegate(),
+              NavigateToPasswordCheckup(
+                  password_manager::PasswordCheckReferrer::kUnsafeStateBubble));
   controller()->OnAccepted();
   ResetController();
   histogram_tester.ExpectUniqueSample(kCheckedHistogram, true, 1);
diff --git a/chrome/browser/ui/passwords/credential_leak_dialog_controller_impl.cc b/chrome/browser/ui/passwords/credential_leak_dialog_controller_impl.cc
index 3a25bd9..59e157b 100644
--- a/chrome/browser/ui/passwords/credential_leak_dialog_controller_impl.cc
+++ b/chrome/browser/ui/passwords/credential_leak_dialog_controller_impl.cc
@@ -47,7 +47,8 @@
     LogLeakDialogTypeAndDismissalReason(
         password_manager::GetLeakDialogType(leak_type_),
         LeakDialogDismissalReason::kClickedCheckPasswords);
-    delegate_->NavigateToPasswordCheckup();
+    delegate_->NavigateToPasswordCheckup(
+        password_manager::PasswordCheckReferrer::kPasswordBreachDialog);
   } else {
     LogLeakDialogTypeAndDismissalReason(
         password_manager::GetLeakDialogType(leak_type_),
diff --git a/chrome/browser/ui/passwords/credential_leak_dialog_controller_impl_unittest.cc b/chrome/browser/ui/passwords/credential_leak_dialog_controller_impl_unittest.cc
index e9802bf..9be7003 100644
--- a/chrome/browser/ui/passwords/credential_leak_dialog_controller_impl_unittest.cc
+++ b/chrome/browser/ui/passwords/credential_leak_dialog_controller_impl_unittest.cc
@@ -127,7 +127,10 @@
   EXPECT_CALL(leak_prompt(), ShowCredentialLeakPrompt());
   controller().ShowCredentialLeakPrompt(&leak_prompt());
 
-  EXPECT_CALL(ui_controller_mock(), NavigateToPasswordCheckup());
+  EXPECT_CALL(
+      ui_controller_mock(),
+      NavigateToPasswordCheckup(
+          password_manager::PasswordCheckReferrer::kPasswordBreachDialog));
   EXPECT_CALL(ui_controller_mock(), OnLeakDialogHidden());
   controller().OnAcceptDialog();
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index bcb91eb..c9d3b966 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -594,13 +594,13 @@
       referrer);
 }
 
-void ManagePasswordsUIController::NavigateToPasswordCheckup() {
+void ManagePasswordsUIController::NavigateToPasswordCheckup(
+    password_manager::PasswordCheckReferrer referrer) {
   if (base::FeatureList::IsEnabled(
           password_manager::features::kPasswordCheck)) {
     chrome::ShowPasswordCheck(
         chrome::FindBrowserWithWebContents(web_contents()));
-    password_manager::LogPasswordCheckReferrer(
-        password_manager::PasswordCheckReferrer::kPasswordBreachDialog);
+    password_manager::LogPasswordCheckReferrer(referrer);
   } else {
     NavigateToPasswordCheckupPage(
         Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
index d626c031..5c3fcb5e 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.h
@@ -216,7 +216,8 @@
   friend class content::WebContentsUserData<ManagePasswordsUIController>;
 
   // PasswordsLeakDialogDelegate:
-  void NavigateToPasswordCheckup() override;
+  void NavigateToPasswordCheckup(
+      password_manager::PasswordCheckReferrer referrer) override;
   void OnLeakDialogHidden() override;
 
   enum class BubbleStatus {
diff --git a/chrome/browser/ui/passwords/passwords_leak_dialog_delegate.h b/chrome/browser/ui/passwords/passwords_leak_dialog_delegate.h
index d0a0d3b..f29078584 100644
--- a/chrome/browser/ui/passwords/passwords_leak_dialog_delegate.h
+++ b/chrome/browser/ui/passwords/passwords_leak_dialog_delegate.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_PASSWORDS_PASSWORDS_LEAK_DIALOG_DELEGATE_H_
 #define CHROME_BROWSER_UI_PASSWORDS_PASSWORDS_LEAK_DIALOG_DELEGATE_H_
 
+#include "components/password_manager/core/browser/ui/password_check_referrer.h"
+
 // An interface for leak detection dialog implemented by
 // ManagePasswordsUIController. Allows to retrieve the current state of the tab
 // and notify about user actions.
@@ -14,7 +16,8 @@
   virtual void OnLeakDialogHidden() = 0;
 
   // Open a new tab pointing to Password Checkup.
-  virtual void NavigateToPasswordCheckup() = 0;
+  virtual void NavigateToPasswordCheckup(
+      password_manager::PasswordCheckReferrer referrer) = 0;
 
  protected:
   virtual ~PasswordsLeakDialogDelegate() = default;
diff --git a/chrome/browser/ui/passwords/passwords_leak_dialog_delegate_mock.h b/chrome/browser/ui/passwords/passwords_leak_dialog_delegate_mock.h
index fdfaf004..2c559afa 100644
--- a/chrome/browser/ui/passwords/passwords_leak_dialog_delegate_mock.h
+++ b/chrome/browser/ui/passwords/passwords_leak_dialog_delegate_mock.h
@@ -14,8 +14,11 @@
   PasswordsLeakDialogDelegateMock();
   ~PasswordsLeakDialogDelegateMock() override;
 
-  MOCK_METHOD0(OnLeakDialogHidden, void());
-  MOCK_METHOD0(NavigateToPasswordCheckup, void());
+  MOCK_METHOD(void, OnLeakDialogHidden, (), (override));
+  MOCK_METHOD(void,
+              NavigateToPasswordCheckup,
+              (password_manager::PasswordCheckReferrer),
+              (override));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(PasswordsLeakDialogDelegateMock);
diff --git a/chrome/browser/ui/passwords/passwords_model_delegate.h b/chrome/browser/ui/passwords/passwords_model_delegate.h
index 1899110..73a28e9 100644
--- a/chrome/browser/ui/passwords/passwords_model_delegate.h
+++ b/chrome/browser/ui/passwords/passwords_model_delegate.h
@@ -10,6 +10,7 @@
 
 #include "base/memory/weak_ptr.h"
 #include "components/password_manager/core/browser/manage_passwords_referrer.h"
+#include "components/password_manager/core/browser/ui/password_check_referrer.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "components/password_manager/core/common/password_manager_ui.h"
 
@@ -141,7 +142,8 @@
   virtual void NavigateToPasswordManagerSettingsPage(
       password_manager::ManagePasswordsReferrer referrer) = 0;
   // Open a new tab, pointing to the password check in the settings page.
-  virtual void NavigateToPasswordCheckup() = 0;
+  virtual void NavigateToPasswordCheckup(
+      password_manager::PasswordCheckReferrer referrer) = 0;
   // Called by the view when the "Sign in to Chrome" button or the "Sync to"
   // button in the promo bubble are clicked.
   virtual void EnableSync(const AccountInfo& account,
diff --git a/chrome/browser/ui/passwords/passwords_model_delegate_mock.h b/chrome/browser/ui/passwords/passwords_model_delegate_mock.h
index a62699a..78d44cc 100644
--- a/chrome/browser/ui/passwords/passwords_model_delegate_mock.h
+++ b/chrome/browser/ui/passwords/passwords_model_delegate_mock.h
@@ -20,55 +20,88 @@
   PasswordsModelDelegateMock();
   ~PasswordsModelDelegateMock() override;
 
-  MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
-  MOCK_METHOD0(GetPasswordFormMetricsRecorder,
-               password_manager::PasswordFormMetricsRecorder*());
-  MOCK_METHOD0(GetPasswordFeatureManager,
-               password_manager::PasswordFeatureManager*());
-  MOCK_CONST_METHOD0(GetOrigin, url::Origin());
-  MOCK_CONST_METHOD0(GetState, password_manager::ui::State());
-  MOCK_CONST_METHOD0(GetPendingPassword, const autofill::PasswordForm&());
-  MOCK_CONST_METHOD0(GetUnsyncedCredentials,
-                     const std::vector<autofill::PasswordForm>&());
-  MOCK_CONST_METHOD0(GetCredentialSource,
-                     password_manager::metrics_util::CredentialSourceType());
-  MOCK_CONST_METHOD0(
-      GetCurrentForms,
-      const std::vector<std::unique_ptr<autofill::PasswordForm>>&());
-  MOCK_CONST_METHOD0(GetCurrentInteractionStats,
-                     password_manager::InteractionsStats*());
-  MOCK_CONST_METHOD0(GetTotalNumberCompromisedPasswords, size_t());
-  MOCK_CONST_METHOD0(DidAuthForAccountStoreOptInFail, bool());
-  MOCK_CONST_METHOD0(BubbleIsManualFallbackForSaving, bool());
-  MOCK_METHOD0(OnBubbleShown, void());
-  MOCK_METHOD0(OnBubbleHidden, void());
-  MOCK_METHOD0(OnNoInteraction, void());
-  MOCK_METHOD0(OnNopeUpdateClicked, void());
-  MOCK_METHOD0(NeverSavePassword, void());
-  MOCK_METHOD1(UpdatePassword, void(const autofill::PasswordForm&));
-  MOCK_METHOD0(OnPasswordsRevealed, void());
-  MOCK_METHOD2(SavePassword,
-               void(const base::string16&, const base::string16&));
-  MOCK_METHOD0(SaveUnsyncedCredentialsInProfileStore, void());
-  MOCK_METHOD0(DiscardUnsyncedCredentials, void());
-  MOCK_METHOD0(MovePasswordToAccountStore, void());
-  MOCK_METHOD0(BlockMovingPasswordToAccountStore, void());
-  MOCK_METHOD2(ChooseCredential,
-               void(const autofill::PasswordForm&,
-                    password_manager::CredentialType));
-  MOCK_METHOD1(NavigateToPasswordManagerAccountDashboard,
-               void(password_manager::ManagePasswordsReferrer));
-  MOCK_METHOD1(NavigateToPasswordManagerSettingsPage,
-               void(password_manager::ManagePasswordsReferrer));
-  MOCK_METHOD0(NavigateToPasswordCheckup, void());
-  MOCK_METHOD2(EnableSync,
-               void(const AccountInfo& account, bool is_default_promo_account));
-  MOCK_METHOD0(OnDialogHidden, void());
-  MOCK_METHOD0(AuthenticateUser, bool());
-  MOCK_METHOD2(AuthenticateUserForAccountStoreOptInAndSavePassword,
-               void(const base::string16&, const base::string16&));
-  MOCK_METHOD0(AuthenticateUserForAccountStoreOptInAndMovePassword, void());
-  MOCK_CONST_METHOD0(ArePasswordsRevealedWhenBubbleIsOpened, bool());
+  MOCK_METHOD(content::WebContents*, GetWebContents, (), (const override));
+  MOCK_METHOD(password_manager::PasswordFormMetricsRecorder*,
+              GetPasswordFormMetricsRecorder,
+              (),
+              (override));
+  MOCK_METHOD(password_manager::PasswordFeatureManager*,
+              GetPasswordFeatureManager,
+              (),
+              (override));
+  MOCK_METHOD(url::Origin, GetOrigin, (), (const override));
+  MOCK_METHOD(password_manager::ui::State, GetState, (), (const override));
+  MOCK_METHOD(const autofill::PasswordForm&,
+              GetPendingPassword,
+              (),
+              (const override));
+  MOCK_METHOD(const std::vector<autofill::PasswordForm>&,
+              GetUnsyncedCredentials,
+              (),
+              (const override));
+  MOCK_METHOD(password_manager::metrics_util::CredentialSourceType,
+              GetCredentialSource,
+              (),
+              (const override));
+  MOCK_METHOD(const std::vector<std::unique_ptr<autofill::PasswordForm>>&,
+              GetCurrentForms,
+              (),
+              (const override));
+  MOCK_METHOD(password_manager::InteractionsStats*,
+              GetCurrentInteractionStats,
+              (),
+              (const override));
+  MOCK_METHOD(size_t, GetTotalNumberCompromisedPasswords, (), (const override));
+  MOCK_METHOD(bool, DidAuthForAccountStoreOptInFail, (), (const override));
+  MOCK_METHOD(bool, BubbleIsManualFallbackForSaving, (), (const override));
+  MOCK_METHOD(void, OnBubbleShown, (), (override));
+  MOCK_METHOD(void, OnBubbleHidden, (), (override));
+  MOCK_METHOD(void, OnNoInteraction, (), (override));
+  MOCK_METHOD(void, OnNopeUpdateClicked, (), (override));
+  MOCK_METHOD(void, NeverSavePassword, (), (override));
+  MOCK_METHOD(void, OnPasswordsRevealed, (), (override));
+  MOCK_METHOD(void,
+              SavePassword,
+              (const base::string16&, const base::string16&),
+              (override));
+  MOCK_METHOD(void, SaveUnsyncedCredentialsInProfileStore, (), (override));
+  MOCK_METHOD(void, DiscardUnsyncedCredentials, (), (override));
+  MOCK_METHOD(void, MovePasswordToAccountStore, (), (override));
+  MOCK_METHOD(void, BlockMovingPasswordToAccountStore, (), (override));
+  MOCK_METHOD(void,
+              ChooseCredential,
+              (const autofill::PasswordForm&, password_manager::CredentialType),
+              (override));
+  MOCK_METHOD(void,
+              NavigateToPasswordManagerAccountDashboard,
+              (password_manager::ManagePasswordsReferrer),
+              (override));
+  MOCK_METHOD(void,
+              NavigateToPasswordManagerSettingsPage,
+              (password_manager::ManagePasswordsReferrer),
+              (override));
+  MOCK_METHOD(void,
+              NavigateToPasswordCheckup,
+              (password_manager::PasswordCheckReferrer),
+              (override));
+  MOCK_METHOD(void,
+              EnableSync,
+              (const AccountInfo& account, bool is_default_promo_account),
+              (override));
+  MOCK_METHOD(void, OnDialogHidden, (), (override));
+  MOCK_METHOD(bool, AuthenticateUser, (), (override));
+  MOCK_METHOD(void,
+              AuthenticateUserForAccountStoreOptInAndSavePassword,
+              (const base::string16&, const base::string16&),
+              (override));
+  MOCK_METHOD(void,
+              AuthenticateUserForAccountStoreOptInAndMovePassword,
+              (),
+              (override));
+  MOCK_METHOD(bool,
+              ArePasswordsRevealedWhenBubbleIsOpened,
+              (),
+              (const override));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(PasswordsModelDelegateMock);
diff --git a/chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.cc b/chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.cc
index 1103686..6cd178c 100644
--- a/chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.cc
+++ b/chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.cc
@@ -6,10 +6,24 @@
 
 #include "chrome/browser/download/download_stats.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
+#include "chrome/common/content_restriction.h"
 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
+#include "ppapi/c/private/ppb_pdf.h"
 
 namespace {
 
+// For the UpdateContentRestrictions() call below, ensure the enum values in
+// chrome/common/content_restriction.h and ppapi/c/private/ppb_pdf.h match.
+#define STATIC_ASSERT_ENUM(a, b)                            \
+  static_assert(static_cast<int>(a) == static_cast<int>(b), \
+                "mismatching enums: " #a)
+
+STATIC_ASSERT_ENUM(CONTENT_RESTRICTION_COPY, PP_CONTENT_RESTRICTION_COPY);
+STATIC_ASSERT_ENUM(CONTENT_RESTRICTION_CUT, PP_CONTENT_RESTRICTION_CUT);
+STATIC_ASSERT_ENUM(CONTENT_RESTRICTION_PASTE, PP_CONTENT_RESTRICTION_PASTE);
+STATIC_ASSERT_ENUM(CONTENT_RESTRICTION_PRINT, PP_CONTENT_RESTRICTION_PRINT);
+STATIC_ASSERT_ENUM(CONTENT_RESTRICTION_SAVE, PP_CONTENT_RESTRICTION_SAVE);
+
 content::WebContents* GetWebContentsToUse(
     content::WebContents* web_contents) {
   // If we're viewing the PDF in a MimeHandlerViewGuest, use its embedder
@@ -36,7 +50,7 @@
 
   CoreTabHelper* core_tab_helper =
       CoreTabHelper::FromWebContents(web_contents_to_use);
-  // |core_tab_helper| is NULL for WebViewGuest.
+  // |core_tab_helper| is null for WebViewGuest.
   if (core_tab_helper)
     core_tab_helper->UpdateContentRestrictions(content_restrictions);
 }
diff --git a/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc b/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc
index 0b1f406..3b32f3f 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_interactive_uitest.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 <memory>
 #include <vector>
 
 #include "base/command_line.h"
@@ -148,7 +149,7 @@
     ChromeBrowserMainParts* chrome_browser_main_parts =
         static_cast<ChromeBrowserMainParts*>(browser_main_parts);
     chrome_browser_main_parts->AddParts(
-        new StartupPagePrefSetterMainExtraParts(urls));
+        std::make_unique<StartupPagePrefSetterMainExtraParts>(urls));
   }
 
  private:
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 9d59f1d..f644ee2 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -44,6 +44,7 @@
 #include "chrome/browser/optimization_guide/optimization_guide_web_contents_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_initialize.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
+#include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/performance_hints/performance_hints_observer.h"
 #include "chrome/browser/plugins/pdf_plugin_placeholder_observer.h"
 #include "chrome/browser/predictors/loading_predictor_factory.h"
@@ -334,11 +335,7 @@
   if (OomInterventionTabHelper::IsEnabled()) {
     OomInterventionTabHelper::CreateForWebContents(web_contents);
   }
-  if (base::FeatureList::IsEnabled(
-          chrome::android::kPageInfoPerformanceHints) ||
-      base::FeatureList::IsEnabled(
-          chrome::android::kContextMenuPerformanceInfo) ||
-      base::FeatureList::IsEnabled(kPerformanceHintsObserver)) {
+  if (IsPerformanceHintsObserverEnabled()) {
     PerformanceHintsObserver::CreateForWebContents(web_contents);
   }
   SearchGeolocationDisclosureTabHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/views/crostini/crostini_browser_test_util.cc b/chrome/browser/ui/views/crostini/crostini_browser_test_util.cc
index a704fb1..61c1e87 100644
--- a/chrome/browser/ui/views/crostini/crostini_browser_test_util.cc
+++ b/chrome/browser/ui/views/crostini/crostini_browser_test_util.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_browser_main.h"
@@ -100,7 +101,7 @@
       static_cast<ChromeBrowserMainParts*>(browser_main_parts);
   extra_parts_ =
       new CrostiniBrowserTestChromeBrowserMainExtraParts(register_termina_);
-  chrome_browser_main_parts->AddParts(extra_parts_);
+  chrome_browser_main_parts->AddParts(base::WrapUnique(extra_parts_));
 }
 
 void CrostiniDialogBrowserTest::SetUp() {
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index 9865a1f..36e1883 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -506,13 +506,13 @@
 
   // Set up widget.
 
-  widget_ = views::BubbleDialogDelegateView::CreateBubble(this);
+  views::BubbleDialogDelegateView::CreateBubble(this);
   set_adjust_if_offscreen(true);
 
   slide_animation_delegate_ =
       std::make_unique<WidgetSlideAnimationDelegate>(this);
   fade_animation_delegate_ =
-      std::make_unique<WidgetFadeAnimationDelegate>(widget_);
+      std::make_unique<WidgetFadeAnimationDelegate>(GetWidget());
   thumbnail_observer_ = std::make_unique<ThumbnailObserver>(this);
 
   constexpr int kFootnoteVerticalMargin = 8;
@@ -569,31 +569,33 @@
 
   // If widget is already visible and anchored to the correct tab we should not
   // try to reset the anchor view or reshow.
-  if (widget_->IsVisible() && GetAnchorView() == tab &&
+  if (GetWidget()->IsVisible() && GetAnchorView() == tab &&
       !slide_animation_delegate_->is_animating()) {
-    widget_->SetBounds(slide_animation_delegate_->CalculateTargetBounds(tab));
+    GetWidget()->SetBounds(
+        slide_animation_delegate_->CalculateTargetBounds(tab));
     slide_animation_delegate_->SetCurrentBounds();
     OnHoverCardLanded();
     return;
   }
 
-  if (widget_->IsVisible())
+  if (GetWidget()->IsVisible())
     ++hover_cards_seen_count_;
 
-  if (widget_->IsVisible() && !disable_animations_for_testing_) {
+  if (GetWidget()->IsVisible() && !disable_animations_for_testing_) {
     slide_animation_delegate_->AnimateToAnchorView(tab);
   } else {
     if (!anchor_view_set)
       SetAnchorView(tab);
-    widget_->SetBounds(slide_animation_delegate_->CalculateTargetBounds(tab));
+    GetWidget()->SetBounds(
+        slide_animation_delegate_->CalculateTargetBounds(tab));
     slide_animation_delegate_->SetCurrentBounds();
     OnHoverCardLanded();
   }
 
-  if (!widget_->IsVisible()) {
+  if (!GetWidget()->IsVisible()) {
     if (disable_animations_for_testing_ || show_immediately) {
-      widget_->SetOpacity(1.0f);
-      widget_->Show();
+      GetWidget()->SetOpacity(1.0f);
+      GetWidget()->Show();
     } else {
       // Note that this will restart the timer if it is already running. If the
       // hover cards are not yet visible, moving the cursor within the tabstrip
@@ -605,18 +607,18 @@
 }
 
 bool TabHoverCardBubbleView::IsVisible() {
-  return widget_->IsVisible();
+  return GetWidget()->IsVisible();
 }
 
 void TabHoverCardBubbleView::FadeOutToHide() {
   delayed_show_timer_.Stop();
-  if (!widget_->IsVisible())
+  if (!GetWidget()->IsVisible())
     return;
   thumbnail_observer_->Observe(nullptr);
   slide_animation_delegate_->StopAnimation();
   last_visible_timestamp_ = base::TimeTicks::Now();
   if (disable_animations_for_testing_) {
-    widget_->Hide();
+    GetWidget()->Hide();
   } else {
     fade_animation_delegate_->FadeOut();
   }
@@ -859,7 +861,7 @@
     base::TimeDelta elapsed_time) {
   constexpr base::TimeDelta kMaxHoverCardReshowTimeDelta =
       base::TimeDelta::FromSeconds(5);
-  if ((!widget_->IsVisible() || IsFadingOut()) &&
+  if ((!GetWidget()->IsVisible() || IsFadingOut()) &&
       elapsed_time <= kMaxHoverCardReshowTimeDelta) {
     constexpr base::TimeDelta kMinHoverCardReshowTimeDelta =
         base::TimeDelta::FromMilliseconds(1);
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
index d771828..20c86bb5 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
@@ -93,8 +93,6 @@
 
   void RecordTimeSinceLastSeenMetric(base::TimeDelta elapsed_time);
 
-  base::OneShotTimer delayed_show_timer_;
-
   // Fade animations interfere with browser tests so we disable them in tests.
   static bool disable_animations_for_testing_;
   std::unique_ptr<WidgetFadeAnimationDelegate> fade_animation_delegate_;
@@ -111,7 +109,6 @@
   // the mouse reenters within a given amount of time.
   base::TimeTicks last_mouse_exit_timestamp_;
 
-  views::Widget* widget_ = nullptr;
   views::Label* title_label_ = nullptr;
   FadeLabel* title_fade_label_ = nullptr;
   base::Optional<TabAlertState> alert_state_;
@@ -124,6 +121,8 @@
   size_t hover_cards_seen_count_ = 0;
   bool waiting_for_decompress_ = false;
 
+  base::OneShotTimer delayed_show_timer_;
+
   DISALLOW_COPY_AND_ASSIGN(TabHoverCardBubbleView);
 };
 
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.cc b/chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.cc
new file mode 100644
index 0000000..ba44fc2
--- /dev/null
+++ b/chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.cc
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.h"
+
+#include "base/bind.h"
+#include "base/i18n/time_formatting.h"
+#include "base/values.h"
+
+namespace {
+// Keys in the JSON representation of a log message
+const char kLogMessageTextKey[] = "text";
+const char kLogMessageTimeKey[] = "time";
+const char kLogMessageFileKey[] = "file";
+const char kLogMessageLineKey[] = "line";
+const char kLogMessageSeverityKey[] = "severity";
+
+// Converts |log_message| to a raw dictionary value used as a JSON argument to
+// JavaScript functions.
+base::Value LogMessageToDictionary(const LogBuffer::LogMessage& log_message) {
+  base::Value dictionary(base::Value::Type::DICTIONARY);
+  dictionary.SetStringKey(kLogMessageTextKey, log_message.text);
+  dictionary.SetStringKey(
+      kLogMessageTimeKey,
+      base::TimeFormatTimeOfDayWithMilliseconds(log_message.time));
+  dictionary.SetStringKey(kLogMessageFileKey, log_message.file);
+  dictionary.SetIntKey(kLogMessageLineKey, log_message.line);
+  dictionary.SetIntKey(kLogMessageSeverityKey, log_message.severity);
+  return dictionary;
+}
+}  // namespace
+
+NearbyInternalsLogsHandler::NearbyInternalsLogsHandler() : observer_(this) {}
+
+NearbyInternalsLogsHandler::~NearbyInternalsLogsHandler() = default;
+
+void NearbyInternalsLogsHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "getLogMessages",
+      base::BindRepeating(&NearbyInternalsLogsHandler::HandleGetLogMessages,
+                          base::Unretained(this)));
+}
+
+void NearbyInternalsLogsHandler::OnJavascriptAllowed() {
+  observer_.Add(LogBuffer::GetInstance());
+}
+
+void NearbyInternalsLogsHandler::OnJavascriptDisallowed() {
+  observer_.RemoveAll();
+}
+
+void NearbyInternalsLogsHandler::HandleGetLogMessages(
+    const base::ListValue* args) {
+  AllowJavascript();
+  const base::Value& callback_id = args->GetList()[0];
+  base::Value list(base::Value::Type::LIST);
+  for (const auto& log : *LogBuffer::GetInstance()->logs()) {
+    list.Append(LogMessageToDictionary(log));
+  }
+  ResolveJavascriptCallback(callback_id, list);
+}
+
+void NearbyInternalsLogsHandler::OnLogBufferCleared() {
+  FireWebUIListener("log-buffer-cleared");
+}
+
+void NearbyInternalsLogsHandler::OnLogMessageAdded(
+    const LogBuffer::LogMessage& log_message) {
+  FireWebUIListener("log-message-added", LogMessageToDictionary(log_message));
+}
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.h b/chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.h
new file mode 100644
index 0000000..3ba482bd
--- /dev/null
+++ b/chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.h
@@ -0,0 +1,49 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_LOGS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_LOGS_HANDLER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
+#include "base/values.h"
+#include "chrome/browser/nearby_sharing/logging/log_buffer.h"
+#include "chrome/browser/nearby_sharing/logging/logging.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace base {
+class Value;
+}
+
+// WebUIMessageHandler for the NS_LOG Macro to pass logging messages to the
+// chrome://nearby-internals logging tab.
+class NearbyInternalsLogsHandler : public content::WebUIMessageHandler,
+                                   public LogBuffer::Observer {
+ public:
+  NearbyInternalsLogsHandler();
+  NearbyInternalsLogsHandler(const NearbyInternalsLogsHandler&) = delete;
+  NearbyInternalsLogsHandler& operator=(const NearbyInternalsLogsHandler&) =
+      delete;
+  ~NearbyInternalsLogsHandler() override;
+
+  // content::WebUIMessageHandler
+  void RegisterMessages() override;
+  void OnJavascriptAllowed() override;
+  void OnJavascriptDisallowed() override;
+
+ private:
+  // LogBuffer::Observer
+  void OnLogMessageAdded(const LogBuffer::LogMessage& log_message) override;
+  void OnLogBufferCleared() override;
+
+  // Message handler callback that returns the Log Buffer in dictionary form.
+  void HandleGetLogMessages(const base::ListValue* args);
+
+  // Message handler callback that clears the Log Buffer.
+  void ClearLogBuffer(const base::ListValue* args);
+
+  ScopedObserver<LogBuffer, LogBuffer::Observer> observer_{this};
+  base::WeakPtrFactory<NearbyInternalsLogsHandler> weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_NEARBY_INTERNALS_NEARBY_INTERNALS_LOGS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc b/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc
index bcbd409a..c1b116b 100644
--- a/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc
+++ b/chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.cc
@@ -4,10 +4,13 @@
 
 #include "chrome/browser/ui/webui/nearby_internals/nearby_internals_ui.h"
 
+#include <memory>
+
 #include "base/containers/span.h"
 #include "base/feature_list.h"
 #include "chrome/browser/browser_features.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/nearby_internals/nearby_internals_logs_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/nearby_internals_resources.h"
@@ -22,7 +25,7 @@
 }  // namespace
 
 NearbyInternalsUI::NearbyInternalsUI(content::WebUI* web_ui)
-    : ui::MojoWebUIController(web_ui) {
+    : ui::MojoWebUIController(web_ui, /*enable_chrome_send=*/true) {
   Profile* profile = Profile::FromWebUI(web_ui);
   // Nearby Sharing is not available to incognito or guest profiles.
   DCHECK(profile->IsRegularProfile());
@@ -37,6 +40,8 @@
       kNearbyInternalsGeneratedPath, IDR_NEARBY_INTERNALS_INDEX_HTML);
 
   content::WebUIDataSource::Add(profile, html_source);
+
+  web_ui->AddMessageHandler(std::make_unique<NearbyInternalsLogsHandler>());
 }
 
 NearbyInternalsUI::~NearbyInternalsUI() = default;
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index d13fafa6..fd93d204 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1594035519-bdce305e14959d596c45f90edc11488f647eb05b.profdata
+chrome-mac-master-1594058350-fa79bcca0a8f78a4047ebf7527ab39bc8dad55f0.profdata
diff --git a/chrome/services/cups_proxy/public/cpp/cups_util.cc b/chrome/services/cups_proxy/public/cpp/cups_util.cc
index 258259b..f851a43e 100644
--- a/chrome/services/cups_proxy/public/cpp/cups_util.cc
+++ b/chrome/services/cups_proxy/public/cpp/cups_util.cc
@@ -130,7 +130,12 @@
   char resource[HTTP_MAX_URI], unwanted_buffer[HTTP_MAX_URI];
   int unwanted_port;
 
-  std::string printer_uri = ippGetString(printer_uri_attr, 0, NULL);
+  std::string printer_uri;
+  const char* printer_uri_ptr = ippGetString(printer_uri_attr, 0, nullptr);
+  if (printer_uri_ptr) {
+    printer_uri = printer_uri_ptr;
+  }
+
   httpSeparateURI(HTTP_URI_CODING_RESOURCE, printer_uri.data(), unwanted_buffer,
                   HTTP_MAX_URI, unwanted_buffer, HTTP_MAX_URI, unwanted_buffer,
                   HTTP_MAX_URI, &unwanted_port, resource, HTTP_MAX_URI);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 9aa8364e..fb7f5c2 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3259,10 +3259,8 @@
     "../browser/optimization_guide/optimization_guide_permissions_util_unittest.cc",
     "../browser/optimization_guide/optimization_guide_session_statistic_unittest.cc",
     "../browser/optimization_guide/optimization_guide_top_host_provider_unittest.cc",
-    "../browser/optimization_guide/prediction/decision_tree_prediction_model_unittest.cc",
     "../browser/optimization_guide/prediction/prediction_manager_unittest.cc",
     "../browser/optimization_guide/prediction/prediction_model_fetcher_unittest.cc",
-    "../browser/optimization_guide/prediction/prediction_model_unittest.cc",
     "../browser/page_load_metrics/metrics_web_contents_observer_unittest.cc",
     "../browser/page_load_metrics/observers/aborts_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc",
@@ -3639,6 +3637,7 @@
       "../browser/nearby_sharing/instantmessaging/receive_messages_express_unittest.cc",
       "../browser/nearby_sharing/instantmessaging/send_message_express_unittest.cc",
       "../browser/nearby_sharing/instantmessaging/stream_parser_unittest.cc",
+      "../browser/nearby_sharing/nearby_notification_manager_unittest.cc",
       "../browser/nearby_sharing/nearby_process_manager_unittest.cc",
       "../browser/nearby_sharing/nearby_sharing_service_impl_unittest.cc",
       "../browser/nearby_sharing/webrtc_signaling_messenger_unittest.cc",
@@ -4353,6 +4352,7 @@
       "//chrome/services/sharing/public/cpp:unit_tests",
       "//chrome/services/speech:unit_tests",
       "//components/chrome_cleaner/test:test_name_helper",
+      "//components/enterprise",
       "//components/enterprise:test_support",
       "//components/feature_engagement/test:test_support",
       "//components/safety_check:test_support",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
index 850b587e..c422fb7 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
@@ -123,7 +123,7 @@
                 try {
                     base.evaluate();
                 } finally {
-                    ruleTearDown();
+                    Thread.setDefaultUncaughtExceptionHandler(mDefaultUncaughtExceptionHandler);
                 }
             }
         };
@@ -138,27 +138,6 @@
         return ACTIVITY_START_TIMEOUT_MS;
     }
 
-    private void ruleTearDown() {
-        try {
-            ApplicationTestUtils.tearDown(InstrumentationRegistry.getTargetContext());
-            waitForActivityFinished();
-            Thread.setDefaultUncaughtExceptionHandler(mDefaultUncaughtExceptionHandler);
-        } catch (Exception e) {
-            throw new RuntimeException("Failed to tearDown", e);
-        }
-    }
-
-    private void waitForActivityFinished() {
-        if (mSetActivity == null) return;
-        try {
-            ApplicationTestUtils.waitForActivityState(mSetActivity, ActivityState.DESTROYED);
-        } catch (Exception e) {
-            Log.e(TAG, "Cannot finish activity, exception:" + e);
-        } finally {
-            mSetActivity = null;
-        }
-    }
-
     // TODO(yolandyan): remove this once startActivityCompletely is refactored out of
     // ChromeActivityTestRule
     @Override
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
index 169213a..70aa6573 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
@@ -5,12 +5,9 @@
 package org.chromium.chrome.test.util;
 
 import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.app.Activity;
-import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.util.Pair;
@@ -50,10 +47,6 @@
     @SuppressWarnings("deprecation")
     @SuppressLint("WakelockTimeout")
     public static void setUp(Context context) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            finishAllChromeTasks(context);
-        }
-
         // Make sure the screen is on during test runs.
         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         sWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK
@@ -72,12 +65,6 @@
             // Make sure that sWakeLock is only released from being held state
             sWakeLock.release();
         }
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            try {
-                finishAllChromeTasks(context);
-            } catch (AssertionError exception) {
-            }
-        }
     }
 
     // TODO(bauerb): make this function throw more specific exception and update
@@ -188,39 +175,6 @@
         waitForActivityState(activity, ActivityState.DESTROYED);
     }
 
-    /** Finishes all tasks Chrome has listed in Android's Overview. */
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    public static void finishAllChromeTasks(final Context context) {
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            try {
-                // Close all of the tasks one by one.
-                ActivityManager activityManager =
-                        (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-                for (ActivityManager.AppTask task : activityManager.getAppTasks()) {
-                    task.finishAndRemoveTask();
-                }
-            } catch (Exception e) {
-                // Ignore any exceptions the Android framework throws so that otherwise passing
-                // tests don't fail during tear down. See crbug.com/653731.
-            }
-        });
-
-        CriteriaHelper.pollUiThread(Criteria.equals(0, new Callable<Integer>() {
-            @Override
-            public Integer call() {
-                return getNumChromeTasks(context);
-            }
-        }));
-    }
-
-    /** Counts how many tasks Chrome has listed in Android's Overview. */
-    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
-    public static int getNumChromeTasks(Context context) {
-        ActivityManager activityManager =
-                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-        return activityManager.getAppTasks().size();
-    }
-
     /**
      * Waits till the WebContents receives the expected page scale factor
      * from the compositor and asserts that this happens.
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeRenderTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeRenderTestRule.java
index ba32fb6c..5a0abb38 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeRenderTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeRenderTestRule.java
@@ -20,7 +20,18 @@
  * public class MyTest {
  *     // Provide RenderTestRule with the path from src/ to the golden directory.
  *     @Rule
- *     public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule();
+ *     public ChromeRenderTestRule mRenderTestRule = new ChromeRenderTestRule.Builder()
+ *             // Required. If using ANDROID_RENDER_TESTS_PUBLIC, the Builder can be created with
+ *             // the shorthand ChromeRenderTestRule.Builder.withPublicCorpus().
+ *             .setCorpus(ChromeRenderTestRule.Corpus.ANDROID_RENDER_TESTS_PUBLIC)
+ *             // Optional, only necessary once a CL lands that should invalidate previous golden
+ *             // images, e.g. a UI rework.
+ *             .setRevision(2)
+ *             // Optional, only necessary if you want a message to be associated with these
+ *             // golden images and shown in the Gold web UI, e.g. the reason why the revision was
+ *             // incremented.
+ *             .setDescription("Material design rework")
+ *             .build();
  *
  *     @Test
  *     // The test must have the feature "RenderTest" for the bots to display renders.
@@ -39,10 +50,6 @@
  * </pre>
  */
 public class ChromeRenderTestRule extends RenderTestRule {
-    public ChromeRenderTestRule() {
-        super();
-    }
-
     protected ChromeRenderTestRule(int revision, @RenderTestRule.Corpus String corpus,
             String description, boolean failOnUnsupportedConfigs) {
         super(revision, corpus, description, failOnUnsupportedConfigs);
@@ -57,13 +64,20 @@
     }
 
     /**
-     * Builder to create a ChromeRenderTestRule for use with Skia Gold.
+     * Builder to create a ChromeRenderTestRule.
      */
-    public static class SkiaGoldBuilder extends RenderTestRule.SkiaGoldBuilder {
+    public static class Builder extends RenderTestRule.BaseBuilder<Builder> {
         @Override
         public ChromeRenderTestRule build() {
             return new ChromeRenderTestRule(
                     mRevision, mCorpus, mDescription, mFailOnUnsupportedConfigs);
         }
+
+        /**
+         * Creates a Builder with the default public corpus.
+         */
+        public static Builder withPublicCorpus() {
+            return new Builder().setCorpus(Corpus.ANDROID_RENDER_TESTS_PUBLIC);
+        }
     }
 }
diff --git a/chrome/test/data/extensions/api_test/automation/tests/desktop/common.js b/chrome/test/data/extensions/api_test/automation/tests/desktop/common.js
index d92790a..30123c17 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/desktop/common.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/desktop/common.js
@@ -31,12 +31,8 @@
     active: true,
     url: url
   };
-  chrome.tabs.create(createParams, function(tab) {
-    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
-      if (tabId == tab.id && changeInfo.status == 'complete') {
-        chrome.automation.getTree(tab.id, callback);
-      }
-    });
+  createTabAndWaitUntilLoaded(url, function(tab) {
+    chrome.automation.getTree(tab.id, callback);
   });
 }
 
@@ -58,7 +54,7 @@
 function setUpAndRunTestsInPage(allTests, opt_path) {
   var path = opt_path || 'index.html';
   getUrlFromConfig(path, function(url) {
-    createTab(url, function(unused_tab) {
+    createTabAndWaitUntilLoaded(url, function(unused_tab) {
       chrome.automation.getTree(function (returnedRootNode) {
         rootNode = returnedRootNode;
         if (rootNode.docLoaded) {
@@ -82,8 +78,12 @@
   });
 }
 
-function createTab(url, callback) {
+function createTabAndWaitUntilLoaded(url, callback) {
   chrome.tabs.create({"url": url}, function(tab) {
-    callback(tab);
+    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
+      if (tabId == tab.id && changeInfo.status == 'complete') {
+        callback(tab);
+      }
+    });
   });
 }
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/close_tab.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/close_tab.js
index 416f5b8e..e7fbb18a 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/close_tab.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/close_tab.js
@@ -5,7 +5,7 @@
 var allTests = [
   function testCloseTab() {
     getUrlFromConfig('index.html', function(url) {
-      chrome.tabs.create({'url': url}, function(tab) {
+      createTabAndWaitUntilLoaded(url, function(tab) {
         chrome.automation.getTree(function(rootNode) {
           function doTestCloseTab() {
             var button = rootNode.find({role: 'button'});
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/common.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/common.js
index ac5eb32..512fdd4 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/common.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/common.js
@@ -13,9 +13,13 @@
 var rootNode = null;
 var url = '';
 
-function createTab(url, callback) {
+function createTabAndWaitUntilLoaded(url, callback) {
   chrome.tabs.create({"url": url}, function(tab) {
-    callback(tab);
+    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
+      if (tabId == tab.id && changeInfo.status == 'complete') {
+        callback(tab);
+      }
+    });
   });
 }
 
@@ -30,7 +34,7 @@
 function setUpAndRunTests(allTests, opt_path) {
   var path = opt_path || 'index.html';
   getUrlFromConfig(path, function(url) {
-    createTab(url, function(unused_tab) {
+    createTabAndWaitUntilLoaded(url, function(unused_tab) {
       chrome.automation.getTree(function (returnedRootNode) {
         rootNode = returnedRootNode;
         if (rootNode.docLoaded) {
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/tab_id.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/tab_id.js
index d416e39..68354de 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/tab_id.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/tab_id.js
@@ -9,7 +9,7 @@
   chrome.tabs.query({ active: true }, function(tabs) {
     chrome.test.assertEq(1, tabs.length);
     originalActiveTab = tabs[0];
-    createTab(url, function(tab) {
+    createTabAndWaitUntilLoaded(url, function(tab) {
       chrome.tabs.update(originalActiveTab.id, { active: true }, function() {
         callback(tab);
       });
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/common.js b/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/common.js
index 2c5b90dd..4b0b0333 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/common.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/common.js
@@ -8,6 +8,16 @@
 
 var rootNode = null;
 
+function createTabAndWaitUntilLoaded(url, callback) {
+  chrome.tabs.create({"url": url}, function(tab) {
+    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
+      if (tabId == tab.id && changeInfo.status == 'complete') {
+        callback(tab);
+      }
+    });
+  });
+}
+
 function setUpAndRunTests(allTests) {
   chrome.test.getConfig(function(config) {
     assertTrue('testServer' in config, 'Expected testServer in config');
@@ -24,9 +34,8 @@
         chrome.test.runTests(allTests);
       });
     }
-    chrome.tabs.create({ 'url': url }, function() {
+    createTabAndWaitUntilLoaded(url, function(unused_tab) {
       chrome.automation.getTree(gotTree);
     });
   });
 }
-
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/permissions.html b/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/permissions.html
index 58d1431..0a089bc 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/permissions.html
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/permissions.html
@@ -4,4 +4,5 @@
  * LICENSE file.
 -->
 
+<script src="common.js"></script>
 <script src="permissions.js"></script>
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/permissions.js b/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/permissions.js
index 28f1e09..4e98730e 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/permissions.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_boolean/permissions.js
@@ -35,13 +35,13 @@
   urlA = 'http://a.com:PORT/index.html'
       .replace(/PORT/, config.testServer.port);
 
-  chrome.tabs.create({ 'url': urlA }, function() {
+  createTabAndWaitUntilLoaded(urlA, function(unused_tab) {
     chrome.test.runTests(allTestsADomain);
 
     urlB = 'http://b.com:PORT/index.html'
         .replace(/PORT/, config.testServer.port);
 
-    chrome.tabs.create({ 'url': urlB }, function() {
+    createTabAndWaitUntilLoaded(urlB, function(unused_tab) {
       chrome.test.runTests(allTestsBDomain);
     });
   });
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_hosts/permissions.js b/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_hosts/permissions.js
index ac67bcc9..e7b8f78 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_hosts/permissions.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs_automation_hosts/permissions.js
@@ -10,6 +10,16 @@
 var urlA = '';
 var urlB = '';
 
+function createTabAndWaitUntilLoaded(url, callback) {
+  chrome.tabs.create({"url": url}, function(tab) {
+    chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
+      if (tabId == tab.id && changeInfo.status == 'complete') {
+        callback(tab);
+      }
+    });
+  });
+}
+
 var allTestsADomain = [
   function testSuccess() {
     chrome.automation.getTree(function(tree) {
@@ -34,13 +44,13 @@
   urlA = 'http://a.com:PORT/index.html'
       .replace(/PORT/, config.testServer.port);
 
-  chrome.tabs.create({ 'url': urlA }, function() {
+  createTabAndWaitUntilLoaded(urlA, function(unused_tab) {
     chrome.test.runTests(allTestsADomain);
 
     urlB = 'http://b.com:PORT/index.html'
         .replace(/PORT/, config.testServer.port);
 
-    chrome.tabs.create({ 'url': urlB }, function() {
+    createTabAndWaitUntilLoaded(urlB, function(unused_tab) {
       chrome.test.runTests(allTestsBDomain);
     });
   });
diff --git a/chrome/test/enterprise/e2e/policy/allow_deleting_browser_history/allow_deleting_browser_history_webdriver_test.py b/chrome/test/enterprise/e2e/policy/allow_deleting_browser_history/allow_deleting_browser_history_webdriver_test.py
index d4dbb1b..45091a1 100644
--- a/chrome/test/enterprise/e2e/policy/allow_deleting_browser_history/allow_deleting_browser_history_webdriver_test.py
+++ b/chrome/test/enterprise/e2e/policy/allow_deleting_browser_history/allow_deleting_browser_history_webdriver_test.py
@@ -58,9 +58,9 @@
 
     disabled = checkbox.get_attribute('disabled')
     if disabled == 'true':
-      print 'DISABLED'
+      print('DISABLED')
     else:
-      print 'ENABLED'
+      print('ENABLED')
 
   finally:
     driver.quit()
diff --git a/chrome/test/enterprise/e2e/policy/apps_shortcut/is_apps_shortcut_visible.py b/chrome/test/enterprise/e2e/policy/apps_shortcut/is_apps_shortcut_visible.py
index 19af716..8c8a13d 100644
--- a/chrome/test/enterprise/e2e/policy/apps_shortcut/is_apps_shortcut_visible.py
+++ b/chrome/test/enterprise/e2e/policy/apps_shortcut/is_apps_shortcut_visible.py
@@ -13,14 +13,14 @@
     application = Application(backend="uia")
     application.connect(title_re='.*Chrome|.*Chromium')
 
-    print "Looking for apps shortcut..."
+    print("Looking for apps shortcut...")
     for desc in application.top_window().descendants():
-      print desc.window_text()
+      print(desc.window_text())
       if "Apps" == desc.window_text():
-        print "TRUE"
+        print("TRUE")
         return
 
-    print "FALSE"
+    print("FALSE")
   finally:
     driver.quit()
 
diff --git a/chrome/test/enterprise/e2e/policy/bookmarkbar_enabled/bookmarkbar_webdriver.py b/chrome/test/enterprise/e2e/policy/bookmarkbar_enabled/bookmarkbar_webdriver.py
index 76d089f..ee8a83d7d 100644
--- a/chrome/test/enterprise/e2e/policy/bookmarkbar_enabled/bookmarkbar_webdriver.py
+++ b/chrome/test/enterprise/e2e/policy/bookmarkbar_enabled/bookmarkbar_webdriver.py
@@ -18,9 +18,9 @@
   app.connect(title_re='.*Chrome|.*Chromium')
   app.top_window().child_window(title="Bookmarks", control_type="ToolBar") \
       .print_control_identifiers()
-  print "Bookmarkbar is found"
+  print("Bookmarkbar is found")
 except ElementNotFoundError as error:
-  print error
-  print "Bookmarkbar is missing"
+  print(error)
+  print("Bookmarkbar is missing")
 finally:
   driver.quit()
diff --git a/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py b/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
index 54737b7..d3e05e1 100644
--- a/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
+++ b/chrome/test/enterprise/e2e/policy/cloud_management_enrollment_token/cloud_enrollment_webdriver.py
@@ -22,12 +22,12 @@
     policy_url = "chrome://policy"
     driver.get(policy_url)
     driver.find_element_by_id('reload-policies').click
-    print driver.find_element_by_class_name('legend').text
-    print driver.find_element_by_class_name('machine-enrollment-name').text
-    print driver.find_element_by_class_name('machine-enrollment-token').text
-    print driver.find_element_by_class_name('status').text
+    print(driver.find_element_by_class_name('legend').text)
+    print(driver.find_element_by_class_name('machine-enrollment-name').text)
+    print(driver.find_element_by_class_name('machine-enrollment-token').text)
+    print(driver.find_element_by_class_name('status').text)
   except Exception as error:
-    print error
+    print(error)
   finally:
     driver.quit()
 
diff --git a/chrome/test/enterprise/e2e/policy/default_search_provider/default_search_provider_webdriver.py b/chrome/test/enterprise/e2e/policy/default_search_provider/default_search_provider_webdriver.py
index 6a7684d..ff0ce9b 100644
--- a/chrome/test/enterprise/e2e/policy/default_search_provider/default_search_provider_webdriver.py
+++ b/chrome/test/enterprise/e2e/policy/default_search_provider/default_search_provider_webdriver.py
@@ -19,8 +19,8 @@
   omnibox = app.top_window() \
             .child_window(title="Address and search bar", control_type="Edit")
   omnibox.set_edit_text('anything').type_keys('{ENTER}')
-  print driver.current_url
+  print(driver.current_url)
 except Exception as error:
-  print error
+  print(error)
 finally:
   driver.quit()
diff --git a/chrome/test/enterprise/e2e/policy/extension_forcelist/is_extension_installed.py b/chrome/test/enterprise/e2e/policy/extension_forcelist/is_extension_installed.py
index 2bf876fb..f8d7611 100644
--- a/chrome/test/enterprise/e2e/policy/extension_forcelist/is_extension_installed.py
+++ b/chrome/test/enterprise/e2e/policy/extension_forcelist/is_extension_installed.py
@@ -34,7 +34,7 @@
   driver.get("chrome://extensions")
 
   # It's nested within a couple of shadow doms on the page - extract it.
-  print "Looking for extension on extensions page: %s" % FLAGS.extension_id
+  print("Looking for extension on extensions page: %s" % FLAGS.extension_id)
   extension_page = False
   try:
     selectors = ["extensions-manager", "extensions-item-list"]
@@ -46,9 +46,9 @@
     print(traceback.format_exc())
 
   if extension_page:
-    print "TRUE"
+    print("TRUE")
   else:
-    print "FALSE"
+    print("FALSE")
 
 
 def main(argv):
diff --git a/chrome/test/enterprise/e2e/policy/force_google_safe_search/force_google_safe_search_webdriver_test.py b/chrome/test/enterprise/e2e/policy/force_google_safe_search/force_google_safe_search_webdriver_test.py
index 078225e..5f8e9552 100644
--- a/chrome/test/enterprise/e2e/policy/force_google_safe_search/force_google_safe_search_webdriver_test.py
+++ b/chrome/test/enterprise/e2e/policy/force_google_safe_search/force_google_safe_search_webdriver_test.py
@@ -22,5 +22,5 @@
 # wait for the search result page to be loaded
 wait.until(EC.visibility_of_element_located((By.ID, 'search')))
 
-print driver.current_url
+print(driver.current_url)
 driver.quit()
diff --git a/chrome/test/enterprise/e2e/policy/fullscreen_allowed/is_fullscreen_allowed.py b/chrome/test/enterprise/e2e/policy/fullscreen_allowed/is_fullscreen_allowed.py
index bb850a2f..084a34f 100644
--- a/chrome/test/enterprise/e2e/policy/fullscreen_allowed/is_fullscreen_allowed.py
+++ b/chrome/test/enterprise/e2e/policy/fullscreen_allowed/is_fullscreen_allowed.py
@@ -15,13 +15,13 @@
     w = application.top_window()
 
     for desc in w.descendants():
-      print "item: %s" % desc
+      print("item: %s" % desc)
 
-    print "Closing info bar."
+    print("Closing info bar.")
     container = w.child_window(best_match="Infobar Container")
     container.child_window(best_match="Close").click_input()
 
-    print "press F11 to enter full screen mode."
+    print("press F11 to enter full screen mode.")
     w.type_keys('{F11}')
 
     window_rect = w.rectangle()
@@ -31,14 +31,14 @@
     content_height = driver.execute_script("return window.innerHeight")
 
     # The content area should be the same size as the full window.
-    print "window_rect: %s" % window_rect
-    print "window_width: %s" % window_width
-    print "window_height: %s" % window_height
-    print "content_width: %s" % content_width
-    print "content_height: %s" % content_height
+    print("window_rect: %s" % window_rect)
+    print("window_width: %s" % window_width)
+    print("window_height: %s" % window_height)
+    print("content_width: %s" % content_width)
+    print("content_height: %s" % content_height)
 
     fs = window_width == content_width and window_height == content_height
-    print "FullscreenAllowed: %s" % fs
+    print("FullscreenAllowed: %s" % fs)
   finally:
     driver.quit()
 
diff --git a/chrome/test/enterprise/e2e/policy/homepage/get_home_button.py b/chrome/test/enterprise/e2e/policy/homepage/get_home_button.py
index c34b2774..be31880d9 100644
--- a/chrome/test/enterprise/e2e/policy/homepage/get_home_button.py
+++ b/chrome/test/enterprise/e2e/policy/homepage/get_home_button.py
@@ -16,7 +16,7 @@
   home_button = app.top_window().child_window(
       title="Home", control_type="Button")
   if home_button.exists(timeout=1):
-    print 'home button exists'
+    print('home button exists')
 
 finally:
   driver.quit()
diff --git a/chrome/test/enterprise/e2e/policy/homepage/get_homepage_url.py b/chrome/test/enterprise/e2e/policy/homepage/get_homepage_url.py
index af07d707..5416f38 100644
--- a/chrome/test/enterprise/e2e/policy/homepage/get_homepage_url.py
+++ b/chrome/test/enterprise/e2e/policy/homepage/get_homepage_url.py
@@ -15,6 +15,6 @@
   # Use shortcut Alt+HOME to go to the home page
   app.top_window().type_keys("%{HOME}")
 
-  print 'homepage:%s' % driver.current_url
+  print('homepage:%s' % driver.current_url)
 finally:
   driver.quit()
diff --git a/chrome/test/enterprise/e2e/policy/install_extension.py b/chrome/test/enterprise/e2e/policy/install_extension.py
index 2998904..e2de8d0c3 100644
--- a/chrome/test/enterprise/e2e/policy/install_extension.py
+++ b/chrome/test/enterprise/e2e/policy/install_extension.py
@@ -36,7 +36,7 @@
        .child_window(title_re='.*Your admin has blocked', control_type="TitleBar") \
        .print_control_identifiers()
   except ElementNotFoundError as error:
-    print "Not blocked"
+    print("Not blocked")
   finally:
     driver.quit()
 
diff --git a/chrome/test/enterprise/e2e/policy/open_page.py b/chrome/test/enterprise/e2e/policy/open_page.py
index d54237a..b06629f 100644
--- a/chrome/test/enterprise/e2e/policy/open_page.py
+++ b/chrome/test/enterprise/e2e/policy/open_page.py
@@ -32,9 +32,9 @@
     time.sleep(FLAGS.wait)
 
   if FLAGS.text_only:
-    print driver.find_element_by_css_selector('html').text.encode('utf-8')
+    print(driver.find_element_by_css_selector('html').text.encode('utf-8'))
   else:
-    print driver.page_source.encode('utf-8')
+    print(driver.page_source.encode('utf-8'))
 
   driver.quit()
 
diff --git a/chrome/test/enterprise/e2e/policy/password_manager_enabled/password_manager_enabled_webdriver_test.py b/chrome/test/enterprise/e2e/policy/password_manager_enabled/password_manager_enabled_webdriver_test.py
index 320d5a0..e595467 100644
--- a/chrome/test/enterprise/e2e/policy/password_manager_enabled/password_manager_enabled_webdriver_test.py
+++ b/chrome/test/enterprise/e2e/policy/password_manager_enabled/password_manager_enabled_webdriver_test.py
@@ -29,9 +29,9 @@
   ])
 
   if el.find_element_by_css_selector("cr-toggle").get_attribute("checked"):
-    print "TRUE"
+    print("TRUE")
   else:
-    print "FALSE"
+    print("FALSE")
 
   driver.quit()
 
diff --git a/chrome/test/enterprise/e2e/policy/popups_allowed/popup_allowed_webdriver_test.py b/chrome/test/enterprise/e2e/policy/popups_allowed/popup_allowed_webdriver_test.py
index 9a76f6c..9b2d868 100644
--- a/chrome/test/enterprise/e2e/policy/popups_allowed/popup_allowed_webdriver_test.py
+++ b/chrome/test/enterprise/e2e/policy/popups_allowed/popup_allowed_webdriver_test.py
@@ -16,7 +16,7 @@
   driver.implicitly_wait(5)
   driver.get(testSite)
   handles = driver.window_handles
-  print len(handles)
+  print(len(handles))
   driver.quit()
 
 
diff --git a/chrome/test/enterprise/e2e/policy/restore_on_startup/restore_on_startup_webdriver_test.py b/chrome/test/enterprise/e2e/policy/restore_on_startup/restore_on_startup_webdriver_test.py
index 2127046..c6a9dda 100644
--- a/chrome/test/enterprise/e2e/policy/restore_on_startup/restore_on_startup_webdriver_test.py
+++ b/chrome/test/enterprise/e2e/policy/restore_on_startup/restore_on_startup_webdriver_test.py
@@ -53,7 +53,7 @@
   # give chrome some time to load everything
   time.sleep(2)
 
-  print json.dumps(_get_urls(driver))
+  print(json.dumps(_get_urls(driver)))
   test_util.shutdown_chrome()
 
 
@@ -68,7 +68,7 @@
   # currently there's no statisfactory solution.
   time.sleep(10)
 
-  print json.dumps(_get_urls(driver))
+  print(json.dumps(_get_urls(driver)))
   test_util.shutdown_chrome()
 
 
diff --git a/chrome/test/enterprise/e2e/policy/safe_browsing/safe_browsing_ui_test.py b/chrome/test/enterprise/e2e/policy/safe_browsing/safe_browsing_ui_test.py
index 296faf0..71715c1 100644
--- a/chrome/test/enterprise/e2e/policy/safe_browsing/safe_browsing_ui_test.py
+++ b/chrome/test/enterprise/e2e/policy/safe_browsing/safe_browsing_ui_test.py
@@ -42,30 +42,30 @@
   # experiments have shown 3-4 minutes in most cases, so 5 should be plenty.
   time.sleep(60 * 5)
 
-  print "Visiting unsafe page: %s" % UnsafePageLink
+  print("Visiting unsafe page: %s" % UnsafePageLink)
   visit(window, UnsafePageLink)
 
   unsafe_page = False
   for desc in app.top_window().descendants():
     if desc.window_text():
-      print "unsafe_page.item: %s" % desc.window_text()
+      print("unsafe_page.item: %s" % desc.window_text())
       if UnsafePageLinkTabText in desc.window_text():
         unsafe_page = True
         break
 
-  print "Downloading unsafe file: %s" % UnsafeDownloadLink
+  print("Downloading unsafe file: %s" % UnsafeDownloadLink)
   visit(window, UnsafeDownloadLink)
 
   unsafe_download = False
   for desc in app.top_window().descendants():
     if desc.window_text():
-      print "unsafe_download.item: %s" % desc.window_text()
+      print("unsafe_download.item: %s" % desc.window_text())
       if re.search(UnsafeDownloadTextRe, desc.window_text()):
         unsafe_download = True
         break
 
-  print "RESULTS.unsafe_page: %s" % unsafe_page
-  print "RESULTS.unsafe_download: %s" % unsafe_download
+  print("RESULTS.unsafe_page: %s" % unsafe_page)
+  print("RESULTS.unsafe_download: %s" % unsafe_download)
 
   driver.quit()
 
diff --git a/chrome/test/enterprise/e2e/policy/translate_enabled/translate_enabled_webdriver_test.py b/chrome/test/enterprise/e2e/policy/translate_enabled/translate_enabled_webdriver_test.py
index 41d6452f..67bc5b9 100644
--- a/chrome/test/enterprise/e2e/policy/translate_enabled/translate_enabled_webdriver_test.py
+++ b/chrome/test/enterprise/e2e/policy/translate_enabled/translate_enabled_webdriver_test.py
@@ -47,9 +47,9 @@
     os.system('taskkill /f /im chrome.exe')
 
   if translatePopupVisible:
-    print "TRUE"
+    print("TRUE")
   else:
-    print "FALSE"
+    print("FALSE")
 
 
 if __name__ == '__main__':
diff --git a/chrome/test/enterprise/e2e/policy/user_data_dir/user_data_dir_webdriver.py b/chrome/test/enterprise/e2e/policy/user_data_dir/user_data_dir_webdriver.py
index 6a89f7cfd..f9f6c96c 100644
--- a/chrome/test/enterprise/e2e/policy/user_data_dir/user_data_dir_webdriver.py
+++ b/chrome/test/enterprise/e2e/policy/user_data_dir/user_data_dir_webdriver.py
@@ -19,8 +19,8 @@
   version_url = "chrome://version"
 
   # Verify the user data dir is not existing before launch the Chrome
-  print "User data before running chrome is " + str(
-      os.path.isdir(FLAGS.user_data_dir))
+  print("User data before running chrome is " + str(
+      os.path.isdir(FLAGS.user_data_dir)))
 
   # Launch real Chrome
   os.system('start chrome --remote-debugging-port=9222')
@@ -34,16 +34,16 @@
   try:
     # Verify User Data Dir in chrome://policy page
     driver.get(policy_url)
-    print driver.find_element_by_css_selector('html').text.encode('utf-8')
+    print(driver.find_element_by_css_selector('html').text.encode('utf-8'))
 
     # Verfiy User Data Dir used in chrome://version
     driver.get(version_url)
-    print "Profile path is " + driver.find_element_by_id("profile_path").text
+    print("Profile path is " + driver.find_element_by_id("profile_path").text)
 
     # Verify if UserDataDir folder is created
-    print "User data dir creation is " + str(os.path.isdir(FLAGS.user_data_dir))
+    print("User data dir creation is " + str(os.path.isdir(FLAGS.user_data_dir)))
   except Exception as error:
-    print error
+    print(error)
   finally:
     driver.quit()
     os.system('taskkill /f /im chrome.exe')
diff --git a/chrome/test/enterprise/e2e/policy/webprotect_file_download/webprotect_file_download_webdriver.py b/chrome/test/enterprise/e2e/policy/webprotect_file_download/webprotect_file_download_webdriver.py
index e448547..0ca5147 100644
--- a/chrome/test/enterprise/e2e/policy/webprotect_file_download/webprotect_file_download_webdriver.py
+++ b/chrome/test/enterprise/e2e/policy/webprotect_file_download/webprotect_file_download_webdriver.py
@@ -30,9 +30,9 @@
     app.connect(title_re='.*Chrome|.*Chromium')
     app.top_window() \
         .child_window(title_re=regex, control_type=type)
-    print message
+    print(message)
   except ElementNotFoundError as error:
-    print error
+    print(error)
 
 
 def main(argv):
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 4c865040..b251755 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -225,6 +225,7 @@
       "printing/ppd_metadata_manager_unittest.cc",
       "printing/ppd_metadata_matchers.h",
       "printing/ppd_metadata_parser_unittest.cc",
+      "printing/ppd_provider_v3_unittest.cc",
       "printing/printer_config_cache_unittest.cc",
     ]
   } else {
diff --git a/chromeos/lacros/OWNERS b/chromeos/lacros/OWNERS
new file mode 100644
index 0000000..c60afcd
--- /dev/null
+++ b/chromeos/lacros/OWNERS
@@ -0,0 +1,2 @@
+file://chromeos/LACROS_OWNERS
+
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc
index b503be749..bb8e8a1 100644
--- a/chromeos/network/network_state.cc
+++ b/chromeos/network/network_state.cc
@@ -90,7 +90,15 @@
   if (ManagedStatePropertyChanged(key, value))
     return true;
   if (key == shill::kSignalStrengthProperty) {
-    return GetIntegerValue(key, value, &signal_strength_);
+    int signal_strength = signal_strength_;
+    if (!GetIntegerValue(key, value, &signal_strength))
+      return false;
+    if (signal_strength_ > 0 && abs(signal_strength - signal_strength_) <
+                                    kSignalStrengthChangeThreshold) {
+      return false;
+    }
+    signal_strength_ = signal_strength;
+    return true;
   } else if (key == shill::kStateProperty) {
     std::string connection_state;
     if (!GetStringValue(key, value, &connection_state))
diff --git a/chromeos/network/network_state.h b/chromeos/network/network_state.h
index 2fc59cfb..74f4664 100644
--- a/chromeos/network/network_state.h
+++ b/chromeos/network/network_state.h
@@ -243,6 +243,9 @@
   static std::unique_ptr<NetworkState> CreateDefaultCellular(
       const std::string& device_path);
 
+  // Ignore changes to signal strength less than this value.
+  constexpr static const int kSignalStrengthChangeThreshold = 5;
+
  private:
   friend class MobileActivatorTest;
   friend class NetworkStateHandler;
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index fbd3246..3b12ea8 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -35,9 +35,6 @@
 
 namespace {
 
-// Ignore changes to signal strength less than this value for active networks.
-const int kSignalStrengthChangeThreshold = 5;
-
 // Constants used for logging.
 constexpr char kReasonStateChange[] = "State Change";
 constexpr char kReasonChange[] = "New Network";
@@ -126,7 +123,7 @@
            activation_state_ == network->activation_state() &&
            connect_requested_ == network->connect_requested() &&
            (abs(signal_strength_ - network->signal_strength()) <
-            kSignalStrengthChangeThreshold) &&
+            NetworkState::kSignalStrengthChangeThreshold) &&
            network_technology_ == network->network_technology();
   }
 
diff --git a/chromeos/printing/ppd_provider_v3.cc b/chromeos/printing/ppd_provider_v3.cc
index 8a0487c..5ca614d4 100644
--- a/chromeos/printing/ppd_provider_v3.cc
+++ b/chromeos/printing/ppd_provider_v3.cc
@@ -130,12 +130,56 @@
   base::WeakPtrFactory<PpdProviderImpl> weak_factory_{this};
 };
 
+// Copied directly from v2 PpdProvider
+// TODO(crbug.com/888189): figure out where this fits in the big picture
+bool PpdReferenceIsWellFormed(const Printer::PpdReference& reference) {
+  int filled_fields = 0;
+  if (!reference.user_supplied_ppd_url.empty()) {
+    ++filled_fields;
+    GURL tmp_url(reference.user_supplied_ppd_url);
+    if (!tmp_url.is_valid() || !tmp_url.SchemeIs("file")) {
+      LOG(ERROR) << "Invalid url for a user-supplied ppd: "
+                 << reference.user_supplied_ppd_url
+                 << " (must be a file:// URL)";
+      return false;
+    }
+  }
+  if (!reference.effective_make_and_model.empty()) {
+    ++filled_fields;
+  }
+
+  // All effective-make-and-model strings should be lowercased, since v2.
+  // Since make-and-model strings could include non-Latin chars, only checking
+  // that it excludes all upper-case chars A-Z.
+  if (!std::all_of(reference.effective_make_and_model.begin(),
+                   reference.effective_make_and_model.end(),
+                   [](char c) -> bool { return !base::IsAsciiUpper(c); })) {
+    return false;
+  }
+  // Should have exactly one non-empty field.
+  return filled_fields == 1;
+}
+
 }  // namespace
 
 PrinterSearchData::PrinterSearchData() = default;
 PrinterSearchData::PrinterSearchData(const PrinterSearchData& other) = default;
 PrinterSearchData::~PrinterSearchData() = default;
 
+// static; copied directly from v2 PpdProvider
+// TODO(crbug.com/888189): figure out where this fits in the big picture
+std::string PpdProvider::PpdReferenceToCacheKey(
+    const Printer::PpdReference& reference) {
+  DCHECK(PpdReferenceIsWellFormed(reference));
+  // The key prefixes here are arbitrary, but ensure we can't have an (unhashed)
+  // collision between keys generated from different PpdReference fields.
+  if (!reference.effective_make_and_model.empty()) {
+    return std::string("em:") + reference.effective_make_and_model;
+  } else {
+    return std::string("up:") + reference.user_supplied_ppd_url;
+  }
+}
+
 // static
 scoped_refptr<PpdProvider> PpdProvider::Create(
     const std::string& browser_locale,
diff --git a/chromeos/printing/ppd_provider_v3.h b/chromeos/printing/ppd_provider_v3.h
index dd02561..21fcba75 100644
--- a/chromeos/printing/ppd_provider_v3.h
+++ b/chromeos/printing/ppd_provider_v3.h
@@ -18,7 +18,7 @@
 //
 // TODO(crbug.com/888189): fold this into ppd_provider.h,
 // deprecating the existing static Create() method.
-scoped_refptr<PpdProvider> CreateV3Provider(
+CHROMEOS_EXPORT scoped_refptr<PpdProvider> CreateV3Provider(
     base::StringPiece browser_locale,
     const base::Version& current_version,
     scoped_refptr<PpdCache> cache,
diff --git a/chromeos/printing/ppd_provider_v3_unittest.cc b/chromeos/printing/ppd_provider_v3_unittest.cc
new file mode 100644
index 0000000..591404b9
--- /dev/null
+++ b/chromeos/printing/ppd_provider_v3_unittest.cc
@@ -0,0 +1,1017 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/printing/ppd_provider_v3.h"
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/simple_test_clock.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_message_loop.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/version.h"
+#include "chromeos/constants/chromeos_paths.h"
+#include "chromeos/printing/ppd_cache.h"
+#include "chromeos/printing/ppd_metadata_manager.h"
+#include "chromeos/printing/printer_config_cache.h"
+#include "chromeos/printing/printer_configuration.h"
+#include "net/base/net_errors.h"
+#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace {
+
+using PrinterDiscoveryType = PrinterSearchData::PrinterDiscoveryType;
+
+// Name of the fake server we're resolving ppds from.
+const char kPpdServer[] = "bogus.google.com";
+
+// A pseudo-ppd that should get cupsFilter lines extracted from it.
+const char kCupsFilterPpdContents[] = R"(
+Other random contents that we don't care about.
+*cupsFilter: "application/vnd.cups-raster 0 my_filter"
+More random contents that we don't care about
+*cupsFilter: "application/vnd.cups-awesome 0 a_different_filter"
+*cupsFilter: "application/vnd.cups-awesomesauce 0 filter3"
+Yet more randome contents that we don't care about.
+More random contents that we don't care about.
+)";
+
+// A pseudo-ppd that should get cupsFilter2 lines extracted from it.
+// We also have cupsFilter lines in here, but since cupsFilter2 lines
+// exist, the cupsFilter lines should be ignored.
+const char kCupsFilter2PpdContents[] = R"(
+Other random contents that we don't care about.
+*cupsFilter: "application/vnd.cups-raster 0 my_filter"
+More random contents that we don't care about
+*cupsFilter2: "foo bar 0 the_real_filter"
+*cupsFilter2: "bar baz 381 another_real_filter"
+Yet more randome contents that we don't care about.
+More random contents that we don't care about.
+)";
+
+class PpdProviderTest : public ::testing::Test {
+ public:
+  PpdProviderTest()
+      : task_environment_(base::test::TaskEnvironment::MainThreadType::IO) {
+    TurnOffFakePpdServer();
+  }
+
+  void SetUp() override {
+    ASSERT_TRUE(ppd_cache_temp_dir_.CreateUniqueTempDir());
+  }
+
+  void TearDown() override { StopFakePpdServer(); }
+
+  // Create and return a provider for a test that uses the given |locale|.  If
+  // run_cache_on_test_thread is true, we'll run the cache using the
+  // task_environment_; otherwise we'll let it spawn it's own background
+  // threads.  You should only run the cache on the test thread if you need to
+  // explicitly drain cache actions independently of draining ppd provider
+  // actions; otherwise letting the cache spawn its own thread should be safe,
+  // and better exercises the code paths under test.
+  scoped_refptr<PpdProvider> CreateProvider(const std::string& locale,
+                                            bool run_cache_on_test_thread) {
+    auto provider_options = PpdProvider::Options();
+    provider_options.ppd_server_root = std::string("https://") + kPpdServer;
+
+    if (run_cache_on_test_thread) {
+      ppd_cache_ = PpdCache::CreateForTesting(
+          ppd_cache_temp_dir_.GetPath(),
+          task_environment_.GetMainThreadTaskRunner());
+    } else {
+      ppd_cache_ = PpdCache::Create(ppd_cache_temp_dir_.GetPath());
+    }
+
+    auto manager_config_cache =
+        PrinterConfigCache::Create(&clock_, base::BindLambdaForTesting([&]() {
+          return reinterpret_cast<network::mojom::URLLoaderFactory*>(
+              &loader_factory_);
+        }));
+    auto manager = PpdMetadataManager::Create(locale, &clock_,
+                                              std::move(manager_config_cache));
+    auto config_cache =
+        PrinterConfigCache::Create(&clock_, base::BindLambdaForTesting([&]() {
+          return reinterpret_cast<network::mojom::URLLoaderFactory*>(
+              &loader_factory_);
+        }));
+    return CreateV3Provider(locale, base::Version("40.8.6753.09"), ppd_cache_,
+                            std::move(manager), std::move(config_cache));
+  }
+
+  // Fill loader_factory_ with preset contents for test URLs
+  void StartFakePpdServer() {
+    loader_factory_.ClearResponses();
+    for (const auto& entry : server_contents()) {
+      network::URLLoaderCompletionStatus status;
+      if (!entry.second.empty()) {
+        status.decoded_body_length = entry.second.size();
+      } else {
+        status.error_code = net::ERR_ADDRESS_UNREACHABLE;
+      }
+
+      loader_factory_.AddResponse(FileToURL(entry.first),
+                                  network::mojom::URLResponseHead::New(),
+                                  entry.second, status);
+    }
+  }
+
+  // Interceptor posts a *task* during destruction that actually unregisters
+  // things.  So we have to run the message loop post-interceptor-destruction to
+  // actually unregister the URLs, otherwise they won't *actually* be
+  // unregistered until the next time we invoke the message loop.  Which may be
+  // in the middle of the next test.
+  //
+  // Note this is harmless to call if we haven't started a fake ppd server.
+  void StopFakePpdServer() {
+    TurnOffFakePpdServer();
+    task_environment_.RunUntilIdle();
+  }
+
+  // Capture the result of a ResolveManufacturers() call.
+  void CaptureResolveManufacturers(PpdProvider::CallbackResultCode code,
+                                   const std::vector<std::string>& data) {
+    captured_resolve_manufacturers_.push_back({code, data});
+  }
+
+  // Capture the result of a ResolvePrinters() call.
+  void CaptureResolvePrinters(PpdProvider::CallbackResultCode code,
+                              const PpdProvider::ResolvedPrintersList& data) {
+    captured_resolve_printers_.push_back({code, data});
+  }
+
+  // Capture the result of a ResolvePpd() call.
+  void CaptureResolvePpd(PpdProvider::CallbackResultCode code,
+                         const std::string& ppd_contents) {
+    CapturedResolvePpdResults results;
+    results.code = code;
+    results.ppd_contents = ppd_contents;
+    captured_resolve_ppd_.push_back(results);
+  }
+
+  // Capture the result of a ResolveUsbIds() call.
+  void CaptureResolvePpdReference(PpdProvider::CallbackResultCode code,
+                                  const Printer::PpdReference& ref,
+                                  const std::string& usb_manufacturer) {
+    captured_resolve_ppd_references_.push_back({code, ref, usb_manufacturer});
+  }
+
+  // Capture the result of a ResolvePpdLicense() call.
+  void CaptureResolvePpdLicense(PpdProvider::CallbackResultCode code,
+                                const std::string& license) {
+    captured_resolve_ppd_license_.push_back({code, license});
+  }
+
+  void CaptureReverseLookup(PpdProvider::CallbackResultCode code,
+                            const std::string& manufacturer,
+                            const std::string& model) {
+    captured_reverse_lookup_.push_back({code, manufacturer, model});
+  }
+
+  // Discard the result of a ResolvePpd() call.
+  void DiscardResolvePpd(PpdProvider::CallbackResultCode code,
+                         const std::string& contents) {}
+
+ protected:
+  // Run a ResolveManufacturers run from the given locale, expect to get
+  // results in expected_used_locale.
+  void RunLocalizationTest(const std::string& browser_locale,
+                           const std::string& expected_used_locale) {
+    captured_resolve_manufacturers_.clear();
+    auto provider = CreateProvider(browser_locale, false);
+    provider->ResolveManufacturers(base::BindOnce(
+        &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
+    task_environment_.RunUntilIdle();
+    provider = nullptr;
+    ASSERT_EQ(captured_resolve_manufacturers_.size(), 1UL);
+    EXPECT_EQ(captured_resolve_manufacturers_[0].first, PpdProvider::SUCCESS);
+
+    const auto& result_vec = captured_resolve_manufacturers_[0].second;
+
+    // It's sufficient to check for one of the expected locale keys to make sure
+    // we got the right map.
+    EXPECT_TRUE(
+        base::Contains(result_vec, "manufacturer_a_" + expected_used_locale));
+  }
+
+  // Fake server being down, return ERR_ADDRESS_UNREACHABLE for all endpoints
+  void TurnOffFakePpdServer() {
+    loader_factory_.ClearResponses();
+    network::URLLoaderCompletionStatus status(net::ERR_ADDRESS_UNREACHABLE);
+    for (const auto& entry : server_contents()) {
+      loader_factory_.AddResponse(FileToURL(entry.first),
+                                  network::mojom::URLResponseHead::New(), "",
+                                  status);
+    }
+  }
+
+  GURL FileToURL(std::string filename) {
+    return GURL(
+        base::StringPrintf("https://%s/%s", kPpdServer, filename.c_str()));
+  }
+
+  // List of relevant endpoint for this FakeServer
+  std::vector<std::pair<std::string, std::string>> server_contents() const {
+    // Use brace initialization to express the desired server contents as "url",
+    // "contents" pairs.
+    return {{"metadata_v2/locales.json",
+             R"(["en",
+             "es-mx",
+             "en-gb"])"},
+            {"metadata_v2/index-01.json",
+             R"([
+             ["printer_a_ref", "printer_a.ppd", {"license": "fake_license"}]
+            ])"},
+            {"metadata_v2/index-02.json",
+             R"([
+             ["printer_b_ref", "printer_b.ppd"]
+            ])"},
+            {"metadata_v2/index-03.json",
+             R"([
+             ["printer_c_ref", "printer_c.ppd"]
+            ])"},
+            {"metadata_v2/index-04.json",
+             R"([
+             ["printer_d_ref", "printer_d.ppd"]
+            ])"},
+            {"metadata_v2/index-05.json",
+             R"([
+             ["printer_e_ref", "printer_e.ppd"]
+            ])"},
+            {"metadata_v2/index-13.json",
+             R"([
+            ])"},
+            {"metadata_v2/usb-031f.json",
+             R"([
+             [1592, "Some canonical reference"],
+             [6535, "Some other canonical reference"]
+            ])"},
+            {"metadata_v2/usb-03f0.json", ""},
+            {"metadata_v2/usb-1234.json", ""},
+            {"metadata_v2/manufacturers-en.json",
+             R"([
+            ["manufacturer_a_en", "manufacturer_a.json"],
+            ["manufacturer_b_en", "manufacturer_b.json"]
+            ])"},
+            {"metadata_v2/manufacturers-en-gb.json",
+             R"([
+            ["manufacturer_a_en-gb", "manufacturer_a.json"],
+            ["manufacturer_b_en-gb", "manufacturer_b.json"]
+            ])"},
+            {"metadata_v2/manufacturers-es-mx.json",
+             R"([
+            ["manufacturer_a_es-mx", "manufacturer_a.json"],
+            ["manufacturer_b_es-mx", "manufacturer_b.json"]
+            ])"},
+            {"metadata_v2/manufacturer_a.json",
+             R"([
+            ["printer_a", "printer_a_ref"],
+            ["printer_b", "printer_b_ref"],
+            ["printer_d", "printer_d_ref"]
+            ])"},
+            {"metadata_v2/manufacturer_a.json",
+             R"([
+            ["printer_a", "printer_a_ref",
+              {"min_milestone":25.0000}],
+            ["printer_b", "printer_b_ref",
+              {"min_milestone":30.0000, "max_milestone":45.0000}],
+            ["printer_d", "printer_d_ref",
+              {"min_milestone":60.0000, "max_milestone":75.0000}]
+            ])"},
+            {"metadata_v2/manufacturer_b.json",
+             R"([
+            ["printer_c", "printer_c_ref"],
+            ["printer_e", "printer_e_ref"]
+            ])"},
+            {"metadata_v2/reverse_index-en-01.json",
+             R"([
+             ["printer_a_ref", "manufacturer_a_en", "printer_a"]
+             ])"},
+            {"metadata_v2/reverse_index-en-19.json",
+             R"([
+             ])"},
+            {"metadata_v2/manufacturer_b.json",
+             R"([
+            ["printer_c", "printer_c_ref",
+              {"max_milestone":55.0000}],
+            ["printer_e", "printer_e_ref",
+              {"min_milestone":17.0000, "max_milestone":33.0000}]
+            ])"},
+            {"ppds/printer_a.ppd", kCupsFilterPpdContents},
+            {"ppds/printer_b.ppd", kCupsFilter2PpdContents},
+            {"ppds/printer_c.ppd", "c"},
+            {"ppds/printer_d.ppd", "d"},
+            {"ppds/printer_e.ppd", "e"},
+            {"user_supplied_ppd_directory/user_supplied.ppd", "u"}};
+  }
+
+  // Environment for task schedulers.
+  base::test::TaskEnvironment task_environment_;
+
+  std::vector<
+      std::pair<PpdProvider::CallbackResultCode, std::vector<std::string>>>
+      captured_resolve_manufacturers_;
+
+  std::vector<std::pair<PpdProvider::CallbackResultCode,
+                        PpdProvider::ResolvedPrintersList>>
+      captured_resolve_printers_;
+
+  struct CapturedResolvePpdResults {
+    PpdProvider::CallbackResultCode code;
+    std::string ppd_contents;
+  };
+  std::vector<CapturedResolvePpdResults> captured_resolve_ppd_;
+
+  struct CapturedResolvePpdReferenceResults {
+    PpdProvider::CallbackResultCode code;
+    Printer::PpdReference ref;
+    std::string usb_manufacturer;
+  };
+
+  std::vector<CapturedResolvePpdReferenceResults>
+      captured_resolve_ppd_references_;
+
+  struct CapturedReverseLookup {
+    PpdProvider::CallbackResultCode code;
+    std::string manufacturer;
+    std::string model;
+  };
+  std::vector<CapturedReverseLookup> captured_reverse_lookup_;
+
+  struct CapturedResolvePpdLicense {
+    PpdProvider::CallbackResultCode code;
+    std::string license;
+  };
+  std::vector<CapturedResolvePpdLicense> captured_resolve_ppd_license_;
+
+  base::ScopedTempDir ppd_cache_temp_dir_;
+  base::ScopedTempDir interceptor_temp_dir_;
+
+  // Reference to the underlying ppd_cache_ so we can muck with it to test
+  // cache-dependent behavior of ppd_provider_.
+  scoped_refptr<PpdCache> ppd_cache_;
+
+  // Misc extra stuff needed for the test environment to function.
+  base::SimpleTestClock clock_;
+  network::TestURLLoaderFactory loader_factory_;
+};
+
+// Test that we get back manufacturer maps as expected.
+TEST_F(PpdProviderTest, ManufacturersFetch) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+  // Issue two requests at the same time, both should be resolved properly.
+  provider->ResolveManufacturers(base::BindOnce(
+      &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
+  provider->ResolveManufacturers(base::BindOnce(
+      &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+  ASSERT_EQ(2UL, captured_resolve_manufacturers_.size());
+  std::vector<std::string> expected_result(
+      {"manufacturer_a_en", "manufacturer_b_en"});
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[0].first);
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[1].first);
+  EXPECT_TRUE(captured_resolve_manufacturers_[0].second == expected_result);
+  EXPECT_TRUE(captured_resolve_manufacturers_[1].second == expected_result);
+}
+
+// Test that we get a reasonable error when we have no server to contact.  Tis
+// is almost exactly the same as the above test, we just don't bring up the fake
+// server first.
+TEST_F(PpdProviderTest, ManufacturersFetchNoServer) {
+  auto provider = CreateProvider("en", false);
+  // Issue two requests at the same time, both should be resolved properly.
+  provider->ResolveManufacturers(base::BindOnce(
+      &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
+  provider->ResolveManufacturers(base::BindOnce(
+      &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+  ASSERT_EQ(2UL, captured_resolve_manufacturers_.size());
+  EXPECT_EQ(PpdProvider::SERVER_ERROR,
+            captured_resolve_manufacturers_[0].first);
+  EXPECT_EQ(PpdProvider::SERVER_ERROR,
+            captured_resolve_manufacturers_[1].first);
+  EXPECT_TRUE(captured_resolve_manufacturers_[0].second.empty());
+  EXPECT_TRUE(captured_resolve_manufacturers_[1].second.empty());
+}
+
+// Test that we get things in the requested locale, and that fallbacks are sane.
+TEST_F(PpdProviderTest, LocalizationAndFallbacks) {
+  StartFakePpdServer();
+  RunLocalizationTest("en-gb", "en-gb");
+  RunLocalizationTest("en-blah", "en");
+  RunLocalizationTest("en-gb-foo", "en-gb");
+  RunLocalizationTest("es", "es-mx");
+  RunLocalizationTest("bogus", "en");
+}
+
+// Tests that mutiples requests for make-and-model resolution can be fulfilled
+// simultaneously.
+TEST_F(PpdProviderTest, RepeatedMakeModel) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+
+  PrinterSearchData unrecognized_printer;
+  unrecognized_printer.discovery_type = PrinterDiscoveryType::kManual;
+  unrecognized_printer.make_and_model = {"Printer Printer"};
+
+  PrinterSearchData recognized_printer;
+  recognized_printer.discovery_type = PrinterDiscoveryType::kManual;
+  recognized_printer.make_and_model = {"printer_a_ref"};
+
+  PrinterSearchData mixed;
+  mixed.discovery_type = PrinterDiscoveryType::kManual;
+  mixed.make_and_model = {"printer_a_ref", "Printer Printer"};
+
+  // Resolve the same thing repeatedly.
+  provider->ResolvePpdReference(
+      unrecognized_printer,
+      base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                     base::Unretained(this)));
+  provider->ResolvePpdReference(
+      mixed, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                            base::Unretained(this)));
+  provider->ResolvePpdReference(
+      recognized_printer,
+      base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                     base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+
+  ASSERT_EQ(static_cast<size_t>(3), captured_resolve_ppd_references_.size());
+  EXPECT_EQ(PpdProvider::NOT_FOUND, captured_resolve_ppd_references_[0].code);
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[1].code);
+  EXPECT_EQ("printer_a_ref",
+            captured_resolve_ppd_references_[1].ref.effective_make_and_model);
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[2].code);
+  EXPECT_EQ("printer_a_ref",
+            captured_resolve_ppd_references_[2].ref.effective_make_and_model);
+}
+
+// Test successful and unsuccessful usb resolutions.
+TEST_F(PpdProviderTest, UsbResolution) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+
+  PrinterSearchData search_data;
+  search_data.discovery_type = PrinterDiscoveryType::kUsb;
+
+  // Should get back "Some canonical reference"
+  search_data.usb_vendor_id = 0x031f;
+  search_data.usb_product_id = 1592;
+  provider->ResolvePpdReference(
+      search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                                  base::Unretained(this)));
+  // Should get back "Some other canonical reference"
+  search_data.usb_vendor_id = 0x031f;
+  search_data.usb_product_id = 6535;
+  provider->ResolvePpdReference(
+      search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                                  base::Unretained(this)));
+
+  // Vendor id that exists, nonexistent device id, should get a NOT_FOUND.
+  search_data.usb_vendor_id = 0x031f;
+  search_data.usb_product_id = 8162;
+  provider->ResolvePpdReference(
+      search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                                  base::Unretained(this)));
+
+  // Nonexistent vendor id, should get a NOT_FOUND in the real world, but
+  // the URL interceptor we're using considers all nonexistent files to
+  // be effectively CONNECTION REFUSED, so we just check for non-success
+  // on this one.
+  search_data.usb_vendor_id = 0x1234;
+  search_data.usb_product_id = 1782;
+  provider->ResolvePpdReference(
+      search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                                  base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+
+  ASSERT_EQ(captured_resolve_ppd_references_.size(), static_cast<size_t>(4));
+  EXPECT_EQ(captured_resolve_ppd_references_[0].code, PpdProvider::SUCCESS);
+  EXPECT_EQ(captured_resolve_ppd_references_[0].ref.effective_make_and_model,
+            "Some canonical reference");
+  EXPECT_EQ(captured_resolve_ppd_references_[1].code, PpdProvider::SUCCESS);
+  EXPECT_EQ(captured_resolve_ppd_references_[1].ref.effective_make_and_model,
+            "Some other canonical reference");
+  EXPECT_EQ(captured_resolve_ppd_references_[2].code, PpdProvider::NOT_FOUND);
+  EXPECT_FALSE(captured_resolve_ppd_references_[3].code ==
+               PpdProvider::SUCCESS);
+}
+
+// For convenience a null ResolveManufacturers callback target.
+void ResolveManufacturersNop(PpdProvider::CallbackResultCode code,
+                             const std::vector<std::string>& v) {}
+
+// Test basic ResolvePrinters() functionality.  At the same time, make
+// sure we can get the PpdReference for each of the resolved printers.
+TEST_F(PpdProviderTest, ResolvePrinters) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+
+  // Grab the manufacturer list, but don't bother to save it, we know what
+  // should be in it and we check that elsewhere.  We just need to run the
+  // resolve to populate the internal PpdProvider structures.
+  provider->ResolveManufacturers(base::BindOnce(&ResolveManufacturersNop));
+  task_environment_.RunUntilIdle();
+
+  provider->ResolvePrinters(
+      "manufacturer_a_en",
+      base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
+                     base::Unretained(this)));
+  provider->ResolvePrinters(
+      "manufacturer_b_en",
+      base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
+                     base::Unretained(this)));
+
+  task_environment_.RunUntilIdle();
+  ASSERT_EQ(2UL, captured_resolve_printers_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[0].first);
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[1].first);
+  EXPECT_EQ(2UL, captured_resolve_printers_[0].second.size());
+
+  // First capture should get back printer_a, and printer_b, with ppd
+  // reference effective make and models of printer_a_ref and printer_b_ref.
+  const auto& capture0 = captured_resolve_printers_[0].second;
+  ASSERT_EQ(2UL, capture0.size());
+  EXPECT_EQ("printer_a", capture0[0].name);
+  EXPECT_EQ("printer_a_ref", capture0[0].ppd_ref.effective_make_and_model);
+
+  EXPECT_EQ("printer_b", capture0[1].name);
+  EXPECT_EQ("printer_b_ref", capture0[1].ppd_ref.effective_make_and_model);
+
+  // Second capture should get back printer_c with effective make and model of
+  // printer_c_ref
+  const auto& capture1 = captured_resolve_printers_[1].second;
+  ASSERT_EQ(1UL, capture1.size());
+  EXPECT_EQ("printer_c", capture1[0].name);
+  EXPECT_EQ("printer_c_ref", capture1[0].ppd_ref.effective_make_and_model);
+  // EXPECT_EQ(base::Version("55"), capture1[0].restrictions.max_milestone);
+}
+
+// Test that if we give a bad reference to ResolvePrinters(), we get an
+// INTERNAL_ERROR.
+TEST_F(PpdProviderTest, ResolvePrintersBadReference) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+  provider->ResolveManufacturers(base::BindOnce(&ResolveManufacturersNop));
+  task_environment_.RunUntilIdle();
+
+  provider->ResolvePrinters(
+      "bogus_doesnt_exist",
+      base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
+                     base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+  ASSERT_EQ(1UL, captured_resolve_printers_.size());
+  EXPECT_EQ(PpdProvider::INTERNAL_ERROR, captured_resolve_printers_[0].first);
+}
+
+// Test that if the server is unavailable, we get SERVER_ERRORs back out.
+TEST_F(PpdProviderTest, ResolvePrintersNoServer) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+  provider->ResolveManufacturers(base::BindOnce(&ResolveManufacturersNop));
+  task_environment_.RunUntilIdle();
+
+  StopFakePpdServer();
+
+  provider->ResolvePrinters(
+      "manufacturer_a_en",
+      base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
+                     base::Unretained(this)));
+  provider->ResolvePrinters(
+      "manufacturer_b_en",
+      base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
+                     base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+  ASSERT_EQ(2UL, captured_resolve_printers_.size());
+  EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[0].first);
+  EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[1].first);
+}
+
+// Test a successful ppd resolution from an effective_make_and_model reference.
+TEST_F(PpdProviderTest, ResolveServerKeyPpd) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+  Printer::PpdReference ref;
+  ref.effective_make_and_model = "printer_b_ref";
+  provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                           base::Unretained(this)));
+  ref.effective_make_and_model = "printer_c_ref";
+  provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                           base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+
+  ASSERT_EQ(2UL, captured_resolve_ppd_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(kCupsFilter2PpdContents, captured_resolve_ppd_[0].ppd_contents);
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[1].code);
+  EXPECT_EQ("c", captured_resolve_ppd_[1].ppd_contents);
+}
+
+// Test that we *don't* resolve a ppd URL over non-file schemes.  It's not clear
+// whether we'll want to do this in the long term, but for now this is
+// disallowed because we're not sure we completely understand the security
+// implications.
+TEST_F(PpdProviderTest, ResolveUserSuppliedUrlPpdFromNetworkFails) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+
+  Printer::PpdReference ref;
+  ref.user_supplied_ppd_url = base::StringPrintf(
+      "https://%s/user_supplied_ppd_directory/user_supplied.ppd", kPpdServer);
+  provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                           base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+  EXPECT_EQ(PpdProvider::INTERNAL_ERROR, captured_resolve_ppd_[0].code);
+  EXPECT_TRUE(captured_resolve_ppd_[0].ppd_contents.empty());
+}
+
+// Test a successful ppd resolution from a user_supplied_url field when
+// reading from a file.  Note we shouldn't need the server to be up
+// to do this successfully, as we should be able to do this offline.
+TEST_F(PpdProviderTest, ResolveUserSuppliedUrlPpdFromFile) {
+  auto provider = CreateProvider("en", false);
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
+
+  std::string user_ppd_contents = "Woohoo";
+
+  ASSERT_TRUE(base::WriteFile(filename, user_ppd_contents));
+
+  Printer::PpdReference ref;
+  ref.user_supplied_ppd_url =
+      base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
+  provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                           base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(user_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
+}
+
+// Test that we cache ppd resolutions when we fetch them and that we can resolve
+// from the cache without the server available.
+TEST_F(PpdProviderTest, ResolvedPpdsGetCached) {
+  auto provider = CreateProvider("en", false);
+  std::string user_ppd_contents = "Woohoo";
+  Printer::PpdReference ref;
+  {
+    base::ScopedTempDir temp_dir;
+    ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+    base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
+
+    ASSERT_TRUE(base::WriteFile(filename, user_ppd_contents));
+
+    ref.user_supplied_ppd_url =
+        base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
+    provider->ResolvePpd(ref,
+                         base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                        base::Unretained(this)));
+    task_environment_.RunUntilIdle();
+
+    ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+    EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+    EXPECT_EQ(user_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
+  }
+  // ScopedTempDir goes out of scope, so the source file should now be
+  // deleted.  But if we resolve again, we should hit the cache and
+  // still be successful.
+
+  captured_resolve_ppd_.clear();
+
+  // Recreate the provider to make sure we don't have any memory caches which
+  // would mask problems with disk persistence.
+  provider = CreateProvider("en", false);
+
+  // Re-resolve.
+  provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                           base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(user_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
+}
+
+// Test that all entrypoints will correctly work with case-insensitve
+// effective-make-and-model strings.
+TEST_F(PpdProviderTest, CaseInsensitiveMakeAndModel) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+  std::string ref = "pRiNteR_A_reF";
+
+  Printer::PpdReference ppd_ref;
+  ppd_ref.effective_make_and_model = ref;
+  provider->ResolvePpd(ppd_ref,
+                       base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                      base::Unretained(this)));
+  provider->ReverseLookup(ref,
+                          base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
+                                         base::Unretained(this)));
+  PrinterSearchData printer_info;
+  printer_info.make_and_model = {ref};
+  provider->ResolvePpdReference(
+      printer_info, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                                   base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+
+  // Check PpdProvider::ResolvePpd
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(kCupsFilterPpdContents, captured_resolve_ppd_[0].ppd_contents);
+
+  // Check PpdProvider::ReverseLookup
+  ASSERT_EQ(1UL, captured_reverse_lookup_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_reverse_lookup_[0].code);
+  EXPECT_EQ("manufacturer_a_en", captured_reverse_lookup_[0].manufacturer);
+  EXPECT_EQ("printer_a", captured_reverse_lookup_[0].model);
+
+  // Check PpdProvider::ResolvePpdReference
+  ASSERT_EQ(1UL, captured_resolve_ppd_references_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[0].code);
+  EXPECT_EQ("printer_a_ref",
+            captured_resolve_ppd_references_[0].ref.effective_make_and_model);
+}
+
+// Tests that ResolvePpdLicense is able to correctly source the index and
+// determine the name of the PPD license associated with the given effecive make
+// and model (if any).
+TEST_F(PpdProviderTest, ResolvePpdLicense) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+
+  // For this effective_make_and_model, we expect that there is associated
+  // license.
+  const char kEmm1[] = "printer_a_ref";
+  provider->ResolvePpdLicense(
+      kEmm1, base::BindOnce(&PpdProviderTest::CaptureResolvePpdLicense,
+                            base::Unretained(this)));
+
+  // We do not expect there to be any license associated with this
+  // effective_make_and_model, so the response should be empty.
+  const char kEmm2[] = "printer_b_ref";
+  provider->ResolvePpdLicense(
+      kEmm2, base::BindOnce(&PpdProviderTest::CaptureResolvePpdLicense,
+                            base::Unretained(this)));
+
+  task_environment_.RunUntilIdle();
+
+  ASSERT_EQ(2UL, captured_resolve_ppd_license_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_license_[0].code);
+  EXPECT_EQ("fake_license", captured_resolve_ppd_license_[0].license);
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_license_[1].code);
+  EXPECT_EQ("", captured_resolve_ppd_license_[1].license);
+}
+
+// Verifies that we can extract the Manufacturer and Model selectison for a
+// given effective make and model.
+TEST_F(PpdProviderTest, ReverseLookup) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+  std::string ref = "printer_a_ref";
+  provider->ReverseLookup(ref,
+                          base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
+                                         base::Unretained(this)));
+  // TODO(skau): PpdProvider has a race condition that prevents running these
+  // requests in parallel.
+  task_environment_.RunUntilIdle();
+
+  std::string ref_fail = "printer_does_not_exist";
+  provider->ReverseLookup(ref_fail,
+                          base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
+                                         base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+
+  ASSERT_EQ(2U, captured_reverse_lookup_.size());
+  CapturedReverseLookup success_capture = captured_reverse_lookup_[0];
+  EXPECT_EQ(PpdProvider::SUCCESS, success_capture.code);
+  EXPECT_EQ("manufacturer_a_en", success_capture.manufacturer);
+  EXPECT_EQ("printer_a", success_capture.model);
+
+  CapturedReverseLookup failed_capture = captured_reverse_lookup_[1];
+  EXPECT_EQ(PpdProvider::NOT_FOUND, failed_capture.code);
+}
+
+// If we have a fresh entry in the cache, we shouldn't need to go out to the
+// network at all to successfully resolve a ppd.
+TEST_F(PpdProviderTest, FreshCacheHitNoNetworkTraffic) {
+  // Explicitly *not* starting a fake server.
+  std::string cached_ppd_contents =
+      "These cached contents are different from what's being served";
+  auto provider = CreateProvider("en", true);
+  Printer::PpdReference ref;
+  ref.effective_make_and_model = "printer_a_ref";
+  std::string cache_key = PpdProvider::PpdReferenceToCacheKey(ref);
+  // Cache exists, and is just created, so should be fresh.
+  ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
+                              cached_ppd_contents, base::TimeDelta());
+  task_environment_.RunUntilIdle();
+  provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                           base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+
+  // Should get the cached (not served) results back, and not have hit the
+  // network.
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(cached_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
+}
+
+// If we have a stale cache entry and a good network connection, does the cache
+// get refreshed during a resolution?
+TEST_F(PpdProviderTest, StaleCacheGetsRefreshed) {
+  StartFakePpdServer();
+  std::string cached_ppd_contents =
+      "These cached contents are different from what's being served";
+  auto provider = CreateProvider("en", true);
+  // printer_ref_a resolves to kCupsFilterPpdContents on the server.
+  std::string expected_ppd = kCupsFilterPpdContents;
+  Printer::PpdReference ref;
+  ref.effective_make_and_model = "printer_a_ref";
+  std::string cache_key = PpdProvider::PpdReferenceToCacheKey(ref);
+  // Cache exists, and is 6 months old, so really stale.
+  ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
+                              cached_ppd_contents,
+                              base::TimeDelta::FromDays(180));
+  task_environment_.RunUntilIdle();
+  provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                           base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+
+  // Should get the served results back, not the stale cached ones.
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(captured_resolve_ppd_[0].ppd_contents, expected_ppd);
+
+  // Check that the cache was also updated.
+  PpdCache::FindResult captured_find_result;
+  // This is just a complicated syntax around the idea "use the Find callback to
+  // save the result in captured_find_result.
+  ppd_cache_->Find(PpdProvider::PpdReferenceToCacheKey(ref),
+                   base::BindOnce(
+                       [](PpdCache::FindResult* captured_find_result,
+                          const PpdCache::FindResult& find_result) {
+                         *captured_find_result = find_result;
+                       },
+                       &captured_find_result));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ(captured_find_result.success, true);
+  EXPECT_EQ(captured_find_result.contents, expected_ppd);
+  EXPECT_LT(captured_find_result.age, base::TimeDelta::FromDays(1));
+}
+
+// Test that, if we have an old entry in the cache that needs to be refreshed,
+// and we fail to contact the server, we still use the cached version.
+TEST_F(PpdProviderTest, StaleCacheGetsUsedIfNetworkFails) {
+  // Note that we're explicitly *not* starting the Fake ppd server in this test.
+  std::string cached_ppd_contents =
+      "These cached contents are different from what's being served";
+  auto provider = CreateProvider("en", true);
+  Printer::PpdReference ref;
+  ref.effective_make_and_model = "printer_a_ref";
+  std::string cache_key = PpdProvider::PpdReferenceToCacheKey(ref);
+  // Cache exists, and is 6 months old, so really stale.
+  ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
+                              cached_ppd_contents,
+                              base::TimeDelta::FromDays(180));
+  task_environment_.RunUntilIdle();
+  provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                           base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+
+  // Should successfully resolve from the cache, even though it's stale.
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(cached_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
+
+  // Check that the cache is *not* updated; it should remain stale.
+  PpdCache::FindResult captured_find_result;
+  // This is just a complicated syntax around the idea "use the Find callback to
+  // save the result in captured_find_result.
+  ppd_cache_->Find(PpdProvider::PpdReferenceToCacheKey(ref),
+                   base::BindOnce(
+                       [](PpdCache::FindResult* captured_find_result,
+                          const PpdCache::FindResult& find_result) {
+                         *captured_find_result = find_result;
+                       },
+                       &captured_find_result));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ(captured_find_result.success, true);
+  EXPECT_EQ(captured_find_result.contents, cached_ppd_contents);
+  EXPECT_GT(captured_find_result.age, base::TimeDelta::FromDays(179));
+}
+
+// For user-provided ppds, we should always use the latest version on
+// disk if it still exists there.
+TEST_F(PpdProviderTest, UserPpdAlwaysRefreshedIfAvailable) {
+  base::ScopedTempDir temp_dir;
+  StartFakePpdServer();
+  std::string cached_ppd_contents = "Cached Ppd Contents";
+  std::string disk_ppd_contents = "Updated Ppd Contents";
+  auto provider = CreateProvider("en", true);
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
+
+  Printer::PpdReference ref;
+  ref.user_supplied_ppd_url =
+      base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
+
+  // Put cached_ppd_contents into the cache.
+  ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
+                              cached_ppd_contents, base::TimeDelta());
+  task_environment_.RunUntilIdle();
+
+  // Write different contents to disk, so that the cached contents are
+  // now stale.
+  ASSERT_TRUE(base::WriteFile(filename, disk_ppd_contents));
+
+  provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
+                                           base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+  ASSERT_EQ(1UL, captured_resolve_ppd_.size());
+  EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
+  EXPECT_EQ(disk_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
+
+  // Check that the cache was also updated with the new contents.
+  PpdCache::FindResult captured_find_result;
+  ppd_cache_->Find(PpdProvider::PpdReferenceToCacheKey(ref),
+                   base::BindOnce(
+                       [](PpdCache::FindResult* captured_find_result,
+                          const PpdCache::FindResult& find_result) {
+                         *captured_find_result = find_result;
+                       },
+                       &captured_find_result));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ(captured_find_result.success, true);
+  EXPECT_EQ(captured_find_result.contents, disk_ppd_contents);
+}
+
+// Test resolving usb manufacturer when failed to resolve PpdReference.
+TEST_F(PpdProviderTest, ResolveUsbManufacturer) {
+  StartFakePpdServer();
+  auto provider = CreateProvider("en", false);
+
+  PrinterSearchData search_data;
+  search_data.discovery_type = PrinterDiscoveryType::kUsb;
+
+  // Vendor id that exists, nonexistent device id, should get a NOT_FOUND.
+  // Although this is an unsupported printer model, we can still expect to get
+  // the manufacturer name.
+  search_data.usb_vendor_id = 0x03f0;
+  search_data.usb_product_id = 9999;
+  provider->ResolvePpdReference(
+      search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                                  base::Unretained(this)));
+
+  // Nonexistent vendor id, should get a NOT_FOUND in the real world, but
+  // the URL interceptor we're using considers all nonexistent files to
+  // be effectively CONNECTION REFUSED, so we just check for non-success
+  // on this one. We should also not be able to get a manufacturer name from a
+  // nonexistent vendor id.
+  search_data.usb_vendor_id = 0x1234;
+  search_data.usb_product_id = 1782;
+  provider->ResolvePpdReference(
+      search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
+                                  base::Unretained(this)));
+  task_environment_.RunUntilIdle();
+
+  ASSERT_EQ(static_cast<size_t>(2), captured_resolve_ppd_references_.size());
+  // Was able to find the printer manufactuer but unable to find the printer
+  // model should result in a NOT_FOUND.
+  EXPECT_EQ(PpdProvider::NOT_FOUND, captured_resolve_ppd_references_[0].code);
+  // Failed to grab the PPD for a USB printer, but should still be able to grab
+  // its manufacturer name.
+  EXPECT_EQ("HP", captured_resolve_ppd_references_[0].usb_manufacturer);
+
+  // Unable to find the PPD file should result in a failure.
+  EXPECT_FALSE(captured_resolve_ppd_references_[1].code ==
+               PpdProvider::SUCCESS);
+  // Unknown vendor id should result in an empty manufacturer string.
+  EXPECT_TRUE(captured_resolve_ppd_references_[1].usb_manufacturer.empty());
+}
+
+}  // namespace
+}  // namespace chromeos
diff --git a/components/autofill_assistant/browser/user_model.cc b/components/autofill_assistant/browser/user_model.cc
index 020f1b2..61d0a95f 100644
--- a/components/autofill_assistant/browser/user_model.cc
+++ b/components/autofill_assistant/browser/user_model.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "components/autofill_assistant/browser/user_model.h"
-#include "components/autofill_assistant/browser/field_formatter.h"
 
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
@@ -57,17 +56,9 @@
   return weak_ptr_factory_.GetWeakPtr();
 }
 
-void UserModel::SetValue(const std::string& input,
+void UserModel::SetValue(const std::string& identifier,
                          const ValueProto& value,
                          bool force_notification) {
-  // Replace all placeholders in the input.
-  auto formatted_identifier =
-      field_formatter::FormatString(input, identifier_placeholders_);
-  if (!formatted_identifier.has_value()) {
-    VLOG(2) << "Error setting value: placeholder not found for " << input;
-    return;
-  }
-  std::string identifier = *formatted_identifier;
   auto result = values_.emplace(identifier, value);
   if (!force_notification && !result.second && result.first->second == value &&
       value.is_client_side_only() ==
@@ -82,14 +73,8 @@
   }
 }
 
-base::Optional<ValueProto> UserModel::GetValue(const std::string& input) const {
-  // Replace all placeholders in the input.
-  auto formatted_identifier =
-      field_formatter::FormatString(input, identifier_placeholders_);
-  if (!formatted_identifier.has_value()) {
-    return base::nullopt;
-  }
-  std::string identifier = *formatted_identifier;
+base::Optional<ValueProto> UserModel::GetValue(
+    const std::string& identifier) const {
   auto it = values_.find(identifier);
   if (it != values_.end()) {
     return it->second;
@@ -161,20 +146,6 @@
   observers_.RemoveObserver(observer);
 }
 
-void UserModel::AddIdentifierPlaceholders(
-    const std::map<std::string, std::string> placeholders) {
-  for (const auto& placeholder : placeholders) {
-    identifier_placeholders_[placeholder.first] = placeholder.second;
-  }
-}
-
-void UserModel::RemoveIdentifierPlaceholders(
-    const std::map<std::string, std::string> placeholders) {
-  for (const auto& placeholder : placeholders) {
-    identifier_placeholders_.erase(placeholder.first);
-  }
-}
-
 void UserModel::SetAutofillCreditCards(
     std::unique_ptr<std::vector<std::unique_ptr<autofill::CreditCard>>>
         credit_cards) {
diff --git a/components/autofill_assistant/browser/user_model.h b/components/autofill_assistant/browser/user_model.h
index 266dee6..dd32253 100644
--- a/components/autofill_assistant/browser/user_model.h
+++ b/components/autofill_assistant/browser/user_model.h
@@ -74,17 +74,6 @@
     return values;
   }
 
-  // Adds a set of placeholders (overwrite if necessary). When looking up values
-  // by identifier, all occurrences of ${key} are automatically replaced by
-  // their value. Example: the current set of placeholders contains "i" -> "1".
-  // Looking up the value "value[${i}]" will now actually lookup "value[1]".
-  void AddIdentifierPlaceholders(
-      const std::map<std::string, std::string> placeholders);
-
-  // Removes a set of placeholders.
-  void RemoveIdentifierPlaceholders(
-      const std::map<std::string, std::string> placeholders);
-
   // Replaces the set of available autofill credit cards.
   void SetAutofillCreditCards(
       std::unique_ptr<std::vector<std::unique_ptr<autofill::CreditCard>>>
@@ -118,7 +107,6 @@
   friend class UserModelTest;
 
   std::map<std::string, ValueProto> values_;
-  std::map<std::string, std::string> identifier_placeholders_;
   std::map<std::string, std::unique_ptr<autofill::CreditCard>> credit_cards_;
   std::map<std::string, std::unique_ptr<autofill::AutofillProfile>> profiles_;
   base::ObserverList<Observer> observers_;
diff --git a/components/autofill_assistant/browser/user_model_unittest.cc b/components/autofill_assistant/browser/user_model_unittest.cc
index a1d7729..799d606 100644
--- a/components/autofill_assistant/browser/user_model_unittest.cc
+++ b/components/autofill_assistant/browser/user_model_unittest.cc
@@ -366,75 +366,4 @@
   EXPECT_TRUE(GetValues().at("identifier").is_client_side_only());
 }
 
-TEST_F(UserModelTest, GetValueWithPlaceholders) {
-  ValueProto value;
-  value.mutable_strings()->add_values("a");
-  value.mutable_strings()->add_values("b");
-  value.mutable_strings()->add_values("c");
-  model_.SetValue("multi_value", value);
-  model_.SetValue("single_value_0", SimpleValue(std::string("d")));
-  model_.SetValue("single_value_1", SimpleValue(std::string("e")));
-  model_.SetValue("single_value_2", SimpleValue(std::string("f")));
-
-  EXPECT_EQ(model_.GetValue("multi_value[${i}]"), base::nullopt);
-  EXPECT_EQ(model_.GetValue("single_value_i"), base::nullopt);
-  model_.AddIdentifierPlaceholders({{"i", "0"}});
-  EXPECT_EQ(model_.GetValue("multi_value[${i}]"),
-            SimpleValue(std::string("a")));
-  EXPECT_EQ(model_.GetValue("single_value_${i}"),
-            SimpleValue(std::string("d")));
-
-  // Add placeholder.
-  model_.AddIdentifierPlaceholders({{"j", "1"}});
-  EXPECT_EQ(model_.GetValue("multi_value[${j}]"),
-            SimpleValue(std::string("b")));
-  EXPECT_EQ(model_.GetValue("single_value_${j}"),
-            SimpleValue(std::string("e")));
-  EXPECT_EQ(model_.GetValue("single_value_${j}[${i}]"),
-            SimpleValue(std::string("e")));
-
-  // Overwrite placeholder.
-  model_.AddIdentifierPlaceholders({{"i", "2"}});
-  EXPECT_EQ(model_.GetValue("multi_value[${i}]"),
-            SimpleValue(std::string("c")));
-  EXPECT_EQ(model_.GetValue("single_value_${i}"),
-            SimpleValue(std::string("f")));
-  EXPECT_EQ(model_.GetValue("single_value_${j}[${i}]"), base::nullopt);
-  // Remove placeholder (the value does not matter, it's just about the key).
-  model_.RemoveIdentifierPlaceholders({{"i", "123"}});
-  EXPECT_EQ(model_.GetValue("multi_value[${i}]"), base::nullopt);
-  EXPECT_EQ(model_.GetValue("single_value_${i}"), base::nullopt);
-  EXPECT_EQ(model_.GetValue("single_value_${j}"),
-            SimpleValue(std::string("e")));
-}
-
-TEST_F(UserModelTest, SetValueWithPlaceholders) {
-  ValueProto value;
-  value.mutable_strings()->add_values("a");
-  value.mutable_strings()->add_values("b");
-  value.mutable_strings()->add_values("c");
-  model_.SetValue("value_${i}", value);
-  EXPECT_EQ(model_.GetValue("value_${i}"), base::nullopt);
-
-  model_.AddIdentifierPlaceholders({{"i", "0"}});
-  model_.SetValue("value_${i}", value);
-  EXPECT_EQ(model_.GetValue("value_0"), value);
-  EXPECT_EQ(model_.GetValue("value_${i}"), value);
-
-  model_.RemoveIdentifierPlaceholders({{"i", "0"}});
-  EXPECT_EQ(model_.GetValue("value_0"), value);
-  EXPECT_EQ(model_.GetValue("value_${i}"), base::nullopt);
-
-  model_.AddIdentifierPlaceholders({{"i", "0"}});
-  model_.AddIdentifierPlaceholders({{"j", "1"}});
-  model_.SetValue("value_${i}_${j}", value);
-  EXPECT_EQ(model_.GetValue("value_0_1"), value);
-  EXPECT_EQ(model_.GetValue("value_${i}_${j}"), value);
-
-  model_.RemoveIdentifierPlaceholders({{"j", "1"}});
-  EXPECT_EQ(model_.GetValue("value_${i}_${j}"), base::nullopt);
-  model_.SetValue("value_${i}", value);
-  EXPECT_EQ(model_.GetValue("value_${i}"), value);
-}
-
 }  // namespace autofill_assistant
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/PromoDialogRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/PromoDialogRenderTest.java
index 39d5e52..8fed184d 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/PromoDialogRenderTest.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/PromoDialogRenderTest.java
@@ -42,7 +42,7 @@
             new NightModeTestUtils.NightModeParams().getParameters();
 
     @Rule
-    public RenderTestRule mRenderTestRule = new RenderTestRule();
+    public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
 
     private static final String LONG_STRING = "A very very very very very very very very very"
             + "very very very very long string";
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonRenderTest.java
index 54a2c38..828ef310 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonRenderTest.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RadioButtonRenderTest.java
@@ -42,7 +42,7 @@
             new NightModeTestUtils.NightModeParams().getParameters();
 
     @Rule
-    public RenderTestRule mRenderTestRule = new RenderTestRule();
+    public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
 
     private RadioButtonWithDescriptionLayout mLayout;
 
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/listmenu/ListMenuRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/listmenu/ListMenuRenderTest.java
index ea9367e..c9a0cf2b 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/listmenu/ListMenuRenderTest.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/listmenu/ListMenuRenderTest.java
@@ -44,7 +44,7 @@
             new NightModeTestUtils.NightModeParams().getParameters();
 
     @Rule
-    public RenderTestRule mRenderTestRule = new RenderTestRule();
+    public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
 
     private View mView;
 
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardViewRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardViewRenderTest.java
index 857f5cd0..5b8e4c3d 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardViewRenderTest.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/promo/PromoCardViewRenderTest.java
@@ -48,7 +48,7 @@
             new NightModeTestUtils.NightModeParams().getParameters();
 
     @Rule
-    public RenderTestRule mRenderTestRule = new RenderTestRule();
+    public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
 
     public PromoCardViewRenderTest(boolean nightModeEnabled) {
         NightModeTestUtils.setUpNightModeForDummyUiActivity(nightModeEnabled);
diff --git a/components/content_settings/core/browser/content_settings_registry_unittest.cc b/components/content_settings/core/browser/content_settings_registry_unittest.cc
index 063dcb2..1d975a4 100644
--- a/components/content_settings/core/browser/content_settings_registry_unittest.cc
+++ b/components/content_settings/core/browser/content_settings_registry_unittest.cc
@@ -15,13 +15,20 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_registry.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+// Cannot use an anonymous namespace because WebsiteSettingsRegistry's
+// constructor and destructor are private.
 namespace content_settings {
 
+using ::testing::Contains;
+using ::testing::ElementsAre;
+
 class ContentSettingsRegistryTest : public testing::Test {
  protected:
   ContentSettingsRegistryTest() : registry_(&website_settings_registry_) {}
+
   ContentSettingsRegistry* registry() { return &registry_; }
   WebsiteSettingsRegistry* website_settings_registry() {
     return &website_settings_registry_;
@@ -61,11 +68,7 @@
       registry()->Get(ContentSettingsType::COOKIES);
   ASSERT_TRUE(info);
 
-  // Check that the whitelisted types are correct.
-  std::vector<std::string> expected_whitelist;
-  expected_whitelist.push_back("chrome");
-  expected_whitelist.push_back("devtools");
-  EXPECT_EQ(expected_whitelist, info->whitelisted_schemes());
+  EXPECT_THAT(info->whitelisted_schemes(), ElementsAre("chrome", "devtools"));
 
   // Check the other properties are populated correctly.
   EXPECT_TRUE(info->IsSettingValid(CONTENT_SETTING_SESSION_ONLY));
@@ -129,7 +132,7 @@
   // These settings are safe to inherit in incognito mode because they only
   // disable features like popup blocking, download blocking or ad blocking.
   // They do not allow access to user data.
-  const ContentSettingsType whitelist[] = {
+  const ContentSettingsType safe_types[] = {
       ContentSettingsType::PLUGINS,              //
       ContentSettingsType::POPUPS,               //
       ContentSettingsType::AUTOMATIC_DOWNLOADS,  //
@@ -143,6 +146,7 @@
     SCOPED_TRACE("Content setting: " + info->website_settings_info()->name());
     // TODO(crbug.com/781756): Check IsSettingValid() because "protocol-handler"
     // and "mixed-script" don't have a proper initial default value.
+
     if (info->IsSettingValid(CONTENT_SETTING_ALLOW) &&
         info->GetInitialDefaultSetting() == CONTENT_SETTING_ALLOW) {
       // ALLOW-by-default settings are not affected by incognito_behavior, so
@@ -151,10 +155,11 @@
                 ContentSettingsInfo::INHERIT_IN_INCOGNITO);
       continue;
     }
+
     if (info->incognito_behavior() ==
-            ContentSettingsInfo::INHERIT_IN_INCOGNITO &&
-        !base::Contains(whitelist, info->website_settings_info()->type()))
-      FAIL() << "Content setting not whitelisted.";
+        ContentSettingsInfo::INHERIT_IN_INCOGNITO) {
+      EXPECT_THAT(safe_types, Contains(info->website_settings_info()->type()));
+    }
   }
 }
 
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java
index f5d2b05..30a3a8e 100644
--- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java
+++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java
@@ -43,7 +43,7 @@
             new NightModeTestUtils.NightModeParams().getParameters();
 
     @Rule
-    public RenderTestRule mRenderTestRule = new RenderTestRule();
+    public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
 
     private View mView;
 
diff --git a/components/enterprise/BUILD.gn b/components/enterprise/BUILD.gn
index 82c79cbb..65912ac 100644
--- a/components/enterprise/BUILD.gn
+++ b/components/enterprise/BUILD.gn
@@ -8,6 +8,8 @@
     "browser/controller/browser_dm_token_storage.h",
     "browser/controller/chrome_browser_cloud_management_helper.cc",
     "browser/controller/chrome_browser_cloud_management_helper.h",
+    "browser/reporting/browser_report_generator.cc",
+    "browser/reporting/browser_report_generator.h",
     "browser/reporting/policy_info.cc",
     "browser/reporting/policy_info.h",
     "browser/reporting/report_request_definition.h",
@@ -22,6 +24,7 @@
     "//components/policy/proto",
     "//components/prefs",
     "//components/strings",
+    "//components/version_info",
     "//net",
     "//services/network/public/cpp",
   ]
diff --git a/components/enterprise/DEPS b/components/enterprise/DEPS
index 71fa6f2..f3b43f4 100644
--- a/components/enterprise/DEPS
+++ b/components/enterprise/DEPS
@@ -3,6 +3,7 @@
   "+components/prefs",
   "+components/safe_browsing/core/proto",
   "+components/strings/grit",
+  "+components/version_info",
   "+net",
   "+services/network/public",
 ]
diff --git a/components/enterprise/browser/reporting/browser_report_generator.cc b/components/enterprise/browser/reporting/browser_report_generator.cc
new file mode 100644
index 0000000..0f52d62
--- /dev/null
+++ b/components/enterprise/browser/reporting/browser_report_generator.cc
@@ -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.
+
+#include "components/enterprise/browser/reporting/browser_report_generator.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/version.h"
+#include "build/build_config.h"
+#include "components/policy/core/common/cloud/cloud_policy_util.h"
+#include "components/version_info/version_info.h"
+
+namespace em = ::enterprise_management;
+
+namespace enterprise_reporting {
+
+BrowserReportGenerator::BrowserReportGenerator(
+    std::unique_ptr<BrowserReportGenerator::Delegate> delegate)
+    : delegate_(std::move(delegate)) {}
+
+BrowserReportGenerator::~BrowserReportGenerator() = default;
+
+void BrowserReportGenerator::Generate(ReportCallback callback) {
+  auto report = std::make_unique<em::BrowserReport>();
+  GenerateBasicInfo(report.get());
+  delegate_->GenerateProfileInfo(report.get());
+
+  // std::move is required here because the function completes the report
+  // asynchronously.
+  delegate_->GeneratePluginsIfNeeded(std::move(callback), std::move(report));
+}
+
+void BrowserReportGenerator::GenerateBasicInfo(em::BrowserReport* report) {
+#if !defined(OS_CHROMEOS)
+  report->set_browser_version(version_info::GetVersionNumber());
+  report->set_channel(policy::ConvertToProtoChannel(delegate_->GetChannel()));
+  delegate_->GenerateBuildStateInfo(report);
+#endif
+
+  report->set_executable_path(delegate_->GetExecutablePath());
+}
+
+}  // namespace enterprise_reporting
diff --git a/components/enterprise/browser/reporting/browser_report_generator.h b/components/enterprise/browser/reporting/browser_report_generator.h
new file mode 100644
index 0000000..babab3a
--- /dev/null
+++ b/components/enterprise/browser/reporting/browser_report_generator.h
@@ -0,0 +1,58 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ENTERPRISE_BROWSER_REPORTING_BROWSER_REPORT_GENERATOR_H_
+#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_BROWSER_REPORT_GENERATOR_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "components/policy/proto/device_management_backend.pb.h"
+#include "components/version_info/channel.h"
+
+namespace enterprise_reporting {
+
+// A report generator that collects Browser related information.
+class BrowserReportGenerator {
+ public:
+  using ReportCallback = base::OnceCallback<void(
+      std::unique_ptr<enterprise_management::BrowserReport>)>;
+
+  class Delegate {
+   public:
+    virtual ~Delegate() = default;
+
+    virtual std::string GetExecutablePath() = 0;
+    virtual version_info::Channel GetChannel() = 0;
+    virtual void GenerateBuildStateInfo(
+        enterprise_management::BrowserReport* report) = 0;
+    virtual void GenerateProfileInfo(
+        enterprise_management::BrowserReport* report) = 0;
+    virtual void GeneratePluginsIfNeeded(
+        ReportCallback callback,
+        std::unique_ptr<enterprise_management::BrowserReport> report) = 0;
+  };
+
+  explicit BrowserReportGenerator(std::unique_ptr<Delegate> delegate);
+  ~BrowserReportGenerator();
+
+  // Generates a BrowserReport with the following fields:
+  // - browser_version, channel, executable_path
+  // - user profiles: id, name, is_full_report (always be false).
+  // - plugins: name, version, filename, description.
+  void Generate(ReportCallback callback);
+
+ private:
+  std::unique_ptr<Delegate> delegate_;
+
+  // Generates browser_version, channel, executable_path info in the given
+  // report instance.
+  void GenerateBasicInfo(enterprise_management::BrowserReport* report);
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserReportGenerator);
+};
+
+}  // namespace enterprise_reporting
+
+#endif  // COMPONENTS_ENTERPRISE_BROWSER_REPORTING_BROWSER_REPORT_GENERATOR_H_
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
index 741a562..69f43cc 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
@@ -70,8 +70,7 @@
     private static final String TAG = "UrlHandler";
 
     // Enables debug logging on a local build.
-    // TODO(jochen): switch this back to false.
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static final String WTAI_URL_PREFIX = "wtai://wp/";
     private static final String WTAI_MC_URL_PREFIX = "wtai://wp/mc;";
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java
index 2252d8f..3bdfec4 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/RedirectHandler.java
@@ -13,7 +13,6 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.IntentUtils;
-import org.chromium.base.Log;
 import org.chromium.base.PackageManagerUtils;
 import org.chromium.ui.base.PageTransition;
 
@@ -24,7 +23,6 @@
  * This class contains the logic to determine effective navigation/redirect.
  */
 public class RedirectHandler {
-    private static final String TAG = "RedirectHandler";
     /**
      * An invalid entry index.
      */
@@ -150,30 +148,15 @@
         boolean isNewLoadingStartedByUser = false;
         boolean isFromIntent = pageTransitionCore == PageTransition.LINK
                 && (pageTransType & PageTransition.FROM_API) != 0;
-
-        Log.i(TAG,
-                "updateNewUrlLoading called (pageTransType: " + pageTransType
-                        + ", isRedirect: " + isRedirect + ", hasUserGesture: " + hasUserGesture
-                        + ", lastUserInteractionTime: " + lastUserInteractionTime
-                        + ", lastCommittedEntryIndex: " + lastCommittedEntryIndex + ")");
-        Log.i(TAG,
-                " - prevNewUrlLoadingTime: " + prevNewUrlLoadingTime
-                        + ", mLastNewUrlLoadingTime: " + mLastNewUrlLoadingTime);
-        Log.i(TAG,
-                " - pageTransitionCore: " + pageTransitionCore + ", isFromIntent: " + isFromIntent);
         if (!isRedirect) {
             if ((pageTransType & PageTransition.FORWARD_BACK) != 0) {
                 isNewLoadingStartedByUser = true;
-                Log.i(TAG, "- isNewLoadingStartedByUser: forward/back navigation");
             } else if (pageTransitionCore != PageTransition.LINK
                     && pageTransitionCore != PageTransition.FORM_SUBMIT) {
                 isNewLoadingStartedByUser = true;
-                Log.i(TAG, "- isNewLoadingStartedByUser: not a link or form submission");
             } else if (prevNewUrlLoadingTime == INVALID_TIME || isFromIntent
                     || lastUserInteractionTime > prevNewUrlLoadingTime) {
                 isNewLoadingStartedByUser = true;
-                Log.i(TAG,
-                        "- isNewLoadingStartedByUser: first load, from intent or new user gesture");
             }
         }
 
@@ -181,22 +164,17 @@
             // Updates mInitialNavigationType for a new loading started by a user's gesture.
             if (isFromIntent && mInitialIntent != null) {
                 mInitialNavigationType = NAVIGATION_TYPE_FROM_INTENT;
-                Log.i(TAG, " - mInitialNavigationType: FROM_INTENT");
             } else {
                 clearIntentHistory();
                 if (pageTransitionCore == PageTransition.TYPED) {
                     mInitialNavigationType = NAVIGATION_TYPE_FROM_USER_TYPING;
-                    Log.i(TAG, " - mInitialNavigationType: USER_TYPING");
                 } else if (pageTransitionCore == PageTransition.RELOAD
                         || (pageTransType & PageTransition.FORWARD_BACK) != 0) {
                     mInitialNavigationType = NAVIGATION_TYPE_FROM_RELOAD;
-                    Log.i(TAG, " - mInitialNavigationType: RELOAD");
                 } else if (pageTransitionCore == PageTransition.LINK && !hasUserGesture) {
                     mInitialNavigationType = NAVIGATION_TYPE_FROM_LINK_WITHOUT_USER_GESTURE;
-                    Log.i(TAG, " - mInitialNavigationType: LINK_WITHOUT_USER_GESTURE");
                 } else {
                     mInitialNavigationType = NAVIGATION_TYPE_OTHER;
-                    Log.i(TAG, " - mInitialNavigationType: OTHER");
                 }
             }
             mIsOnEffectiveRedirectChain = false;
@@ -205,9 +183,6 @@
         } else if (mInitialNavigationType != NAVIGATION_TYPE_NONE) {
             // Redirect chain starts from the second url loading.
             mIsOnEffectiveRedirectChain = true;
-            Log.i(TAG, " - mIsOnEffectiveRedirectChain: true");
-        } else {
-            Log.i(TAG, " - no updates");
         }
     }
 
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java
index 7606cb5..cc8a438 100644
--- a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java
+++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentAggregatorBridge.java
@@ -77,6 +77,17 @@
     }
 
     @Override
+    public void changeSchedule(final ContentId id, final OfflineItemSchedule schedule) {
+        if (mNativeOfflineContentAggregatorBridge == 0) return;
+        boolean onlyOnWifi = (schedule == null) ? false : schedule.onlyOnWifi;
+        long startTimeMs = (schedule == null) ? -1 : schedule.startTimeMs;
+
+        OfflineContentAggregatorBridgeJni.get().changeSchedule(
+                mNativeOfflineContentAggregatorBridge, OfflineContentAggregatorBridge.this,
+                id.namespace, id.id, onlyOnWifi, startTimeMs);
+    }
+
+    @Override
     public void getItemById(ContentId id, Callback<OfflineItem> callback) {
         if (mNativeOfflineContentAggregatorBridge == 0) return;
         OfflineContentAggregatorBridgeJni.get().getItemById(mNativeOfflineContentAggregatorBridge,
@@ -209,5 +220,8 @@
         void renameItem(long nativeOfflineContentAggregatorBridge,
                 OfflineContentAggregatorBridge caller, String nameSpace, String id, String name,
                 Callback</*RenameResult*/ Integer> callback);
+        void changeSchedule(long nativeOfflineContentAggregatorBridge,
+                OfflineContentAggregatorBridge caller, String nameSpace, String id,
+                boolean onlyOnWifi, long startTimeMs);
     }
 }
diff --git a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java
index 1d33c46..6a2eb26a 100644
--- a/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java
+++ b/components/offline_items_collection/core/android/java/src/org/chromium/components/offline_items_collection/OfflineContentProvider.java
@@ -43,6 +43,9 @@
     /** See OfflineContentProvider::ResumeDownload(...). */
     void resumeDownload(ContentId id, boolean hasUserGesture);
 
+    /** See OfflineContentProvider::ChangeSchedule(...). */
+    void changeSchedule(final ContentId id, final OfflineItemSchedule schedule);
+
     /** See OfflineContentProvider::GetItemById(...). */
     void getItemById(ContentId id, Callback<OfflineItem> callback);
 
diff --git a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
index 124d8a4..45df4c4d 100644
--- a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
+++ b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.cc
@@ -248,6 +248,26 @@
                         std::move(callback));
 }
 
+void OfflineContentAggregatorBridge::ChangeSchedule(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jobj,
+    const base::android::JavaParamRef<jstring>& j_namespace,
+    const base::android::JavaParamRef<jstring>& j_id,
+    jboolean j_only_on_wifi,
+    jlong j_start_time_ms) {
+  base::Optional<OfflineItemSchedule> schedule;
+  if (j_only_on_wifi)
+    schedule = base::make_optional<OfflineItemSchedule>(true, base::nullopt);
+  else if (j_start_time_ms > 0) {
+    schedule = base::make_optional<OfflineItemSchedule>(
+        false, base::Time::FromJavaTime(j_start_time_ms));
+  }
+
+  provider_->ChangeSchedule(JNI_OfflineContentAggregatorBridge_CreateContentId(
+                                env, j_namespace, j_id),
+                            std::move(schedule));
+}
+
 void OfflineContentAggregatorBridge::OnItemsAdded(
     const OfflineContentProvider::OfflineItemList& items) {
   if (java_ref_.is_null())
diff --git a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
index ac80a6a..ab61885c4 100644
--- a/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
+++ b/components/offline_items_collection/core/android/offline_content_aggregator_bridge.h
@@ -87,6 +87,13 @@
                   const base::android::JavaParamRef<jstring>& j_name,
                   const base::android::JavaParamRef<jobject>& j_callback);
 
+  void ChangeSchedule(JNIEnv* env,
+                      const base::android::JavaParamRef<jobject>& jobj,
+                      const base::android::JavaParamRef<jstring>& j_namespace,
+                      const base::android::JavaParamRef<jstring>& j_id,
+                      jboolean j_only_on_wifi,
+                      jlong j_start_time_ms);
+
  private:
   OfflineContentAggregatorBridge(OfflineContentAggregator* aggregator);
 
diff --git a/components/offline_items_collection/core/offline_content_aggregator.cc b/components/offline_items_collection/core/offline_content_aggregator.cc
index 7a9ae71..8c099bf 100644
--- a/components/offline_items_collection/core/offline_content_aggregator.cc
+++ b/components/offline_items_collection/core/offline_content_aggregator.cc
@@ -234,6 +234,16 @@
   it->second->RenameItem(id, name, std::move(callback));
 }
 
+void OfflineContentAggregator::ChangeSchedule(
+    const ContentId& id,
+    base::Optional<OfflineItemSchedule> schedule) {
+  auto it = providers_.find(id.name_space);
+  if (it == providers_.end())
+    return;
+
+  it->second->ChangeSchedule(id, std::move(schedule));
+}
+
 void OfflineContentAggregator::AddObserver(
     OfflineContentProvider::Observer* observer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/offline_items_collection/core/offline_content_aggregator.h b/components/offline_items_collection/core/offline_content_aggregator.h
index cbf7d1f..35bdd0da 100644
--- a/components/offline_items_collection/core/offline_content_aggregator.h
+++ b/components/offline_items_collection/core/offline_content_aggregator.h
@@ -82,6 +82,8 @@
   void RenameItem(const ContentId& id,
                   const std::string& name,
                   RenameCallback callback) override;
+  void ChangeSchedule(const ContentId& id,
+                      base::Optional<OfflineItemSchedule> schedule) override;
   void AddObserver(OfflineContentProvider::Observer* observer) override;
   void RemoveObserver(OfflineContentProvider::Observer* observer) override;
 
diff --git a/components/offline_items_collection/core/offline_content_provider.h b/components/offline_items_collection/core/offline_content_provider.h
index 06f4cd0d..81c0fca 100644
--- a/components/offline_items_collection/core/offline_content_provider.h
+++ b/components/offline_items_collection/core/offline_content_provider.h
@@ -21,6 +21,7 @@
 
 struct ContentId;
 struct OfflineItem;
+struct OfflineItemSchedule;
 struct OfflineItemShareInfo;
 struct OfflineItemVisuals;
 
@@ -154,6 +155,10 @@
                           const std::string& name,
                           RenameCallback callback) = 0;
 
+  // Called to change when to start the OfflineItem represented by |id|.
+  virtual void ChangeSchedule(const ContentId& id,
+                              base::Optional<OfflineItemSchedule> schedule) = 0;
+
   // Adds an observer that should be notified of OfflineItem list modifications.
   virtual void AddObserver(Observer* observer) = 0;
 
diff --git a/components/offline_items_collection/core/test_support/mock_offline_content_provider.h b/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
index 748ce984..682cc66 100644
--- a/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
+++ b/components/offline_items_collection/core/test_support/mock_offline_content_provider.h
@@ -60,6 +60,10 @@
   void RemoveObserver(Observer* observer) override;
   MOCK_METHOD3(RenameItem,
                void(const ContentId&, const std::string&, RenameCallback));
+  MOCK_METHOD(void,
+              ChangeSchedule,
+              (const ContentId&, base::Optional<OfflineItemSchedule>),
+              (override));
 
  private:
   base::ObserverList<Observer>::Unchecked observers_;
diff --git a/components/offline_items_collection/core/throttled_offline_content_provider.cc b/components/offline_items_collection/core/throttled_offline_content_provider.cc
index 1c11171..25c0dbb 100644
--- a/components/offline_items_collection/core/throttled_offline_content_provider.cc
+++ b/components/offline_items_collection/core/throttled_offline_content_provider.cc
@@ -113,6 +113,12 @@
   wrapped_provider_->RenameItem(id, name, std::move(callback));
 }
 
+void ThrottledOfflineContentProvider::ChangeSchedule(
+    const ContentId& id,
+    base::Optional<OfflineItemSchedule> schedule) {
+  wrapped_provider_->ChangeSchedule(id, std::move(schedule));
+}
+
 void ThrottledOfflineContentProvider::AddObserver(
     OfflineContentProvider::Observer* observer) {
   DCHECK(observer);
diff --git a/components/offline_items_collection/core/throttled_offline_content_provider.h b/components/offline_items_collection/core/throttled_offline_content_provider.h
index cde9afc..76ee06b 100644
--- a/components/offline_items_collection/core/throttled_offline_content_provider.h
+++ b/components/offline_items_collection/core/throttled_offline_content_provider.h
@@ -53,6 +53,8 @@
   void RenameItem(const ContentId& id,
                   const std::string& name,
                   RenameCallback callback) override;
+  void ChangeSchedule(const ContentId& id,
+                      base::Optional<OfflineItemSchedule> schedule) override;
   void AddObserver(OfflineContentProvider::Observer* observer) override;
   void RemoveObserver(OfflineContentProvider::Observer* observer) override;
 
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.cc b/components/offline_pages/core/downloads/download_ui_adapter.cc
index b5c12bef..b145597 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter.cc
+++ b/components/offline_pages/core/downloads/download_ui_adapter.cc
@@ -261,6 +261,12 @@
   NOTREACHED();
 }
 
+void DownloadUIAdapter::ChangeSchedule(
+    const ContentId& id,
+    base::Optional<OfflineItemSchedule> schedule) {
+  NOTREACHED();
+}
+
 void DownloadUIAdapter::OnPageGetForVisuals(
     const ContentId& id,
     GetVisualsOptions options,
diff --git a/components/offline_pages/core/downloads/download_ui_adapter.h b/components/offline_pages/core/downloads/download_ui_adapter.h
index 74fad8b1..377b722 100644
--- a/components/offline_pages/core/downloads/download_ui_adapter.h
+++ b/components/offline_pages/core/downloads/download_ui_adapter.h
@@ -27,8 +27,9 @@
 using OfflineContentAggregator =
     offline_items_collection::OfflineContentAggregator;
 using OfflineItem = offline_items_collection::OfflineItem;
-using UpdateDelta = offline_items_collection::UpdateDelta;
+using OfflineItemSchedule = offline_items_collection::OfflineItemSchedule;
 using OfflineItemShareInfo = offline_items_collection::OfflineItemShareInfo;
+using UpdateDelta = offline_items_collection::UpdateDelta;
 
 namespace offline_pages {
 class VisualsDecoder;
@@ -108,6 +109,8 @@
   void RenameItem(const ContentId& id,
                   const std::string& name,
                   RenameCallback callback) override;
+  void ChangeSchedule(const ContentId& id,
+                      base::Optional<OfflineItemSchedule> schedule) override;
   void AddObserver(OfflineContentProvider::Observer* observer) override;
   void RemoveObserver(OfflineContentProvider::Observer* observer) override;
 
diff --git a/components/optimization_guide/BUILD.gn b/components/optimization_guide/BUILD.gn
index 541f804..57ca1f40 100644
--- a/components/optimization_guide/BUILD.gn
+++ b/components/optimization_guide/BUILD.gn
@@ -14,6 +14,8 @@
     "bloom_filter.h",
     "command_line_top_host_provider.cc",
     "command_line_top_host_provider.h",
+    "decision_tree_prediction_model.cc",
+    "decision_tree_prediction_model.h",
     "hint_cache.cc",
     "hint_cache.h",
     "hints_component_info.h",
@@ -46,6 +48,8 @@
     "optimization_guide_switches.h",
     "optimization_metadata.cc",
     "optimization_metadata.h",
+    "prediction_model.cc",
+    "prediction_model.h",
     "store_update_data.cc",
     "store_update_data.h",
     "top_host_provider.h",
@@ -96,6 +100,7 @@
   sources = [
     "bloom_filter_unittest.cc",
     "command_line_top_host_provider_unittest.cc",
+    "decision_tree_prediction_model_unittest.cc",
     "hint_cache_unittest.cc",
     "hints_component_util_unittest.cc",
     "hints_fetcher_unittest.cc",
@@ -105,6 +110,7 @@
     "optimization_guide_service_unittest.cc",
     "optimization_guide_store_unittest.cc",
     "optimization_guide_switches_unittest.cc",
+    "prediction_model_unittest.cc",
     "store_update_data_unittest.cc",
     "url_pattern_with_wildcards_unittest.cc",
   ]
diff --git a/components/optimization_guide/decision_tree_prediction_model.cc b/components/optimization_guide/decision_tree_prediction_model.cc
new file mode 100644
index 0000000..4b1324e
--- /dev/null
+++ b/components/optimization_guide/decision_tree_prediction_model.cc
@@ -0,0 +1,242 @@
+// Copyright 2020 The Chromium 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/optimization_guide/decision_tree_prediction_model.h"
+
+#include <utility>
+
+namespace optimization_guide {
+
+DecisionTreePredictionModel::DecisionTreePredictionModel(
+    std::unique_ptr<optimization_guide::proto::PredictionModel>
+        prediction_model)
+    : PredictionModel(std::move(prediction_model)) {}
+
+DecisionTreePredictionModel::~DecisionTreePredictionModel() = default;
+
+bool DecisionTreePredictionModel::ValidatePredictionModel() const {
+  // Only the top-level ensemble or decision tree must have a threshold. Any
+  // submodels of an ensemble will have model weights but no threshold.
+  if (!model_->has_threshold())
+    return false;
+  return ValidateModel(*model_.get());
+}
+
+bool DecisionTreePredictionModel::ValidateModel(
+    const proto::Model& model) const {
+  if (model.has_ensemble()) {
+    return ValidateEnsembleModel(model.ensemble());
+  }
+  if (model.has_decision_tree()) {
+    return ValidateDecisionTree(model.decision_tree());
+  }
+  return false;
+}
+
+bool DecisionTreePredictionModel::ValidateEnsembleModel(
+    const proto::Ensemble& ensemble) const {
+  if (ensemble.members_size() == 0)
+    return false;
+
+  for (const auto& member : ensemble.members()) {
+    if (!ValidateModel(member.submodel())) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool DecisionTreePredictionModel::ValidateDecisionTree(
+    const proto::DecisionTree& tree) const {
+  if (tree.nodes_size() == 0)
+    return false;
+  return ValidateTreeNode(tree, tree.nodes(0), 0);
+}
+
+bool DecisionTreePredictionModel::ValidateLeaf(const proto::Leaf& leaf) const {
+  return leaf.has_vector() && leaf.vector().value_size() == 1 &&
+         leaf.vector().value(0).has_double_value();
+}
+
+bool DecisionTreePredictionModel::ValidateInequalityTest(
+    const proto::InequalityTest& inequality_test) const {
+  if (!inequality_test.has_threshold())
+    return false;
+  if (!inequality_test.threshold().has_float_value())
+    return false;
+  if (!inequality_test.has_feature_id())
+    return false;
+  if (!inequality_test.feature_id().has_id())
+    return false;
+  if (!inequality_test.has_type())
+    return false;
+  return true;
+}
+
+bool DecisionTreePredictionModel::ValidateTreeNode(
+    const proto::DecisionTree& tree,
+    const proto::TreeNode& node,
+    const int& node_index) const {
+  if (node.has_leaf())
+    return ValidateLeaf(node.leaf());
+
+  if (!node.has_binary_node())
+    return false;
+
+  proto::BinaryNode binary_node = node.binary_node();
+  if (!binary_node.has_inequality_left_child_test())
+    return false;
+
+  if (!ValidateInequalityTest(binary_node.inequality_left_child_test()))
+    return false;
+
+  if (!binary_node.left_child_id().has_value())
+    return false;
+  if (!binary_node.right_child_id().has_value())
+    return false;
+
+  if (binary_node.left_child_id().value() >= tree.nodes_size())
+    return false;
+  if (binary_node.right_child_id().value() >= tree.nodes_size())
+    return false;
+
+  // Assure that no parent has an child index less than itself in order to
+  // prevent loops.
+  if (node_index >= binary_node.left_child_id().value())
+    return false;
+  if (node_index >= binary_node.right_child_id().value())
+    return false;
+
+  if (!ValidateTreeNode(tree, tree.nodes(binary_node.left_child_id().value()),
+                        binary_node.left_child_id().value())) {
+    return false;
+  }
+  if (!ValidateTreeNode(tree, tree.nodes(binary_node.right_child_id().value()),
+                        binary_node.right_child_id().value())) {
+    return false;
+  }
+  return true;
+}
+
+optimization_guide::OptimizationTargetDecision
+DecisionTreePredictionModel::Predict(
+    const base::flat_map<std::string, float>& model_features,
+    double* prediction_score) {
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  *prediction_score = 0.0;
+  // TODO(mcrouse): Add metrics to record if the model evaluation fails.
+  if (!EvaluateModel(*model_.get(), model_features, prediction_score))
+    return optimization_guide::OptimizationTargetDecision::kUnknown;
+  if (*prediction_score > model_->threshold().value())
+    return optimization_guide::OptimizationTargetDecision::kPageLoadMatches;
+  return optimization_guide::OptimizationTargetDecision::kPageLoadDoesNotMatch;
+}
+
+bool DecisionTreePredictionModel::TraverseTree(
+    const proto::DecisionTree& tree,
+    const proto::TreeNode& node,
+    const base::flat_map<std::string, float>& model_features,
+    double* result) {
+  if (node.has_leaf()) {
+    *result = node.leaf().vector().value(0).double_value();
+    return true;
+  }
+
+  proto::BinaryNode binary_node = node.binary_node();
+  float threshold =
+      binary_node.inequality_left_child_test().threshold().float_value();
+  std::string feature_name =
+      binary_node.inequality_left_child_test().feature_id().id().value();
+  auto it = model_features.find(feature_name);
+  if (it == model_features.end())
+    return false;
+  switch (binary_node.inequality_left_child_test().type()) {
+    case proto::InequalityTest::LESS_OR_EQUAL:
+      if (it->second <= threshold)
+        return TraverseTree(tree,
+                            tree.nodes(binary_node.left_child_id().value()),
+                            model_features, result);
+      return TraverseTree(tree,
+                          tree.nodes(binary_node.right_child_id().value()),
+                          model_features, result);
+    case proto::InequalityTest::LESS_THAN:
+      if (it->second < threshold)
+        return TraverseTree(tree,
+                            tree.nodes(binary_node.left_child_id().value()),
+                            model_features, result);
+      return TraverseTree(tree,
+                          tree.nodes(binary_node.right_child_id().value()),
+                          model_features, result);
+    case proto::InequalityTest::GREATER_OR_EQUAL:
+      if (it->second >= threshold)
+        return TraverseTree(tree,
+                            tree.nodes(binary_node.left_child_id().value()),
+                            model_features, result);
+      return TraverseTree(tree,
+                          tree.nodes(binary_node.right_child_id().value()),
+                          model_features, result);
+    case proto::InequalityTest::GREATER_THAN:
+      if (it->second > threshold)
+        return TraverseTree(tree,
+                            tree.nodes(binary_node.left_child_id().value()),
+                            model_features, result);
+      return TraverseTree(tree,
+                          tree.nodes(binary_node.right_child_id().value()),
+                          model_features, result);
+    default:
+      return false;
+  }
+  return false;
+}
+
+bool DecisionTreePredictionModel::EvaluateDecisionTree(
+    const proto::DecisionTree& tree,
+    const base::flat_map<std::string, float>& model_features,
+    double* result) {
+  if (TraverseTree(tree, tree.nodes(0), model_features, result)) {
+    *result *= tree.weight();
+    return true;
+  }
+  return false;
+}
+
+bool DecisionTreePredictionModel::EvaluateEnsembleModel(
+    const proto::Ensemble& ensemble,
+    const base::flat_map<std::string, float>& model_features,
+    double* result) {
+  if (ensemble.members_size() == 0)
+    return false;
+
+  double score = 0.0;
+  for (const auto& member : ensemble.members()) {
+    if (!EvaluateModel(member.submodel(), model_features, &score)) {
+      *result = 0.0;
+      return false;
+    }
+
+    *result += score;
+  }
+  *result = *result / ensemble.members_size();
+  return true;
+}
+
+bool DecisionTreePredictionModel::EvaluateModel(
+    const proto::Model& model,
+    const base::flat_map<std::string, float>& model_features,
+    double* result) {
+  DCHECK(result);
+  // Clear the result value.
+  *result = 0.0;
+
+  if (model.has_ensemble()) {
+    return EvaluateEnsembleModel(model.ensemble(), model_features, result);
+  }
+  if (model.has_decision_tree()) {
+    return EvaluateDecisionTree(model.decision_tree(), model_features, result);
+  }
+  return false;
+}
+
+}  // namespace optimization_guide
diff --git a/components/optimization_guide/decision_tree_prediction_model.h b/components/optimization_guide/decision_tree_prediction_model.h
new file mode 100644
index 0000000..c3856304
--- /dev/null
+++ b/components/optimization_guide/decision_tree_prediction_model.h
@@ -0,0 +1,101 @@
+// Copyright 2020 The Chromium 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_OPTIMIZATION_GUIDE_DECISION_TREE_PREDICTION_MODEL_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_DECISION_TREE_PREDICTION_MODEL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
+#include "components/optimization_guide/prediction_model.h"
+#include "components/optimization_guide/proto/models.pb.h"
+
+namespace optimization_guide {
+
+// A concrete PredictionModel capable of evaluating the decision tree model type
+// supported by the optimization guide.
+class DecisionTreePredictionModel : public PredictionModel {
+ public:
+  explicit DecisionTreePredictionModel(
+      std::unique_ptr<optimization_guide::proto::PredictionModel>
+          prediction_model);
+
+  ~DecisionTreePredictionModel() override;
+
+  // PredictionModel implementation:
+  optimization_guide::OptimizationTargetDecision Predict(
+      const base::flat_map<std::string, float>& model_features,
+      double* prediction_score) override;
+
+ private:
+  // Evaluates the provided model, either an ensemble or decision tree model,
+  // with the |model_features| and stores the output in |result|. Returns false
+  // if evaluation fails.
+  bool EvaluateModel(const proto::Model& model,
+                     const base::flat_map<std::string, float>& model_features,
+                     double* result);
+
+  // Evaluates the decision tree model with the |model_features| and
+  // stores the output in |result|. Returns false if the evaluation fails.
+  bool EvaluateDecisionTree(
+      const proto::DecisionTree& tree,
+      const base::flat_map<std::string, float>& model_features,
+      double* result);
+
+  // Evaluates an ensemble model with the |model_features| and
+  // stores the output in |result|. Returns false if the evaluation fails.
+  bool EvaluateEnsembleModel(
+      const proto::Ensemble& ensemble,
+      const base::flat_map<std::string, float>& model_features,
+      double* result);
+
+  // Performs a depth first traversal the  |tree| based on |model_features|
+  // and stores the value of the leaf in |result|. Returns false if the
+  // traversal or node evaluation fails.
+  bool TraverseTree(const proto::DecisionTree& tree,
+                    const proto::TreeNode& node,
+                    const base::flat_map<std::string, float>& model_features,
+                    double* result);
+
+  // PredictionModel implementation:
+  bool ValidatePredictionModel() const override;
+
+  // Validates a model or submodel of an ensemble. Returns
+  // false if the model is invalid.
+  bool ValidateModel(const proto::Model& model) const;
+
+  // Validates an ensemble model. Returns false if the ensemble
+  // if invalid.
+  bool ValidateEnsembleModel(const proto::Ensemble& ensemble) const;
+
+  // Validates a decision tree model. Returns false if the
+  // decision tree model is invalid.
+  bool ValidateDecisionTree(const proto::DecisionTree& tree) const;
+
+  // Validates a leaf. Returns false if the leaf is invalid.
+  bool ValidateLeaf(const proto::Leaf& leaf) const;
+
+  // Validates an inequality test. Returns false if the
+  // inequality test is invalid.
+  bool ValidateInequalityTest(
+      const proto::InequalityTest& inequality_test) const;
+
+  // Validates each node of a decision tree by traversing every
+  // node of the |tree|. Returns false if any part of the tree is invalid.
+  bool ValidateTreeNode(const proto::DecisionTree& tree,
+                        const proto::TreeNode& node,
+                        const int& node_index) const;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(DecisionTreePredictionModel);
+};
+
+}  // namespace optimization_guide
+
+#endif  // COMPONENTS_OPTIMIZATION_GUIDE_DECISION_TREE_PREDICTION_MODEL_H_
diff --git a/components/optimization_guide/decision_tree_prediction_model_unittest.cc b/components/optimization_guide/decision_tree_prediction_model_unittest.cc
new file mode 100644
index 0000000..67797b99f
--- /dev/null
+++ b/components/optimization_guide/decision_tree_prediction_model_unittest.cc
@@ -0,0 +1,482 @@
+// Copyright 2020 The Chromium 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 <memory>
+#include <utility>
+
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "components/optimization_guide/decision_tree_prediction_model.h"
+#include "components/optimization_guide/prediction_model.h"
+#include "components/optimization_guide/proto/models.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace optimization_guide {
+
+std::unique_ptr<proto::PredictionModel> GetValidDecisionTreePredictionModel() {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      std::make_unique<proto::PredictionModel>();
+  prediction_model->mutable_model()->mutable_threshold()->set_value(5.0);
+
+  proto::DecisionTree decision_tree_model = proto::DecisionTree();
+  decision_tree_model.set_weight(2.0);
+
+  proto::TreeNode* tree_node = decision_tree_model.add_nodes();
+  tree_node->mutable_node_id()->set_value(0);
+  tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(1);
+  tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(2);
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->mutable_feature_id()
+      ->mutable_id()
+      ->set_value("agg1");
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->mutable_threshold()
+      ->set_float_value(1.0);
+
+  tree_node = decision_tree_model.add_nodes();
+  tree_node->mutable_node_id()->set_value(1);
+  tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
+      2.);
+
+  tree_node = decision_tree_model.add_nodes();
+  tree_node->mutable_node_id()->set_value(2);
+  tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
+      4.);
+
+  *prediction_model->mutable_model()->mutable_decision_tree() =
+      decision_tree_model;
+  return prediction_model;
+}
+
+std::unique_ptr<proto::PredictionModel> GetValidEnsemblePredictionModel() {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      std::make_unique<proto::PredictionModel>();
+  prediction_model->mutable_model()->mutable_threshold()->set_value(5.0);
+  proto::Ensemble ensemble = proto::Ensemble();
+  *ensemble.add_members()->mutable_submodel() =
+      *GetValidDecisionTreePredictionModel()->mutable_model();
+
+  *ensemble.add_members()->mutable_submodel() =
+      *GetValidDecisionTreePredictionModel()->mutable_model();
+
+  *prediction_model->mutable_model()->mutable_ensemble() = ensemble;
+  return prediction_model;
+}
+
+TEST(DecisionTreePredictionModel, ValidDecisionTreeModel) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_TRUE(model);
+
+  double prediction_score;
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
+            model->Predict({{"agg1", 1.0}}, &prediction_score));
+  EXPECT_EQ(4., prediction_score);
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
+            model->Predict({{"agg1", 2.0}}, &prediction_score));
+  EXPECT_EQ(8., prediction_score);
+}
+
+TEST(DecisionTreePredictionModel, InequalityLessThan) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()
+      ->mutable_decision_tree()
+      ->mutable_nodes(0)
+      ->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->set_type(proto::InequalityTest::LESS_THAN);
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_TRUE(model);
+
+  double prediction_score;
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
+            model->Predict({{"agg1", 0.5}}, &prediction_score));
+  EXPECT_EQ(4., prediction_score);
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
+            model->Predict({{"agg1", 2.0}}, &prediction_score));
+  EXPECT_EQ(8., prediction_score);
+}
+
+TEST(DecisionTreePredictionModel, InequalityGreaterOrEqual) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()
+      ->mutable_decision_tree()
+      ->mutable_nodes(0)
+      ->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->set_type(proto::InequalityTest::GREATER_OR_EQUAL);
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_TRUE(model);
+
+  double prediction_score;
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
+            model->Predict({{"agg1", 0.5}}, &prediction_score));
+  EXPECT_EQ(8., prediction_score);
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
+            model->Predict({{"agg1", 1.0}}, &prediction_score));
+  EXPECT_EQ(4., prediction_score);
+}
+
+TEST(DecisionTreePredictionModel, InequalityGreaterThan) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()
+      ->mutable_decision_tree()
+      ->mutable_nodes(0)
+      ->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->set_type(proto::InequalityTest::GREATER_THAN);
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_TRUE(model);
+
+  double prediction_score;
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
+            model->Predict({{"agg1", 0.5}}, &prediction_score));
+  EXPECT_EQ(8., prediction_score);
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
+            model->Predict({{"agg1", 2.0}}, &prediction_score));
+  EXPECT_EQ(4., prediction_score);
+}
+
+TEST(DecisionTreePredictionModel, MissingInequalityTest) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()
+      ->mutable_decision_tree()
+      ->mutable_nodes(0)
+      ->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->Clear();
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(DecisionTreePredictionModel, NoDecisionTreeThreshold) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()->clear_threshold();
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(DecisionTreePredictionModel, EmptyTree) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()->mutable_decision_tree()->clear_nodes();
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(DecisionTreePredictionModel, ModelFeatureNotInFeatureMap) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()->mutable_decision_tree()->clear_nodes();
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(DecisionTreePredictionModel, DecisionTreeMissingLeaf) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()
+      ->mutable_decision_tree()
+      ->mutable_nodes(1)
+      ->mutable_leaf()
+      ->Clear();
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(DecisionTreePredictionModel, DecisionTreeLeftChildIndexInvalid) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()
+      ->mutable_decision_tree()
+      ->mutable_nodes(0)
+      ->mutable_binary_node()
+      ->mutable_left_child_id()
+      ->set_value(3);
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(DecisionTreePredictionModel, DecisionTreeRightChildIndexInvalid) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  prediction_model->mutable_model()
+      ->mutable_decision_tree()
+      ->mutable_nodes(0)
+      ->mutable_binary_node()
+      ->mutable_right_child_id()
+      ->set_value(3);
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(DecisionTreePredictionModel, DecisionTreeWithLoopOnLeftChild) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  proto::TreeNode* tree_node =
+      prediction_model->mutable_model()->mutable_decision_tree()->mutable_nodes(
+          1);
+
+  tree_node->mutable_node_id()->set_value(0);
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->mutable_feature_id()
+      ->mutable_id()
+      ->set_value("agg1");
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->mutable_threshold()
+      ->set_float_value(1.0);
+
+  tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(0);
+  tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(2);
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(DecisionTreePredictionModel, DecisionTreeWithLoopOnRightChild) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidDecisionTreePredictionModel();
+
+  proto::TreeNode* tree_node =
+      prediction_model->mutable_model()->mutable_decision_tree()->mutable_nodes(
+          1);
+
+  tree_node->mutable_node_id()->set_value(0);
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->mutable_feature_id()
+      ->mutable_id()
+      ->set_value("agg1");
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->mutable_threshold()
+      ->set_float_value(1.0);
+
+  tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(2);
+  tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(0);
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(DecisionTreePredictionModel, ValidEnsembleModel) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidEnsemblePredictionModel();
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_TRUE(model);
+
+  double prediction_score;
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
+            model->Predict({{"agg1", 1.0}}, &prediction_score));
+  EXPECT_EQ(4., prediction_score);
+  EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
+            model->Predict({{"agg1", 2.0}}, &prediction_score));
+  EXPECT_EQ(8., prediction_score);
+}
+
+TEST(DecisionTreePredictionModel, EnsembleWithNoMembers) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      GetValidEnsemblePredictionModel();
+  prediction_model->mutable_model()
+      ->mutable_ensemble()
+      ->mutable_members()
+      ->Clear();
+
+  proto::ModelInfo* model_info = prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+}  // namespace optimization_guide
diff --git a/components/optimization_guide/prediction_model.cc b/components/optimization_guide/prediction_model.cc
new file mode 100644
index 0000000..87df2ef
--- /dev/null
+++ b/components/optimization_guide/prediction_model.cc
@@ -0,0 +1,104 @@
+// Copyright 2020 The Chromium 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/optimization_guide/prediction_model.h"
+
+#include <utility>
+
+#include "components/optimization_guide/decision_tree_prediction_model.h"
+
+namespace optimization_guide {
+
+// static
+std::unique_ptr<PredictionModel> PredictionModel::Create(
+    std::unique_ptr<optimization_guide::proto::PredictionModel>
+        prediction_model) {
+  // TODO(crbug/1009123): Add a histogram to record if the provided model is
+  // constructed successfully or not.
+  // TODO(crbug/1009123): Adding timing metrics around initialization due to
+  // potential validation overhead.
+  if (!prediction_model->has_model())
+    return nullptr;
+
+  if (!prediction_model->has_model_info())
+    return nullptr;
+
+  if (!prediction_model->model_info().has_version())
+    return nullptr;
+
+  // Enforce that only one ModelType is specified for the PredictionModel.
+  if (prediction_model->model_info().supported_model_types_size() != 1) {
+    return nullptr;
+  }
+
+  // Check that the client supports this type of model and is not an unknown
+  // type.
+  if (!optimization_guide::proto::ModelType_IsValid(
+          prediction_model->model_info().supported_model_types(0)) ||
+      prediction_model->model_info().supported_model_types(0) ==
+          optimization_guide::proto::ModelType::MODEL_TYPE_UNKNOWN) {
+    return nullptr;
+  }
+
+  // Check that the client supports the model features for |prediction model|.
+  for (const auto& model_feature :
+       prediction_model->model_info().supported_model_features()) {
+    if (!optimization_guide::proto::ClientModelFeature_IsValid(model_feature) ||
+        model_feature == optimization_guide::proto::ClientModelFeature::
+                             CLIENT_MODEL_FEATURE_UNKNOWN)
+      return nullptr;
+  }
+
+  std::unique_ptr<PredictionModel> model;
+  // The Decision Tree model type is currently the only supported model type.
+  if (prediction_model->model_info().supported_model_types(0) !=
+      optimization_guide::proto::ModelType::MODEL_TYPE_DECISION_TREE) {
+    return nullptr;
+  }
+  model = std::make_unique<DecisionTreePredictionModel>(
+      std::move(prediction_model));
+
+  // Any constructed model must be validated for correctness according to its
+  // model type before being returned.
+  if (!model->ValidatePredictionModel())
+    return nullptr;
+
+  return model;
+}
+
+PredictionModel::PredictionModel(
+    std::unique_ptr<optimization_guide::proto::PredictionModel>
+        prediction_model) {
+  version_ = prediction_model->model_info().version();
+  model_features_.reserve(
+      prediction_model->model_info().supported_model_features_size() +
+      prediction_model->model_info().supported_host_model_features_size());
+  // Insert all the client model features for the owned |model_|.
+  for (const auto& client_model_feature :
+       prediction_model->model_info().supported_model_features()) {
+    model_features_.emplace(optimization_guide::proto::ClientModelFeature_Name(
+        client_model_feature));
+  }
+  // Insert all the host model features for the owned |model_|.
+  for (const auto& host_model_feature :
+       prediction_model->model_info().supported_host_model_features()) {
+    model_features_.emplace(host_model_feature);
+  }
+  model_ = std::make_unique<optimization_guide::proto::Model>(
+      prediction_model->model());
+}
+
+int64_t PredictionModel::GetVersion() const {
+  SEQUENCE_CHECKER(sequence_checker_);
+  return version_;
+}
+
+base::flat_set<std::string> PredictionModel::GetModelFeatures() const {
+  SEQUENCE_CHECKER(sequence_checker_);
+  return model_features_;
+}
+
+PredictionModel::~PredictionModel() = default;
+
+}  // namespace optimization_guide
diff --git a/components/optimization_guide/prediction_model.h b/components/optimization_guide/prediction_model.h
new file mode 100644
index 0000000..a190905
--- /dev/null
+++ b/components/optimization_guide/prediction_model.h
@@ -0,0 +1,76 @@
+// Copyright 2020 The Chromium 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_OPTIMIZATION_GUIDE_PREDICTION_MODEL_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_PREDICTION_MODEL_H_
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
+#include "components/optimization_guide/optimization_guide_enums.h"
+#include "components/optimization_guide/proto/models.pb.h"
+
+namespace optimization_guide {
+
+// A PredictionModel supported by the optimization guide that makes an
+// OptimizationTargetDecision by evaluating a prediction model.
+class PredictionModel {
+ public:
+  virtual ~PredictionModel();
+
+  // Creates an Prediction model of the correct ModelType specified in
+  // |prediction_model|. The validation overhead of this factory can be high and
+  // should should be called in the background.
+  static std::unique_ptr<PredictionModel> Create(
+      std::unique_ptr<optimization_guide::proto::PredictionModel>
+          prediction_model);
+
+  // Returns the OptimizationTargetDecision by evaluating the |model_|
+  // using the provided |model_features|. |prediction_score| will be populated
+  // with the score output by the model.
+  virtual optimization_guide::OptimizationTargetDecision Predict(
+      const base::flat_map<std::string, float>& model_features,
+      double* prediction_score) = 0;
+
+  // Provide the version of the |model_| by |this|.
+  int64_t GetVersion() const;
+
+  // Provide the model features required for evaluation of the |model_| by
+  // |this|.
+  base::flat_set<std::string> GetModelFeatures() const;
+
+ protected:
+  PredictionModel(std::unique_ptr<optimization_guide::proto::PredictionModel>
+                      prediction_model);
+
+  // The in-memory model used for prediction.
+  std::unique_ptr<optimization_guide::proto::Model> model_;
+
+ private:
+  // Determines if the |model_| is complete and can be successfully evaluated by
+  // |this|.
+  virtual bool ValidatePredictionModel() const = 0;
+
+  // The information that describes the |model_|
+  std::unique_ptr<optimization_guide::proto::ModelInfo> model_info_;
+
+  // The set of features required by the |model_| to be evaluated.
+  base::flat_set<std::string> model_features_;
+
+  // The version of the |model_|.
+  int64_t version_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(PredictionModel);
+};
+
+}  // namespace optimization_guide
+
+#endif  // COMPONENTS_OPTIMIZATION_GUIDE_PREDICTION_MODEL_H_
diff --git a/components/optimization_guide/prediction_model_unittest.cc b/components/optimization_guide/prediction_model_unittest.cc
new file mode 100644
index 0000000..f84fbfd
--- /dev/null
+++ b/components/optimization_guide/prediction_model_unittest.cc
@@ -0,0 +1,174 @@
+// Copyright 2020 The Chromium 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/optimization_guide/prediction_model.h"
+
+#include <utility>
+
+#include "components/optimization_guide/proto/models.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace optimization_guide {
+
+TEST(PredictionModelTest, ValidPredictionModel) {
+  std::unique_ptr<proto::PredictionModel> prediction_model =
+      std::make_unique<proto::PredictionModel>();
+  prediction_model->mutable_model()->mutable_threshold()->set_value(5.0);
+
+  proto::DecisionTree decision_tree_model = proto::DecisionTree();
+  decision_tree_model.set_weight(2.0);
+
+  proto::TreeNode* tree_node = decision_tree_model.add_nodes();
+  tree_node->mutable_node_id()->set_value(0);
+  tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(1);
+  tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(2);
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->mutable_feature_id()
+      ->mutable_id()
+      ->set_value("agg1");
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
+  tree_node->mutable_binary_node()
+      ->mutable_inequality_left_child_test()
+      ->mutable_threshold()
+      ->set_float_value(1.0);
+
+  tree_node = decision_tree_model.add_nodes();
+  tree_node->mutable_node_id()->set_value(1);
+  tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
+      2.);
+
+  tree_node = decision_tree_model.add_nodes();
+  tree_node->mutable_node_id()->set_value(2);
+  tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
+      4.);
+
+  *prediction_model->mutable_model()->mutable_decision_tree() =
+      decision_tree_model;
+
+  optimization_guide::proto::ModelInfo* model_info =
+      prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      optimization_guide::proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_features(
+      optimization_guide::proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
+  model_info->add_supported_host_model_features("agg1");
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+
+  EXPECT_EQ(1, model->GetVersion());
+  EXPECT_EQ(2u, model->GetModelFeatures().size());
+  EXPECT_TRUE(model->GetModelFeatures().count("agg1"));
+  EXPECT_TRUE(model->GetModelFeatures().count(
+      "CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE"));
+}
+
+TEST(PredictionModelTest, NoModel) {
+  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
+      std::make_unique<optimization_guide::proto::PredictionModel>();
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(PredictionModelTest, NoModelVersion) {
+  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
+      std::make_unique<optimization_guide::proto::PredictionModel>();
+
+  optimization_guide::proto::DecisionTree* decision_tree_model =
+      prediction_model->mutable_model()->mutable_decision_tree();
+  decision_tree_model->set_weight(2.0);
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(PredictionModelTest, NoModelType) {
+  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
+      std::make_unique<optimization_guide::proto::PredictionModel>();
+
+  optimization_guide::proto::DecisionTree* decision_tree_model =
+      prediction_model->mutable_model()->mutable_decision_tree();
+  decision_tree_model->set_weight(2.0);
+
+  optimization_guide::proto::ModelInfo* model_info =
+      prediction_model->mutable_model_info();
+  model_info->set_version(1);
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(PredictionModelTest, UnknownModelType) {
+  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
+      std::make_unique<optimization_guide::proto::PredictionModel>();
+
+  optimization_guide::proto::DecisionTree* decision_tree_model =
+      prediction_model->mutable_model()->mutable_decision_tree();
+  decision_tree_model->set_weight(2.0);
+
+  optimization_guide::proto::ModelInfo* model_info =
+      prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      optimization_guide::proto::ModelType::MODEL_TYPE_UNKNOWN);
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(PredictionModelTest, MultipleModelTypes) {
+  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
+      std::make_unique<optimization_guide::proto::PredictionModel>();
+
+  optimization_guide::proto::DecisionTree* decision_tree_model =
+      prediction_model->mutable_model()->mutable_decision_tree();
+  decision_tree_model->set_weight(2.0);
+
+  optimization_guide::proto::ModelInfo* model_info =
+      prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      optimization_guide::proto::ModelType::MODEL_TYPE_DECISION_TREE);
+  model_info->add_supported_model_types(
+      optimization_guide::proto::ModelType::MODEL_TYPE_UNKNOWN);
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+TEST(PredictionModelTest, UnknownModelClientFeature) {
+  std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
+      std::make_unique<optimization_guide::proto::PredictionModel>();
+
+  optimization_guide::proto::DecisionTree* decision_tree_model =
+      prediction_model->mutable_model()->mutable_decision_tree();
+  decision_tree_model->set_weight(2.0);
+
+  optimization_guide::proto::ModelInfo* model_info =
+      prediction_model->mutable_model_info();
+  model_info->set_version(1);
+  model_info->add_supported_model_types(
+      optimization_guide::proto::ModelType::MODEL_TYPE_DECISION_TREE);
+
+  model_info->add_supported_model_features(
+      optimization_guide::proto::ClientModelFeature::
+          CLIENT_MODEL_FEATURE_UNKNOWN);
+
+  std::unique_ptr<PredictionModel> model =
+      PredictionModel::Create(std::move(prediction_model));
+  EXPECT_FALSE(model);
+}
+
+}  // namespace optimization_guide
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java
index 85d7d1d..19d5031 100644
--- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java
+++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinator.java
@@ -51,11 +51,18 @@
      * @param clipRect The {@link Rect} in which this sub-frame should be shown in.
      */
     public void addSubFrame(PlayerFrameCoordinator subFrame, Rect clipRect) {
-        mMediator.addSubFrame(subFrame.getView(), clipRect);
+        mMediator.addSubFrame(subFrame.mView, clipRect, subFrame.getMediator());
         subFrame.mView.getGestureDetector().setParentGestureDetector(mView.getGestureDetector());
     }
 
     /**
+     * @return The mediator associated with this component.
+     */
+    public PlayerFrameMediator getMediator() {
+        return mMediator;
+    }
+
+    /**
      * @return The view associated with this component.
      */
     public View getView() {
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameGestureDetector.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameGestureDetector.java
index daf4b27..22929bf 100644
--- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameGestureDetector.java
+++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameGestureDetector.java
@@ -66,6 +66,11 @@
 
         if (event.getAction() == MotionEvent.ACTION_UP) {
             mPlayerFrameViewDelegate.onRelease();
+            // Propagate the release to the parent, this won't trigger any unexpected behavior as
+            // this is only an UP event.
+            if (mParentGestureDetector != null) {
+                mParentGestureDetector.onTouchEvent(event);
+            }
         }
         return mGestureDetector.onTouchEvent(event);
     }
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java
index 21fe4fc..6d730d2 100644
--- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java
+++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediator.java
@@ -56,6 +56,10 @@
      */
     private final List<Rect> mSubFrameRects = new ArrayList<>();
     /**
+     * Contains all mediators corresponding to this frame's sub-frames.
+     */
+    private final List<PlayerFrameMediator> mSubFrameMediators = new ArrayList<>();
+    /**
      * Contains scaled clip rects corresponding to this frame's sub-frames.
      */
     private final List<Rect> mSubFrameScaledRects = new ArrayList<>();
@@ -67,6 +71,10 @@
      * Contains scaled clip rects for currently visible sub-frames according to {@link #mViewPort}.
      */
     private final List<Rect> mVisibleSubFrameScaledRects = new ArrayList<>();
+    /**
+     * Contains mediators for currently visible sub-frames according to {@link #mViewPort}.
+     */
+    private final List<PlayerFrameMediator> mVisibleSubFrameMediators = new ArrayList<>();
     private final PropertyModel mModel;
     private final PlayerCompositorDelegate mCompositorDelegate;
     private final OverScroller mScroller;
@@ -125,10 +133,12 @@
      * Adds a new sub-frame to this frame.
      * @param subFrameView The {@link View} associated with the sub-frame.
      * @param clipRect     The bounds of the sub-frame, relative to this frame.
+     * @param mediator     The mediator of the sub-frame.
      */
-    void addSubFrame(View subFrameView, Rect clipRect) {
+    void addSubFrame(View subFrameView, Rect clipRect, PlayerFrameMediator mediator) {
         mSubFrameViews.add(subFrameView);
         mSubFrameRects.add(clipRect);
+        mSubFrameMediators.add(mediator);
         mSubFrameScaledRects.add(new Rect());
     }
 
@@ -149,7 +159,6 @@
                 width, height, (mScaleFactor == 0f) ? mInitialScaleFactor : mScaleFactor);
     }
 
-    @Override
     public void setBitmapScaleMatrix(Matrix matrix, float scaleFactor) {
         // Don't update the subframes if the matrix is identity as it will be forcibly recalculated.
         if (!matrix.isIdentity()) {
@@ -165,19 +174,17 @@
         Matrix childBitmapScaleMatrix = new Matrix();
         childBitmapScaleMatrix.setScale(
                 matrixValues[Matrix.MSCALE_X], matrixValues[Matrix.MSCALE_Y]);
-        for (View subFrameView : mVisibleSubFrameViews) {
-            ((PlayerFrameView) subFrameView)
-                    .updateDelegateScaleMatrix(childBitmapScaleMatrix, scaleFactor);
+        for (PlayerFrameMediator subFrameMediator : mVisibleSubFrameMediators) {
+            subFrameMediator.setBitmapScaleMatrix(childBitmapScaleMatrix, scaleFactor);
         }
         mModel.set(PlayerFrameProperties.SCALE_MATRIX, mBitmapScaleMatrix);
     }
 
-    @Override
     public void forceRedraw() {
         mInitialScaleFactor = ((float) mViewportRect.width()) / ((float) mContentWidth);
         moveViewport(0, 0, (mScaleFactor == 0f) ? mInitialScaleFactor : mScaleFactor);
-        for (View subFrameView : mVisibleSubFrameViews) {
-            ((PlayerFrameView) subFrameView).forceRedraw();
+        for (PlayerFrameMediator subFrameMediator : mVisibleSubFrameMediators) {
+            subFrameMediator.forceRedraw();
         }
     }
 
@@ -279,6 +286,7 @@
     private void updateSubFrames(Rect viewport, float scaleFactor) {
         mVisibleSubFrameViews.clear();
         mVisibleSubFrameScaledRects.clear();
+        mVisibleSubFrameMediators.clear();
         for (int i = 0; i < mSubFrameRects.size(); i++) {
             Rect subFrameScaledRect = mSubFrameScaledRects.get(i);
             scaleRect(mSubFrameRects.get(i), subFrameScaledRect, scaleFactor);
@@ -290,6 +298,7 @@
                         transformedTop + subFrameScaledRect.height());
                 mVisibleSubFrameViews.add(mSubFrameViews.get(i));
                 mVisibleSubFrameScaledRects.add(subFrameScaledRect);
+                mVisibleSubFrameMediators.add(mSubFrameMediators.get(i));
             }
         }
     }
@@ -393,6 +402,8 @@
         // Ignore if there is no active overscroll and the direction is down.
         if (!mIsOverscrolling && distanceY <= 0) return false;
 
+        // TODO(crbug/1100338): Propagate this state to child mediators to
+        // support easing.
         mOverscrollAmount += distanceY;
 
         // If the overscroll is completely eased off the cancel the event.
@@ -566,8 +577,8 @@
                 newYRounded + mViewportRect.height());
 
         moveViewport(0, 0, finalScaleFactor);
-        for (View subFrameView : mVisibleSubFrameViews) {
-            ((PlayerFrameView) subFrameView).forceRedraw();
+        for (PlayerFrameMediator subFrameMediator : mVisibleSubFrameMediators) {
+            subFrameMediator.forceRedraw();
         }
 
         return true;
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameView.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameView.java
index 1d47081..b58f05c 100644
--- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameView.java
+++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameView.java
@@ -93,14 +93,6 @@
         layoutSubframes();
     }
 
-    void updateDelegateScaleMatrix(Matrix matrix, float scaleFactor) {
-        mDelegate.setBitmapScaleMatrix(matrix, scaleFactor);
-    }
-
-    void forceRedraw() {
-        mDelegate.forceRedraw();
-    }
-
     @Override
     protected void onDraw(Canvas canvas) {
         canvas.save();
diff --git a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameViewDelegate.java b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameViewDelegate.java
index 3b43a9c..a0dfcd7 100644
--- a/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameViewDelegate.java
+++ b/components/paint_preview/player/android/java/src/org/chromium/components/paintpreview/player/frame/PlayerFrameViewDelegate.java
@@ -4,8 +4,6 @@
 
 package org.chromium.components.paintpreview.player.frame;
 
-import android.graphics.Matrix;
-
 /**
  * Used by {@link PlayerFrameView} to delegate view events to {@link PlayerFrameMediator}.
  */
@@ -16,16 +14,6 @@
     void setLayoutDimensions(int width, int height);
 
     /**
-     * Called to set the bitmap scale matrix for this frame.
-     */
-    void setBitmapScaleMatrix(Matrix matrix, float scaleFactor);
-
-    /**
-     * Triggers a redraw if one is needed.
-     */
-    void forceRedraw();
-
-    /**
      * Called when a scroll gesture is performed.
      * @param distanceX Horizontal scroll values in pixels.
      * @param distanceY Vertical scroll values in pixels.
diff --git a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
index ec49bee8..03b52d6 100644
--- a/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
+++ b/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
@@ -608,9 +608,12 @@
         Pair<View, Rect> subFrame3 =
                 new Pair<>(Mockito.mock(View.class), new Rect(120, 35, 150, 65));
 
-        mMediator.addSubFrame(subFrame1.first, subFrame1.second);
-        mMediator.addSubFrame(subFrame2.first, subFrame2.second);
-        mMediator.addSubFrame(subFrame3.first, subFrame3.second);
+        mMediator.addSubFrame(
+                subFrame1.first, subFrame1.second, Mockito.mock(PlayerFrameMediator.class));
+        mMediator.addSubFrame(
+                subFrame2.first, subFrame2.second, Mockito.mock(PlayerFrameMediator.class));
+        mMediator.addSubFrame(
+                subFrame3.first, subFrame3.second, Mockito.mock(PlayerFrameMediator.class));
 
         // Initial view port setup.
         mMediator.updateViewportSize(100, 200, 1f);
@@ -1096,13 +1099,14 @@
      */
     @Test
     public void testViewPortOnScaleByWithSubFrames() {
-        PlayerFrameView subFrame1View = Mockito.mock(PlayerFrameView.class);
-        Pair<View, Rect> subFrame1 = new Pair<>(subFrame1View, new Rect(10, 20, 60, 40));
-        PlayerFrameView subFrame2View = Mockito.mock(PlayerFrameView.class);
-        Pair<View, Rect> subFrame2 = new Pair<>(subFrame2View, new Rect(30, 50, 70, 160));
+        PlayerFrameMediator subFrame1Mediator = Mockito.mock(PlayerFrameMediator.class);
+        Pair<View, Rect> subFrame1 = new Pair<>(Mockito.mock(View.class), new Rect(10, 20, 60, 40));
+        PlayerFrameMediator subFrame2Mediator = Mockito.mock(PlayerFrameMediator.class);
+        Pair<View, Rect> subFrame2 =
+                new Pair<>(Mockito.mock(View.class), new Rect(30, 50, 70, 160));
 
-        mMediator.addSubFrame(subFrame1.first, subFrame1.second);
-        mMediator.addSubFrame(subFrame2.first, subFrame2.second);
+        mMediator.addSubFrame(subFrame1.first, subFrame1.second, subFrame1Mediator);
+        mMediator.addSubFrame(subFrame2.first, subFrame2.second, subFrame2Mediator);
 
         // Both subframes should be visible.
         mMediator.updateViewportSize(50, 100, 1f);
@@ -1126,16 +1130,16 @@
         Assert.assertEquals(expectedVisibleRects, mModel.get(PlayerFrameProperties.SUBFRAME_RECTS));
         Matrix expectedMatrix = new Matrix();
         expectedMatrix.setScale(2f, 2f);
-        verify(subFrame1View)
-                .updateDelegateScaleMatrix(argThat(new MatrixMatcher(expectedMatrix)), eq(2f));
+        verify(subFrame1Mediator)
+                .setBitmapScaleMatrix(argThat(new MatrixMatcher(expectedMatrix)), eq(2f));
 
         Assert.assertTrue(mMediator.scaleFinished(1f, 0f, 0f));
         Assert.assertEquals(expectedVisibleViews, mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS));
         Assert.assertEquals(expectedVisibleRects, mModel.get(PlayerFrameProperties.SUBFRAME_RECTS));
         expectedMatrix.reset();
-        verify(subFrame1View)
-                .updateDelegateScaleMatrix(argThat(new MatrixMatcher(expectedMatrix)), eq(1f));
-        verify(subFrame1View).forceRedraw();
+        verify(subFrame1Mediator)
+                .setBitmapScaleMatrix(argThat(new MatrixMatcher(expectedMatrix)), eq(1f));
+        verify(subFrame1Mediator).forceRedraw();
 
         // Scroll so the second subframe is back in the viewport..
         mMediator.scrollBy(20, 40);
@@ -1154,10 +1158,10 @@
         Assert.assertEquals(expectedVisibleViews, mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS));
         Assert.assertEquals(expectedVisibleRects, mModel.get(PlayerFrameProperties.SUBFRAME_RECTS));
         expectedMatrix.setScale(0.75f, 0.75f);
-        verify(subFrame1View)
-                .updateDelegateScaleMatrix(argThat(new MatrixMatcher(expectedMatrix)), eq(1.5f));
-        verify(subFrame2View)
-                .updateDelegateScaleMatrix(argThat(new MatrixMatcher(expectedMatrix)), eq(1.5f));
+        verify(subFrame1Mediator)
+                .setBitmapScaleMatrix(argThat(new MatrixMatcher(expectedMatrix)), eq(1.5f));
+        verify(subFrame2Mediator)
+                .setBitmapScaleMatrix(argThat(new MatrixMatcher(expectedMatrix)), eq(1.5f));
     }
 
     /**
@@ -1238,9 +1242,9 @@
      */
     @Test
     public void testViewPortOnScaleByWithNestedSubFrames() {
-        PlayerFrameView subFrameView = Mockito.mock(PlayerFrameView.class);
-        Pair<View, Rect> subFrame = new Pair<>(subFrameView, new Rect(10, 20, 60, 40));
-        mMediator.addSubFrame(subFrame.first, subFrame.second);
+        PlayerFrameMediator subFrameMediator = Mockito.mock(PlayerFrameMediator.class);
+        Pair<View, Rect> subFrame = new Pair<>(Mockito.mock(View.class), new Rect(10, 20, 60, 40));
+        mMediator.addSubFrame(subFrame.first, subFrame.second, subFrameMediator);
 
         // The subframe should be visible.
         mMediator.updateViewportSize(50, 100, 1f);
@@ -1262,8 +1266,8 @@
         mMediator.setBitmapScaleMatrix(scaleMatrix, 2f);
         Assert.assertEquals(expectedVisibleViews, mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS));
         Assert.assertEquals(expectedVisibleRects, mModel.get(PlayerFrameProperties.SUBFRAME_RECTS));
-        verify(subFrameView)
-                .updateDelegateScaleMatrix(argThat(new MatrixMatcher(scaleMatrix)), eq(2f));
+        verify(subFrameMediator)
+                .setBitmapScaleMatrix(argThat(new MatrixMatcher(scaleMatrix)), eq(2f));
 
         expectedVisibleViews.clear();
         expectedVisibleRects.clear();
@@ -1275,11 +1279,11 @@
         mMediator.setBitmapScaleMatrix(scaleMatrix, 1.5f);
         Assert.assertEquals(expectedVisibleViews, mModel.get(PlayerFrameProperties.SUBFRAME_VIEWS));
         Assert.assertEquals(expectedVisibleRects, mModel.get(PlayerFrameProperties.SUBFRAME_RECTS));
-        verify(subFrameView)
-                .updateDelegateScaleMatrix(argThat(new MatrixMatcher(scaleMatrix)), eq(1.5f));
+        verify(subFrameMediator)
+                .setBitmapScaleMatrix(argThat(new MatrixMatcher(scaleMatrix)), eq(1.5f));
 
         // Force a redraw and ensure it is recursive.
         mMediator.forceRedraw();
-        verify(subFrameView).forceRedraw();
+        verify(subFrameMediator).forceRedraw();
     }
 }
diff --git a/components/password_manager/core/browser/ui/password_check_referrer.h b/components/password_manager/core/browser/ui/password_check_referrer.h
index fc4c24d..34bf8a1 100644
--- a/components/password_manager/core/browser/ui/password_check_referrer.h
+++ b/components/password_manager/core/browser/ui/password_check_referrer.h
@@ -19,7 +19,9 @@
   kPasswordSettings = 1,      // Web UI, recorded in JavaScript.
   kPhishGuardDialog = 2,      // Native UI, recorded in C++.
   kPasswordBreachDialog = 3,  // Native UI, recorded in C++.
-  kMaxValue = kPasswordBreachDialog,
+  kMoreToFixBubble = 4,       // Native UI, recorded in C++.
+  kUnsafeStateBubble = 5,     // Native UI, recorded in C++.
+  kMaxValue = kUnsafeStateBubble,
 };
 
 // Name of the corresponding Password Check referrer histogram.
diff --git a/components/pdf/renderer/pdf_accessibility_tree.cc b/components/pdf/renderer/pdf_accessibility_tree.cc
index 5dd34743..7315769 100644
--- a/components/pdf/renderer/pdf_accessibility_tree.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree.cc
@@ -9,6 +9,7 @@
 
 #include "base/i18n/break_iterator.h"
 #include "base/memory/ptr_util.h"
+#include "base/notreached.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversion_utils.h"
 #include "components/pdf/renderer/pdf_ax_action_target.h"
@@ -341,6 +342,20 @@
   return node_ptr;
 }
 
+ax::mojom::Role GetRoleForButtonType(PP_PrivateButtonType button_type) {
+  switch (button_type) {
+    case PP_PrivateButtonType::PP_PRIVATEBUTTON_RADIOBUTTON:
+      return ax::mojom::Role::kRadioButton;
+    case PP_PrivateButtonType::PP_PRIVATEBUTTON_CHECKBOX:
+      return ax::mojom::Role::kCheckBox;
+    case PP_PrivateButtonType::PP_PRIVATEBUTTON_PUSHBUTTON:
+      return ax::mojom::Role::kButton;
+    default:
+      NOTREACHED();
+      return ax::mojom::Role::kNone;
+  }
+}
+
 class PdfAccessibilityTreeBuilder {
  public:
   explicit PdfAccessibilityTreeBuilder(
@@ -361,6 +376,7 @@
         images_(page_objects.images),
         highlights_(page_objects.highlights),
         text_fields_(page_objects.form_fields.text_fields),
+        buttons_(page_objects.form_fields.buttons),
         page_bounds_(page_bounds),
         page_index_(page_index),
         page_node_(page_node),
@@ -391,7 +407,10 @@
     uint32_t current_image_index = 0;
     uint32_t current_highlight_index = 0;
     uint32_t current_text_field_index = 0;
+    uint32_t current_button_index = 0;
     LineHelper line_helper(text_runs_);
+    bool pdf_forms_enabled =
+        base::FeatureList::IsEnabled(chrome_pdf::features::kAccessiblePDFForm);
 
     for (size_t text_run_index = 0; text_run_index < text_runs_.size();
          ++text_run_index) {
@@ -430,12 +449,18 @@
                                &text_run_index);
       } else if (IsObjectInTextRun(text_fields_, current_text_field_index,
                                    text_run_index) &&
-                 base::FeatureList::IsEnabled(
-                     chrome_pdf::features::kAccessiblePDFForm)) {
+                 pdf_forms_enabled) {
         FinishStaticNode(&static_text_node, &static_text);
         AddTextFieldToParaNode(text_fields_[current_text_field_index++],
                                para_node, &text_run_index);
         continue;
+      } else if (IsObjectInTextRun(buttons_, current_button_index,
+                                   text_run_index) &&
+                 pdf_forms_enabled) {
+        FinishStaticNode(&static_text_node, &static_text);
+        AddButtonToParaNode(buttons_[current_button_index++], para_node,
+                            &text_run_index);
+        continue;
       } else {
         PP_PdfPageCharacterIndex page_char_index = {
             page_index_, text_run_start_indices_[text_run_index]};
@@ -502,8 +527,11 @@
     base::span<const ppapi::PdfAccessibilityTextFieldInfo>
         remaining_text_fields =
             base::make_span(text_fields_).subspan(current_text_field_index);
+    base::span<const ppapi::PdfAccessibilityButtonInfo> remaining_buttons =
+        base::make_span(buttons_).subspan(current_button_index);
     AddRemainingAnnotations(remaining_links, remaining_images,
-                            remaining_text_fields, para_node);
+                            remaining_text_fields, remaining_buttons,
+                            para_node);
   }
 
  private:
@@ -694,6 +722,36 @@
     return text_field_node;
   }
 
+  ui::AXNodeData* CreateButtonNode(
+      const ppapi::PdfAccessibilityButtonInfo& button) {
+    ax::mojom::Restriction restriction = button.is_read_only
+                                             ? ax::mojom::Restriction::kReadOnly
+                                             : ax::mojom::Restriction::kNone;
+    ui::AXNodeData* button_node =
+        CreateNode(GetRoleForButtonType(button.type), restriction,
+                   render_accessibility_, nodes_);
+    button_node->AddStringAttribute(ax::mojom::StringAttribute::kName,
+                                    button.name);
+    button_node->AddState(ax::mojom::State::kFocusable);
+
+    if (button.type == PP_PRIVATEBUTTON_RADIOBUTTON ||
+        button.type == PP_PRIVATEBUTTON_CHECKBOX) {
+      ax::mojom::CheckedState checkedState =
+          button.is_checked ? ax::mojom::CheckedState::kTrue
+                            : ax::mojom::CheckedState::kNone;
+      button_node->SetCheckedState(checkedState);
+      button_node->AddStringAttribute(ax::mojom::StringAttribute::kValue,
+                                      button.value);
+      button_node->AddIntAttribute(ax::mojom::IntAttribute::kSetSize,
+                                   button.control_count);
+      button_node->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet,
+                                   button.control_index + 1);
+    }
+
+    button_node->relative_bounds.bounds = PpFloatRectToGfxRectF(button.bounds);
+    return button_node;
+  }
+
   void AddTextToAXNode(uint32_t start_text_run_index,
                        uint32_t end_text_run_index,
                        ui::AXNodeData* ax_node,
@@ -851,15 +909,31 @@
     --(*text_run_index);
   }
 
+  void AddButtonToParaNode(const ppapi::PdfAccessibilityButtonInfo& button,
+                           ui::AXNodeData* para_node,
+                           size_t* text_run_index) {
+    // If the |text_run_index| is less than or equal to the button's text
+    // run index, then push the button ahead of the current text run.
+    ui::AXNodeData* button_node = CreateButtonNode(button);
+    para_node->child_ids.push_back(button_node->id);
+    --(*text_run_index);
+  }
+
   void AddRemainingAnnotations(
       base::span<const ppapi::PdfAccessibilityLinkInfo> links,
       base::span<const ppapi::PdfAccessibilityImageInfo> images,
       base::span<const ppapi::PdfAccessibilityTextFieldInfo> text_fields,
+      base::span<const ppapi::PdfAccessibilityButtonInfo> buttons,
       ui::AXNodeData* para_node) {
-    // If we have additional links, images or text fields to insert in the tree,
-    // and we don't have a paragraph node, create a new one.
-    if (!para_node &&
-        (!links.empty() || !images.empty() || !text_fields.empty())) {
+    // If we don't have additional links, images or form fields to insert in the
+    // tree, then return.
+    if (links.empty() && images.empty() && text_fields.empty() &&
+        buttons.empty()) {
+      return;
+    }
+
+    // If we don't have a paragraph node, create a new one.
+    if (!para_node) {
       para_node = CreateNode(ax::mojom::Role::kParagraph,
                              ax::mojom::Restriction::kReadOnly,
                              render_accessibility_, nodes_);
@@ -885,6 +959,13 @@
         ui::AXNodeData* text_field_node = CreateTextFieldNode(text_field);
         para_node->child_ids.push_back(text_field_node->id);
       }
+
+      // Push all the buttons not anchored to any text run to the last
+      // paragraph.
+      for (const ppapi::PdfAccessibilityButtonInfo& button : buttons) {
+        ui::AXNodeData* button_node = CreateButtonNode(button);
+        para_node->child_ids.push_back(button_node->id);
+      }
     }
   }
 
@@ -895,6 +976,7 @@
   const std::vector<ppapi::PdfAccessibilityImageInfo>& images_;
   const std::vector<ppapi::PdfAccessibilityHighlightInfo>& highlights_;
   const std::vector<ppapi::PdfAccessibilityTextFieldInfo>& text_fields_;
+  const std::vector<ppapi::PdfAccessibilityButtonInfo>& buttons_;
   const gfx::RectF& page_bounds_;
   uint32_t page_index_;
   ui::AXNodeData* page_node_;
diff --git a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
index 83ec253..7d76d56 100644
--- a/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
+++ b/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
@@ -666,6 +666,200 @@
   EXPECT_EQ(0u, text_field_node->children().size());
 }
 
+TEST_F(PdfAccessibilityTreeTest, TestButtonNodeCreation) {
+  // Enable feature flag
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      chrome_pdf::features::kAccessiblePDFForm);
+  text_runs_.emplace_back(kFirstTextRun);
+  text_runs_.emplace_back(kSecondTextRun);
+  chars_.insert(chars_.end(), std::begin(kDummyCharsData),
+                std::end(kDummyCharsData));
+
+  {
+    ppapi::PdfAccessibilityButtonInfo check_box;
+    check_box.bounds = PP_MakeFloatRectFromXYWH(1.0f, 1.0f, 5.0f, 6.0f);
+    check_box.index_in_page = 0;
+    check_box.text_run_index = 2;
+    check_box.name = "Read Only Checkbox";
+    check_box.value = "Yes";
+    check_box.is_read_only = true;
+    check_box.is_checked = true;
+    check_box.control_count = 1;
+    check_box.control_index = 0;
+    check_box.type = PP_PrivateButtonType::PP_PRIVATEBUTTON_CHECKBOX;
+    page_objects_.form_fields.buttons.push_back(std::move(check_box));
+  }
+
+  {
+    ppapi::PdfAccessibilityButtonInfo radio_button;
+    radio_button.bounds = PP_MakeFloatRectFromXYWH(1.0f, 2.0f, 5.0f, 6.0f);
+    radio_button.index_in_page = 1;
+    radio_button.text_run_index = 2;
+    radio_button.name = "Radio Button";
+    radio_button.value = "value 1";
+    radio_button.is_read_only = false;
+    radio_button.is_checked = false;
+    radio_button.control_count = 2;
+    radio_button.control_index = 0;
+    radio_button.type = PP_PrivateButtonType::PP_PRIVATEBUTTON_RADIOBUTTON;
+    page_objects_.form_fields.buttons.push_back(std::move(radio_button));
+  }
+
+  {
+    ppapi::PdfAccessibilityButtonInfo radio_button;
+    radio_button.bounds = PP_MakeFloatRectFromXYWH(1.0f, 3.0f, 5.0f, 6.0f);
+    radio_button.index_in_page = 2;
+    radio_button.text_run_index = 2;
+    radio_button.name = "Radio Button";
+    radio_button.value = "value 2";
+    radio_button.is_read_only = false;
+    radio_button.is_checked = true;
+    radio_button.control_count = 2;
+    radio_button.control_index = 1;
+    radio_button.type = PP_PrivateButtonType::PP_PRIVATEBUTTON_RADIOBUTTON;
+    page_objects_.form_fields.buttons.push_back(std::move(radio_button));
+  }
+
+  {
+    ppapi::PdfAccessibilityButtonInfo push_button;
+    push_button.bounds = PP_MakeFloatRectFromXYWH(1.0f, 4.0f, 5.0f, 6.0f);
+    push_button.index_in_page = 3;
+    push_button.text_run_index = 2;
+    push_button.name = "Push Button";
+    push_button.type = PP_PrivateButtonType::PP_PRIVATEBUTTON_PUSHBUTTON;
+    page_objects_.form_fields.buttons.push_back(std::move(push_button));
+  }
+
+  page_info_.text_run_count = text_runs_.size();
+  page_info_.char_count = chars_.size();
+
+  content::RenderFrame* render_frame = view_->GetMainRenderFrame();
+  ASSERT_TRUE(render_frame);
+  render_frame->SetAccessibilityModeForTest(ui::AXMode::kWebContents);
+  ASSERT_TRUE(render_frame->GetRenderAccessibility());
+
+  FakeRendererPpapiHost host(view_->GetMainRenderFrame());
+  PP_Instance instance = 0;
+  pdf::PdfAccessibilityTree pdf_accessibility_tree(&host, instance);
+
+  pdf_accessibility_tree.SetAccessibilityViewportInfo(viewport_info_);
+  pdf_accessibility_tree.SetAccessibilityDocInfo(doc_info_);
+  pdf_accessibility_tree.SetAccessibilityPageInfo(page_info_, text_runs_,
+                                                  chars_, page_objects_);
+
+  /*
+   * Expected tree structure
+   * Document
+   * ++ Region
+   * ++++ Paragraph
+   * ++++++ Static Text
+   * ++++ Paragraph
+   * ++++++ Static Text
+   * ++++++ Check Box
+   * ++++++ Radio Button
+   * ++++++ Radio Button
+   * ++++++ Button
+   */
+
+  ui::AXNode* root_node = pdf_accessibility_tree.GetRoot();
+  ASSERT_TRUE(root_node);
+  EXPECT_EQ(ax::mojom::Role::kDocument, root_node->data().role);
+  ASSERT_EQ(1u, root_node->children().size());
+
+  ui::AXNode* page_node = root_node->children()[0];
+  ASSERT_TRUE(page_node);
+  EXPECT_EQ(ax::mojom::Role::kRegion, page_node->data().role);
+  ASSERT_EQ(2u, page_node->children().size());
+
+  ui::AXNode* paragraph_node = page_node->children()[0];
+  ASSERT_TRUE(paragraph_node);
+  EXPECT_EQ(ax::mojom::Role::kParagraph, paragraph_node->data().role);
+  ASSERT_EQ(1u, paragraph_node->children().size());
+
+  ui::AXNode* static_text_node = paragraph_node->children()[0];
+  ASSERT_TRUE(static_text_node);
+  EXPECT_EQ(ax::mojom::Role::kStaticText, static_text_node->data().role);
+  ASSERT_EQ(1u, static_text_node->children().size());
+
+  paragraph_node = page_node->children()[1];
+  ASSERT_TRUE(paragraph_node);
+  EXPECT_EQ(ax::mojom::Role::kParagraph, paragraph_node->data().role);
+  const std::vector<ui::AXNode*>& child_nodes = paragraph_node->children();
+  ASSERT_EQ(5u, child_nodes.size());
+
+  static_text_node = child_nodes[0];
+  ASSERT_TRUE(static_text_node);
+  EXPECT_EQ(ax::mojom::Role::kStaticText, static_text_node->data().role);
+  ASSERT_EQ(1u, static_text_node->children().size());
+
+  ui::AXNode* check_box_node = child_nodes[1];
+  ASSERT_TRUE(check_box_node);
+  EXPECT_EQ(ax::mojom::Role::kCheckBox, check_box_node->data().role);
+  EXPECT_EQ("Read Only Checkbox", check_box_node->GetStringAttribute(
+                                      ax::mojom::StringAttribute::kName));
+  EXPECT_EQ("Yes", check_box_node->GetStringAttribute(
+                       ax::mojom::StringAttribute::kValue));
+  EXPECT_EQ(ax::mojom::CheckedState::kTrue,
+            check_box_node->data().GetCheckedState());
+  EXPECT_EQ(1,
+            check_box_node->GetIntAttribute(ax::mojom::IntAttribute::kSetSize));
+  EXPECT_EQ(
+      1, check_box_node->GetIntAttribute(ax::mojom::IntAttribute::kPosInSet));
+  EXPECT_EQ(ax::mojom::Restriction::kReadOnly,
+            check_box_node->data().GetRestriction());
+  EXPECT_EQ(gfx::RectF(1.0f, 1.0f, 5.0f, 6.0f),
+            check_box_node->data().relative_bounds.bounds);
+  EXPECT_EQ(0u, check_box_node->children().size());
+
+  ui::AXNode* radio_button_node = child_nodes[2];
+  ASSERT_TRUE(radio_button_node);
+  EXPECT_EQ(ax::mojom::Role::kRadioButton, radio_button_node->data().role);
+  EXPECT_EQ("Radio Button", radio_button_node->GetStringAttribute(
+                                ax::mojom::StringAttribute::kName));
+  EXPECT_EQ("value 1", radio_button_node->GetStringAttribute(
+                           ax::mojom::StringAttribute::kValue));
+  EXPECT_EQ(ax::mojom::CheckedState::kNone,
+            radio_button_node->data().GetCheckedState());
+  EXPECT_EQ(
+      2, radio_button_node->GetIntAttribute(ax::mojom::IntAttribute::kSetSize));
+  EXPECT_EQ(1, radio_button_node->GetIntAttribute(
+                   ax::mojom::IntAttribute::kPosInSet));
+  EXPECT_NE(ax::mojom::Restriction::kReadOnly,
+            radio_button_node->data().GetRestriction());
+  EXPECT_EQ(gfx::RectF(1.0f, 2.0f, 5.0f, 6.0f),
+            radio_button_node->data().relative_bounds.bounds);
+  EXPECT_EQ(0u, radio_button_node->children().size());
+
+  radio_button_node = child_nodes[3];
+  ASSERT_TRUE(radio_button_node);
+  EXPECT_EQ(ax::mojom::Role::kRadioButton, radio_button_node->data().role);
+  EXPECT_EQ("Radio Button", radio_button_node->GetStringAttribute(
+                                ax::mojom::StringAttribute::kName));
+  EXPECT_EQ("value 2", radio_button_node->GetStringAttribute(
+                           ax::mojom::StringAttribute::kValue));
+  EXPECT_EQ(ax::mojom::CheckedState::kTrue,
+            radio_button_node->data().GetCheckedState());
+  EXPECT_EQ(
+      2, radio_button_node->GetIntAttribute(ax::mojom::IntAttribute::kSetSize));
+  EXPECT_EQ(2, radio_button_node->GetIntAttribute(
+                   ax::mojom::IntAttribute::kPosInSet));
+  EXPECT_EQ(ax::mojom::Restriction::kNone,
+            radio_button_node->data().GetRestriction());
+  EXPECT_EQ(gfx::RectF(1.0f, 3.0f, 5.0f, 6.0f),
+            radio_button_node->data().relative_bounds.bounds);
+  EXPECT_EQ(0u, radio_button_node->children().size());
+
+  ui::AXNode* push_button_node = child_nodes[4];
+  ASSERT_TRUE(push_button_node);
+  EXPECT_EQ(ax::mojom::Role::kButton, push_button_node->data().role);
+  EXPECT_EQ("Push Button", push_button_node->GetStringAttribute(
+                               ax::mojom::StringAttribute::kName));
+  EXPECT_EQ(gfx::RectF(1.0f, 4.0f, 5.0f, 6.0f),
+            push_button_node->data().relative_bounds.bounds);
+  EXPECT_EQ(0u, push_button_node->children().size());
+}
+
 TEST_F(PdfAccessibilityTreeTest, TestPreviousNextOnLine) {
   text_runs_.emplace_back(kFirstRunMultiLine);
   text_runs_.emplace_back(kSecondRunMultiLine);
diff --git a/components/policy/core/browser/configuration_policy_handler.cc b/components/policy/core/browser/configuration_policy_handler.cc
index b825d2d5..0ae9fdf 100644
--- a/components/policy/core/browser/configuration_policy_handler.cc
+++ b/components/policy/core/browser/configuration_policy_handler.cc
@@ -677,4 +677,46 @@
   NOTREACHED();
 }
 
+// SimpleDeprecatingPolicyHandler implementation -----------------------
+
+SimpleDeprecatingPolicyHandler::SimpleDeprecatingPolicyHandler(
+    std::unique_ptr<TypeCheckingPolicyHandler> legacy_policy_handler,
+    std::unique_ptr<TypeCheckingPolicyHandler> new_policy_handler)
+    : legacy_policy_handler_(std::move(legacy_policy_handler)),
+      new_policy_handler_(std::move(new_policy_handler)) {}
+
+SimpleDeprecatingPolicyHandler::~SimpleDeprecatingPolicyHandler() = default;
+
+bool SimpleDeprecatingPolicyHandler::CheckPolicySettings(
+    const PolicyMap& policies,
+    PolicyErrorMap* errors) {
+  // TODO(crbug/1102492): When the legacy policy value is ignored, do you think
+  // it's a good idea to add the "Ignore" error to it: IDS_POLICY_LABEL_IGNORED
+  // && IDS_POLICY_OVERRIDDEN.
+  if (policies.Get(new_policy_handler_->policy_name()))
+    return new_policy_handler_->CheckPolicySettings(policies, errors);
+
+  // The new policy is not set, fall back to legacy ones.
+  return legacy_policy_handler_->CheckPolicySettings(policies, errors);
+}
+
+void SimpleDeprecatingPolicyHandler::ApplyPolicySettingsWithParameters(
+    const policy::PolicyMap& policies,
+    const policy::PolicyHandlerParameters& parameters,
+    PrefValueMap* prefs) {
+  if (policies.Get(new_policy_handler_->policy_name())) {
+    new_policy_handler_->ApplyPolicySettingsWithParameters(policies, parameters,
+                                                           prefs);
+  } else {
+    legacy_policy_handler_->ApplyPolicySettingsWithParameters(
+        policies, parameters, prefs);
+  }
+}
+
+void SimpleDeprecatingPolicyHandler::ApplyPolicySettings(
+    const policy::PolicyMap& /* policies */,
+    PrefValueMap* /* prefs */) {
+  NOTREACHED();
+}
+
 }  // namespace policy
diff --git a/components/policy/core/browser/configuration_policy_handler.h b/components/policy/core/browser/configuration_policy_handler.h
index 0583453..c33d2cf9 100644
--- a/components/policy/core/browser/configuration_policy_handler.h
+++ b/components/policy/core/browser/configuration_policy_handler.h
@@ -472,6 +472,38 @@
   DISALLOW_COPY_AND_ASSIGN(LegacyPoliciesDeprecatingPolicyHandler);
 };
 
+// A policy handler to deprecate a single policy with a new one. It will attempt
+// to use the new value if present and then try to use the legacy value instead.
+class POLICY_EXPORT SimpleDeprecatingPolicyHandler
+    : public ConfigurationPolicyHandler {
+ public:
+  SimpleDeprecatingPolicyHandler(
+      std::unique_ptr<TypeCheckingPolicyHandler> legacy_policy_handler,
+      std::unique_ptr<TypeCheckingPolicyHandler> new_policy_handler);
+  ~SimpleDeprecatingPolicyHandler() override;
+  SimpleDeprecatingPolicyHandler(const SimpleDeprecatingPolicyHandler&) =
+      delete;
+  SimpleDeprecatingPolicyHandler& operator=(
+      const SimpleDeprecatingPolicyHandler&) = delete;
+
+  // ConfigurationPolicyHandler:
+  bool CheckPolicySettings(const PolicyMap& policies,
+                           PolicyErrorMap* errors) override;
+
+  void ApplyPolicySettingsWithParameters(
+      const PolicyMap& policies,
+      const PolicyHandlerParameters& parameters,
+      PrefValueMap* prefs) override;
+
+ protected:
+  void ApplyPolicySettings(const PolicyMap& policies,
+                           PrefValueMap* prefs) override;
+
+ private:
+  std::unique_ptr<TypeCheckingPolicyHandler> legacy_policy_handler_;
+  std::unique_ptr<TypeCheckingPolicyHandler> new_policy_handler_;
+};
+
 }  // namespace policy
 
 #endif  // COMPONENTS_POLICY_CORE_BROWSER_CONFIGURATION_POLICY_HANDLER_H_
diff --git a/components/policy/core/browser/configuration_policy_handler_unittest.cc b/components/policy/core/browser/configuration_policy_handler_unittest.cc
index 4b6a298..0c4b80e7 100644
--- a/components/policy/core/browser/configuration_policy_handler_unittest.cc
+++ b/components/policy/core/browser/configuration_policy_handler_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/check.h"
 #include "base/json/json_reader.h"
 #include "base/values.h"
+#include "components/policy/core/browser/configuration_policy_handler_parameters.h"
 #include "components/policy/core/browser/policy_error_map.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/core/common/policy_types.h"
@@ -1040,4 +1041,66 @@
   EXPECT_FALSE(errors.empty());
 }
 
+TEST(SimpleDeprecatingPolicyHandlerTest, CheckDeprecatedUsedWhenNoNewValue) {
+  PolicyMap policy_map;
+  PrefValueMap prefs;
+  std::unique_ptr<base::Value> expected;
+  const base::Value* value;
+  PolicyErrorMap errors;
+  PolicyHandlerParameters params;
+  const char kLegacyPolicy[] = "legacy_policy";
+
+  SimpleDeprecatingPolicyHandler handler(
+      std::make_unique<SimplePolicyHandler>(kLegacyPolicy, kTestPref,
+                                            base::Value::Type::INTEGER),
+      std::make_unique<SimplePolicyHandler>(kTestPolicy, kTestPref,
+                                            base::Value::Type::INTEGER));
+
+  // Check that legacy value alone is used.
+  policy_map.Set(kLegacyPolicy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+                 POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(42),
+                 nullptr);
+  errors.Clear();
+  EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+  EXPECT_TRUE(errors.empty());
+  prefs.Clear();
+  handler.ApplyPolicySettingsWithParameters(policy_map, params, &prefs);
+  expected = std::make_unique<base::Value>(42);
+  EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
+  EXPECT_EQ(*expected, *value);
+
+  // Set the new value as invalid and verify that the total result is invalid.
+  policy_map.Set(kTestPolicy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+                 POLICY_SOURCE_CLOUD, std::make_unique<base::Value>("0"),
+                 nullptr);
+  errors.Clear();
+  EXPECT_FALSE(handler.CheckPolicySettings(policy_map, &errors));
+  EXPECT_FALSE(errors.empty());
+  prefs.Clear();
+
+  // Set the new value and verify that it overrides the legacy.
+  policy_map.Set(kTestPolicy, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+                 POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(1337),
+                 nullptr);
+  errors.Clear();
+  EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+  EXPECT_TRUE(errors.empty());
+  prefs.Clear();
+  handler.ApplyPolicySettingsWithParameters(policy_map, params, &prefs);
+  expected = std::make_unique<base::Value>(1337);
+  EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
+  EXPECT_EQ(*expected, *value);
+
+  // Erasing the legacy value should have no effect at this point.
+  policy_map.Erase(kLegacyPolicy);
+  errors.Clear();
+  EXPECT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
+  EXPECT_TRUE(errors.empty());
+  prefs.Clear();
+  handler.ApplyPolicySettingsWithParameters(policy_map, params, &prefs);
+  expected = std::make_unique<base::Value>(1337);
+  EXPECT_TRUE(prefs.GetValue(kTestPref, &value));
+  EXPECT_EQ(*expected, *value);
+}
+
 }  // namespace policy
diff --git a/components/policy/tools/syntax_check_policy_template_json.py b/components/policy/tools/syntax_check_policy_template_json.py
index b953e4a8..5d91cba 100755
--- a/components/policy/tools/syntax_check_policy_template_json.py
+++ b/components/policy/tools/syntax_check_policy_template_json.py
@@ -1254,11 +1254,23 @@
             'branch point. Please merge it into Beta or change the version to '
             '%d.' % (policy_name, platform, new_version, current_version))
       elif new_version < current_version - 1:
+        self.non_compatibility_error_count += 1
         self._Error(
             'Version %d has been released to Stable already. Please use '
             'version %d instead for platform %s.' %
             (new_version, current_version, platform), 'policy', policy_name)
 
+  def _CheckDeprecatedFutureField(self, original_policy, new_policy,
+                                  policy_name):
+    '''The 'future' flag has been deprecated, it shouldn't be used for any new
+       policy.'''
+    if ('future' in new_policy
+        and (original_policy is None or 'future' not in original_policy)):
+      self.non_compatibility_error_count += 1
+      self._Error(
+          "The 'future' flag has been deprecated, please use the 'future_on' "
+          "list instead.", 'policy', policy_name)
+
   # Checks if the new policy definitions are compatible with the policy
   # definitions coming from the original_file_contents.
   def _CheckPolicyDefinitionsChangeCompatibility(
@@ -1306,6 +1318,11 @@
         if policy['type'] != 'group'
     }
 
+    original_policy_name_set = {
+        policy['name']
+        for policy in original_policy_definitions if policy['type'] != 'group'
+    }
+
     for original_policy in original_policy_definitions:
       # Check change compatibility for all non-group policy definitions.
       if original_policy['type'] == 'group':
@@ -1340,6 +1357,22 @@
             MergeDict(new_released_platforms, new_rolling_out_platform),
             current_version, original_policy['name'])
 
+      self._CheckDeprecatedFutureField(original_policy, new_policy,
+                                       original_policy['name'])
+
+    # Check brand new policies:
+    for new_policy_name in set(
+        policy_definitions_dict.keys()) - original_policy_name_set:
+      new_policy = policy_definitions_dict[new_policy_name]
+      new_released_platforms, new_rolling_out_platform = \
+              self._GetReleasedPlatforms(new_policy, current_version)
+      if new_released_platforms or new_rolling_out_platform:
+        self._CheckNewReleasedPlatforms({},
+                                        MergeDict(new_released_platforms,
+                                                  new_rolling_out_platform),
+                                        current_version, new_policy_name)
+      self._CheckDeprecatedFutureField(None, new_policy, new_policy_name)
+
   def _LeadingWhitespace(self, line):
     match = LEADING_WHITESPACE.match(line)
     if match:
@@ -1592,15 +1625,15 @@
     # if the new policy definitions are compatible with the original policy
     # definitions (if the original file contents have not raised any syntax
     # errors).
-    current_error_count = self.error_count
-    if (not current_error_count and original_file_contents is not None and
-        current_version is not None):
+    self.non_compatibility_error_count = self.error_count
+    if (not self.non_compatibility_error_count
+        and original_file_contents is not None and current_version is not None):
       self._CheckPolicyDefinitionsChangeCompatibility(
           policy_definitions, original_file_contents, current_version)
 
-    if current_error_count != self.error_count:
+    if self.non_compatibility_error_count != self.error_count:
       print(
-          'There were compatibility validation errors in the change. You may '
+          '\nThere were compatibility validation errors in the change. You may '
           'bypass this validation by adding "BYPASS_POLICY_COMPATIBILITY_CHECK='
           '<justification>" to your changelist description. If you believe '
           'that this validation is a bug, please file a crbug against '
diff --git a/components/variations/service/variations_field_trial_creator.cc b/components/variations/service/variations_field_trial_creator.cc
index 386b858..f7768da 100644
--- a/components/variations/service/variations_field_trial_creator.cc
+++ b/components/variations/service/variations_field_trial_creator.cc
@@ -509,9 +509,9 @@
                                        switches::kForceDisableVariationIds));
   }
 
-  feature_list->InitializeFromCommandLine(
+  feature_list->InitializeFromCommandLineWithFeatureParams(
       command_line->GetSwitchValueASCII(kEnableFeatures),
-      command_line->GetSwitchValueASCII(kDisableFeatures));
+      command_line->GetSwitchValueASCII(kDisableFeatures), &UnescapeValue);
 
   // This needs to happen here: After the InitializeFromCommandLine() call,
   // because the explicit cmdline --disable-features and --enable-features
diff --git a/components/viz/service/display/display_resource_provider.cc b/components/viz/service/display/display_resource_provider.cc
index ce01175..02e23a49 100644
--- a/components/viz/service/display/display_resource_provider.cc
+++ b/components/viz/service/display/display_resource_provider.cc
@@ -182,47 +182,6 @@
   return true;
 }
 
-void DisplayResourceProvider::SendPromotionHints(
-    const std::map<ResourceId, gfx::RectF>& promotion_hints,
-    const ResourceIdSet& requestor_set) {
-#if defined(OS_ANDROID)
-  GLES2Interface* gl = ContextGL();
-  if (!gl)
-    return;
-
-  for (const auto& id : requestor_set) {
-    auto it = resources_.find(id);
-    if (it == resources_.end())
-      continue;
-
-    if (it->second.marked_for_deletion)
-      continue;
-
-    const ChildResource* resource = LockForRead(id, false /* overlay_only */);
-    // TODO(ericrk): We should never fail LockForRead, but we appear to be
-    // doing so on Android in rare cases. Handle this gracefully until a better
-    // solution can be found. https://crbug.com/811858
-    if (!resource)
-      return;
-
-    DCHECK(resource->transferable.wants_promotion_hint);
-
-    // Insist that this is backed by a GPU texture.
-    if (resource->is_gpu_resource_type()) {
-      DCHECK(resource->gl_id);
-      auto iter = promotion_hints.find(id);
-      bool promotable = iter != promotion_hints.end();
-      gl->OverlayPromotionHintCHROMIUM(resource->gl_id, promotable,
-                                       promotable ? iter->second.x() : 0,
-                                       promotable ? iter->second.y() : 0,
-                                       promotable ? iter->second.width() : 0,
-                                       promotable ? iter->second.height() : 0);
-    }
-    UnlockForRead(id);
-  }
-#endif
-}
-
 #if defined(OS_ANDROID)
 bool DisplayResourceProvider::IsBackedBySurfaceTexture(ResourceId id) {
   ChildResource* resource = GetResource(id);
diff --git a/components/viz/service/display/display_resource_provider.h b/components/viz/service/display/display_resource_provider.h
index 1ddeda8..e3241d5 100644
--- a/components/viz/service/display/display_resource_provider.h
+++ b/components/viz/service/display/display_resource_provider.h
@@ -86,19 +86,6 @@
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
                     base::trace_event::ProcessMemoryDump* pmd) override;
 
-  // Send an overlay promotion hint to all resources that requested it via
-  // |requestor_set|.  |promotable_hints| contains all the resources that should
-  // be told that they're promotable.  Others will be told that they're not.
-  //
-  // We don't use |wants_promotion_hints_set_| in place of |requestor_set|,
-  // since we might have resources that aren't used for drawing.  Sending a hint
-  // for a resource that wasn't even considered for overlay would be misleading
-  // to the requestor; the resource might be overlayable except that nobody
-  // tried to do it.
-  void SendPromotionHints(
-      const std::map<ResourceId, gfx::RectF>& promotion_hints,
-      const ResourceIdSet& requestor_set);
-
 #if defined(OS_ANDROID)
   // Indicates if this resource is backed by an Android SurfaceTexture, and thus
   // can't really be promoted to an overlay.
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 591e5c4..3d7bffe6 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -2557,8 +2557,8 @@
                quad->uv_bottom_right.y() - quad->uv_top_left.y());
   matrix.Translate(quad->uv_top_left.x(), quad->uv_top_left.y());
   ToGLMatrix(&gl_matrix[0], matrix);
-  gl_->UniformMatrix4fvStreamTextureMatrixCHROMIUM(
-      current_program_->tex_matrix_location(), false, gl_matrix);
+  gl_->UniformMatrix4fv(current_program_->tex_matrix_location(), 1, false,
+                        gl_matrix);
 
   SetShaderOpacity(quad->shared_quad_state->opacity);
   if (current_program_->rounded_corner_rect_location() != -1) {
diff --git a/components/viz/service/display/overlay_ca_unittest.cc b/components/viz/service/display/overlay_ca_unittest.cc
index 4be3865..b9d2876 100644
--- a/components/viz/service/display/overlay_ca_unittest.cc
+++ b/components/viz/service/display/overlay_ca_unittest.cc
@@ -100,7 +100,8 @@
  public:
   CATestOverlayProcessor()
       : OverlayProcessorMac(true /* could_overlay */,
-                            true /* enable_ca_overlay */) {}
+                            true /* enable_ca_overlay */,
+                            true /* enable_render_pass */) {}
 };
 
 std::unique_ptr<RenderPass> CreateRenderPass() {
diff --git a/components/viz/service/display/overlay_processor_interface.cc b/components/viz/service/display/overlay_processor_interface.cc
index f09e8ac..2153888 100644
--- a/components/viz/service/display/overlay_processor_interface.cc
+++ b/components/viz/service/display/overlay_processor_interface.cc
@@ -4,6 +4,8 @@
 
 #include "components/viz/service/display/overlay_processor_interface.h"
 
+#include <utility>
+
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "components/viz/common/display/renderer_settings.h"
@@ -84,12 +86,14 @@
     scoped_refptr<gpu::GpuTaskSchedulerHelper> gpu_task_scheduler,
     gpu::SharedImageInterface* shared_image_interface) {
 #if defined(OS_MACOSX)
+  // TODO(https://crbug.com/1100728): Get RenderPass overlays working.
+  bool allow_render_pass_overlays = !renderer_settings.use_skia_renderer;
   bool could_overlay = surface_handle != gpu::kNullSurfaceHandle;
   could_overlay &= capabilities.supports_surfaceless;
   bool enable_ca_overlay = could_overlay && renderer_settings.allow_overlays;
 
-  return base::WrapUnique(
-      new OverlayProcessorMac(could_overlay, enable_ca_overlay));
+  return base::WrapUnique(new OverlayProcessorMac(
+      could_overlay, enable_ca_overlay, allow_render_pass_overlays));
 #elif defined(OS_WIN)
   bool enable_dc_overlay = surface_handle != gpu::kNullSurfaceHandle;
   enable_dc_overlay &= !capabilities.supports_surfaceless;
diff --git a/components/viz/service/display/overlay_processor_mac.cc b/components/viz/service/display/overlay_processor_mac.cc
index eeb779b8..3a63b6e 100644
--- a/components/viz/service/display/overlay_processor_mac.cc
+++ b/components/viz/service/display/overlay_processor_mac.cc
@@ -16,9 +16,11 @@
 
 namespace viz {
 OverlayProcessorMac::OverlayProcessorMac(bool could_overlay,
-                                         bool enable_ca_overlay)
+                                         bool enable_ca_overlay,
+                                         bool enable_render_pass)
     : could_overlay_(could_overlay),
       enable_ca_overlay_(enable_ca_overlay),
+      enable_render_pass_(enable_render_pass),
       ca_layer_overlay_processor_(std::make_unique<CALayerOverlayProcessor>()) {
 }
 
@@ -26,6 +28,7 @@
     std::unique_ptr<CALayerOverlayProcessor> ca_layer_overlay_processor)
     : could_overlay_(true),
       enable_ca_overlay_(true),
+      enable_render_pass_(true),
       ca_layer_overlay_processor_(std::move(ca_layer_overlay_processor)) {}
 
 OverlayProcessorMac::~OverlayProcessorMac() = default;
@@ -79,6 +82,15 @@
   if (!enable_ca_overlay_)
     return;
 
+  // TODO(https://crbug.com/1100728): RenderPass overlays don't work when using
+  // SkiaRenderer yet.
+  if (!enable_render_pass_) {
+    for (auto* const quad : render_pass->quad_list) {
+      if (quad->material == DrawQuad::Material::kRenderPass)
+        return;
+    }
+  }
+
   // If ca overlay system didn't succeed, we fall back to surfaceless.
   if (!ca_layer_overlay_processor_->ProcessForCALayerOverlays(
           resource_provider, gfx::RectF(render_pass->output_rect),
diff --git a/components/viz/service/display/overlay_processor_mac.h b/components/viz/service/display/overlay_processor_mac.h
index 59fab542..17df7cb 100644
--- a/components/viz/service/display/overlay_processor_mac.h
+++ b/components/viz/service/display/overlay_processor_mac.h
@@ -27,7 +27,9 @@
  public:
   using CandidateList = CALayerOverlayList;
 
-  OverlayProcessorMac(bool could_overlay, bool enable_ca_overlay);
+  OverlayProcessorMac(bool could_overlay,
+                      bool enable_ca_overlay,
+                      bool enable_render_pass);
   // For testing.
   explicit OverlayProcessorMac(
       std::unique_ptr<CALayerOverlayProcessor> ca_layer_overlay_processor);
@@ -68,6 +70,7 @@
  private:
   const bool could_overlay_;
   const bool enable_ca_overlay_;
+  const bool enable_render_pass_;
   gfx::Rect ca_overlay_damage_rect_;
   gfx::Rect previous_frame_full_bounding_rect_;
 
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 1deed46..9a477f6 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -16,6 +16,7 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "cc/base/math_util.h"
+#include "cc/debug/debug_colors.h"
 #include "cc/paint/render_surface_filters.h"
 #include "components/viz/common/display/renderer_settings.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
@@ -51,6 +52,7 @@
 #include "third_party/skia/include/core/SkShader.h"
 #include "third_party/skia/include/core/SkString.h"
 #include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
+#include "third_party/skia/include/effects/SkColorMatrix.h"
 #include "third_party/skia/include/effects/SkGradientShader.h"
 #include "third_party/skia/include/effects/SkImageFilters.h"
 #include "third_party/skia/include/effects/SkOverdrawColorFilter.h"
@@ -391,6 +393,21 @@
          src == SkBlendModeCoeff::kDC;
 }
 
+sk_sp<SkColorFilter> TintCompositedContentColorTransformFilter() {
+  SkColorMatrix matrix;
+  auto color_transform =
+      cc::DebugColors::TintCompositedContentColorTransformMatrix();
+  std::array<float, 20> transposed;
+  transposed.fill(0.0f);
+  for (int r = 0; r < 4; r++) {
+    for (int c = 0; c < 4; c++) {
+      transposed[r * 5 + c] = color_transform[c * 4 + r];
+    }
+  }
+  matrix.setRowMajor(transposed.data());
+  return SkColorFilters::Matrix(matrix);
+}
+
 }  // namespace
 
 // chrome style prevents this from going in skia_renderer.h, but since it
@@ -489,8 +506,11 @@
   // |scissor_rect_| of the renderer.
   base::Optional<gfx::Rect> scissor_rect;
 
-  SkPaint paint() const {
+  SkPaint paint(bool tint_content) const {
     SkPaint p;
+    if (tint_content) {
+      p.setColorFilter(TintCompositedContentColorTransformFilter());
+    }
     p.setFilterQuality(filter_quality);
     p.setBlendMode(blend_mode);
     p.setAlphaf(opacity);
@@ -1056,7 +1076,7 @@
   bool aa = params->aa_flags != SkCanvas::kNone_QuadAAFlags;
   current_canvas_->clipRect(gfx::RectToSkRect(rpdq_params.filter_bounds), aa);
 
-  SkPaint layer_paint = params->paint();
+  SkPaint layer_paint = params->paint(false);
   // The layer always consumes the opacity, but its blend mode depends on if
   // it was initialized with backdrop content or not.
   params->opacity = 1.f;
@@ -1663,6 +1683,10 @@
                 batched_quad_state_.rounded_corner_bounds, nullptr);
 
   SkPaint paint;
+  if (settings_->tint_gl_composited_content &&
+      current_canvas_ == root_canvas_) {
+    paint.setColorFilter(TintCompositedContentColorTransformFilter());
+  }
   paint.setFilterQuality(batched_quad_state_.filter_quality);
   paint.setBlendMode(batched_quad_state_.blend_mode);
 
@@ -1697,6 +1721,10 @@
     }
   }
 
+  if (settings_->tint_gl_composited_content &&
+      current_canvas_ == root_canvas_) {
+    color = TintCompositedContentColorTransformFilter()->filterColor(color);
+  }
   // PrepareCanvasForRPDQ will have updated params->opacity and blend_mode to
   // account for the layer applying those effects.
   color = SkColorSetA(color, params->opacity * SkColorGetA(color));
@@ -1775,7 +1803,7 @@
   }
   path.transform(cdt);
 
-  SkPaint paint = params->paint();
+  SkPaint paint = params->paint(false);
   paint.setColor(quad->color);  // Must correct alpha afterwards
   paint.setAlphaf(params->opacity * paint.getAlphaf());
   paint.setStyle(SkPaint::kStroke_Style);
@@ -1807,7 +1835,9 @@
   // these represent the valid windows of content to show for the display list,
   // so they need to be used as a clip in Skia.
   SkRect visible_rect = gfx::RectFToSkRect(params->visible_rect);
-  SkPaint paint = params->paint();
+  SkPaint paint = params->paint(settings_->tint_gl_composited_content &&
+                                current_canvas_ == root_canvas_);
+
   if (params->draw_region.has_value()) {
     SkPath clip;
     clip.addPoly(params->draw_region->points, 4, true /* close */);
@@ -1878,7 +1908,8 @@
           : gfx::RectF(gfx::SizeF(quad->resource_size_in_pixels()));
 
   if (rpdq_params) {
-    SkPaint paint = params->paint();
+    SkPaint paint = params->paint(settings_->tint_gl_composited_content &&
+                                  current_canvas_ == root_canvas_);
     DrawSingleImage(image, valid_texel_bounds, rpdq_params, &paint, params);
   } else {
     AddQuadToBatch(image, valid_texel_bounds, params);
@@ -1930,7 +1961,9 @@
   if (!batched_quads_.empty())
     FlushBatchedQuads();
 
-  SkPaint paint = params->paint();
+  SkPaint paint = params->paint(settings_->tint_gl_composited_content &&
+                                current_canvas_ == root_canvas_);
+
   float quad_alpha;
   if (rpdq_params) {
     // The added color filters for background blending will not apply the
@@ -2046,7 +2079,8 @@
   }
 
   if (rpdq_params) {
-    SkPaint paint = params->paint();
+    SkPaint paint = params->paint(settings_->tint_gl_composited_content &&
+                                  current_canvas_ == root_canvas_);
     DrawSingleImage(image, valid_texel_bounds, rpdq_params, &paint, params);
   } else {
     AddQuadToBatch(image, valid_texel_bounds, params);
@@ -2111,13 +2145,15 @@
   // Use provided, unclipped texture coordinates as the content area, which will
   // force coord clamping unless the geometry was clipped, or they span the
   // entire YUV image.
-  SkPaint paint = params->paint();
+  SkPaint paint = params->paint(settings_->tint_gl_composited_content &&
+                                current_canvas_ == root_canvas_);
 
   sk_sp<SkColorFilter> color_filter =
       GetColorFilter(src_color_space, dst_color_space, quad->resource_offset,
                      quad->resource_multiplier);
-  DCHECK(!paint.getColorFilter());
-  paint.setColorFilter(color_filter);
+  paint.setColorFilter(paint.getColorFilter()
+                           ? color_filter->makeComposed(paint.refColorFilter())
+                           : color_filter);
 
   DrawSingleImage(image, quad->ya_tex_coord_rect, rpdq_params, &paint, params);
 }
@@ -2488,7 +2524,9 @@
   if (!batched_quads_.empty())
     FlushBatchedQuads();
 
-  SkPaint paint = params->paint();
+  SkPaint paint = params->paint(settings_->tint_gl_composited_content &&
+                                current_canvas_ == root_canvas_);
+
   DrawSingleImage(content_image.get(), valid_texel_bounds, &rpdq_params, &paint,
                   params);
 }
diff --git a/components/webcrypto/README.md b/components/webcrypto/README.md
new file mode 100644
index 0000000..09f0a7d
--- /dev/null
+++ b/components/webcrypto/README.md
@@ -0,0 +1,27 @@
+# Web Crypto
+
+This directory contains the cryptographic code for Chromium's [Web
+Crypto](https://www.w3.org/TR/WebCryptoAPI/) implementation.
+
+The Web Crypto implementation is split between Blink and this directory.
+
+Blink is responsible for parsing Web Crypto's Web IDL, and translating requests
+into method calls on `blink::WebCrypto`, which in turn is implemented here by
+[WebCryptoImpl](webcrypto_impl.h).
+
+`WebCryptoImpl` is what carries out the actual cryptographic operations. Crypto
+is done directly in the renderer process, in software, using BoringSSL. There is
+intentionally no support for hardware backed tokens.
+
+Threading:
+
+The Web Crypto API expects asynchronous completion of operations, even when
+used from Web Workers. `WebCryptoImpl` takes a blanket approach of dispatching
+incoming work to a small worker pool. This favors main thread
+responsiveness/simplicity over throughput. Operations minimally take two thread
+hops.
+
+The split of responsibilities between Blink and `content`
+(`content` is what registers `blink::WebCrypto` to the Blink Platform) is dated
+and could be simplified. See also
+[crbug.com/614385](https://bugs.chromium.org/p/chromium/issues/detail?id=614385).
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index aa7d4f1..739a19d13e 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -1613,7 +1613,8 @@
     if (!parent)
       continue;
 
-    if (ui::IsTextOrLineBreak(changed_node->data().role)) {
+    if (changed_node->IsText() &&
+        changed_node->data().role != ax::mojom::Role::kInlineTextBox) {
       BrowserAccessibility* parent_obj = GetFromAXNode(parent);
       if (parent_obj)
         nodes_needing_update->insert(parent_obj->GetAXPlatformNode());
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index 639087d..125b17a7 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -647,6 +647,14 @@
         base::BindOnce(&NotifyProcessLaunchedAndConnected, data_.Duplicate()));
   }
 
+#if defined(OS_CHROMEOS)
+  // In ChromeOS, there are still child processes of NaCl modules, and they
+  // don't contribute to tracing actually. So do not register those clients
+  // to the tracing service. See https://crbug.com/1101468.
+  if (data_.process_type >= PROCESS_TYPE_CONTENT_END)
+    return;
+#endif
+
   tracing_registration_ = TracingServiceController::Get().RegisterClient(
       process.Pid(), base::BindRepeating(&BindTracedProcessFromUIThread,
                                          weak_factory_.GetWeakPtr()));
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index f3776fa..e922903a 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -6472,6 +6472,11 @@
       remote_interfaces.InitWithNewPipeAndPassReceiver());
   remote_interfaces_.reset(new service_manager::InterfaceProvider);
   remote_interfaces_->Bind(std::move(remote_interfaces));
+
+  // Called to bind the receiver for this interface to the local frame. We need
+  // to eagarly bind here because binding happens at normal priority on the main
+  // thread and future calls to this interface need to be high priority.
+  GetHighPriorityLocalFrame();
 }
 
 void RenderFrameHostImpl::InvalidateMojoConnection() {
@@ -6480,6 +6485,7 @@
   frame_host_associated_receiver_.reset();
   local_frame_.reset();
   local_main_frame_.reset();
+  high_priority_local_frame_.reset();
   navigation_control_.reset();
   find_in_page_.reset();
   render_accessibility_.reset();
@@ -6597,6 +6603,15 @@
   return local_main_frame_;
 }
 
+const mojo::Remote<blink::mojom::HighPriorityLocalFrame>&
+RenderFrameHostImpl::GetHighPriorityLocalFrame() {
+  if (!high_priority_local_frame_.is_bound()) {
+    GetRemoteInterfaces()->GetInterface(
+        high_priority_local_frame_.BindNewPipeAndPassReceiver());
+  }
+  return high_priority_local_frame_;
+}
+
 void RenderFrameHostImpl::ResetLoadingState() {
   if (is_loading()) {
     // When pending deletion, just set the loading state to not loading.
@@ -8553,8 +8568,15 @@
             renderer_before_unload_start_time, renderer_before_unload_end_time);
       },
       rfh);
-  rfh->GetAssociatedLocalFrame()->BeforeUnload(
-      is_reload, std::move(before_unload_closure));
+  // Experiment to run beforeunload handlers at a higher priority in the
+  // renderer. See crubug.com/1042118.
+  if (base::FeatureList::IsEnabled(features::kHighPriorityBeforeUnload)) {
+    rfh->GetHighPriorityLocalFrame()->DispatchBeforeUnload(
+        is_reload, std::move(before_unload_closure));
+  } else {
+    rfh->GetAssociatedLocalFrame()->BeforeUnload(
+        is_reload, std::move(before_unload_closure));
+  }
 }
 
 void RenderFrameHostImpl::AddServiceWorkerContainerHost(
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 9ba93ff..f53cb6a 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -971,6 +971,15 @@
   const mojo::AssociatedRemote<blink::mojom::LocalMainFrame>&
   GetAssociatedLocalMainFrame();
 
+  // Returns remote to blink::mojom::HighPriorityLocalFrame Mojo interface. Note
+  // this interface is highly experimental and is being tested to address
+  // crbug.com/1042118. It is not an associated interface and may be actively
+  // reordered. GetAssociatedLocalFrame() should be used in most cases and any
+  // additional use cases of this interface should probably consider discussing
+  // with navigation-dev@chromium.org first.
+  const mojo::Remote<blink::mojom::HighPriorityLocalFrame>&
+  GetHighPriorityLocalFrame();
+
   // Resets the loading state. Following this call, the RenderFrameHost will be
   // in a non-loading state.
   void ResetLoadingState();
@@ -2626,6 +2635,9 @@
   // remote will be valid when the frame is the active main frame.
   mojo::AssociatedRemote<blink::mojom::LocalMainFrame> local_main_frame_;
 
+  // Holder of Mojo connection with the HighPriorityLocalFrame in blink.
+  mojo::Remote<blink::mojom::HighPriorityLocalFrame> high_priority_local_frame_;
+
   // Holds a NavigationRequest when it's about to commit, ie. after
   // OnCrossDocumentCommitProcessed has returned a positive answer for this
   // NavigationRequest but before receiving DidCommitProvisionalLoad. This
diff --git a/content/browser/indexed_db/OWNERS b/content/browser/indexed_db/OWNERS
index 7eefb66..0ae9c06 100644
--- a/content/browser/indexed_db/OWNERS
+++ b/content/browser/indexed_db/OWNERS
@@ -1,5 +1,9 @@
-dmurph@chromium.org
+# Primary
+enne@chromium.org
+
+# Secondary
 cmp@chromium.org
+dmurph@chromium.org
 jsbell@chromium.org
 pwnall@chromium.org
 
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc
index 00127af..9defea0 100644
--- a/content/browser/renderer_host/render_widget_host_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -680,6 +680,151 @@
             EvalJs(web_contents(), "`${screen.width}x${screen.height}`"));
 }
 
+class RenderWidgetHostFoldableCSSTest : public RenderWidgetHostBrowserTest {
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ContentBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+  }
+};
+
+// Tests that the renderer receives the root widget's window segments and
+// correctly exposes those via CSS.
+// TODO(crbug.com/1098549) Convert this to a WPT once emulation is available
+// via WebDriver.
+IN_PROC_BROWSER_TEST_F(RenderWidgetHostFoldableCSSTest,
+                       FoldablesCSSWithOverrides) {
+  const char kTestPageURL[] =
+      R"HTML(data:text/html,<!DOCTYPE html>
+      <style>
+        div {
+          margin: env(fold-top, 1px) env(fold-right, 1px)
+                  env(fold-bottom, 1px) env(fold-left, 1px);
+          width: env(fold-width, 1px);
+          height: env(fold-height, 1px);
+        }
+        @media (screen-spanning: none) {
+          div { opacity: 0.1; }
+        }
+        @media (screen-spanning: single-fold-vertical) {
+          div { opacity: 0.2; }
+        }
+        @media (screen-spanning: single-fold-horizontal) {
+          div { opacity: 0.3; }
+        }
+      </style>
+      <div id='target'></div>)HTML";
+
+  EXPECT_TRUE(NavigateToURL(shell(), GURL(kTestPageURL)));
+
+  EXPECT_EQ(
+      "1px",
+      EvalJs(shell(), "getComputedStyle(target).marginTop").ExtractString());
+  EXPECT_EQ(
+      "1px",
+      EvalJs(shell(), "getComputedStyle(target).marginRight").ExtractString());
+  EXPECT_EQ(
+      "1px",
+      EvalJs(shell(), "getComputedStyle(target).marginBottom").ExtractString());
+  EXPECT_EQ(
+      "1px",
+      EvalJs(shell(), "getComputedStyle(target).marginLeft").ExtractString());
+  EXPECT_EQ("1px",
+            EvalJs(shell(), "getComputedStyle(target).width").ExtractString());
+  EXPECT_EQ("1px",
+            EvalJs(shell(), "getComputedStyle(target).height").ExtractString());
+
+  EXPECT_EQ(
+      "0.1",
+      EvalJs(shell(), "getComputedStyle(target).opacity").ExtractString());
+
+  const gfx::Size root_view_size = view()->GetVisibleViewportSize();
+  const int kDisplayFeatureLength = 10;
+  DisplayFeature emulated_display_feature{
+      DisplayFeature::Orientation::kVertical,
+      /* offset */ root_view_size.width() / 2 - kDisplayFeatureLength / 2,
+      /* mask_length */ kDisplayFeatureLength};
+  view()->SetDisplayFeatureForTesting(emulated_display_feature);
+  host()->SynchronizeVisualProperties();
+
+  EXPECT_EQ(
+      "0px",
+      EvalJs(shell(), "getComputedStyle(target).marginTop").ExtractString());
+  EXPECT_EQ(
+      base::NumberToString(emulated_display_feature.offset +
+                           emulated_display_feature.mask_length) +
+          "px",
+      EvalJs(shell(), "getComputedStyle(target).marginRight").ExtractString());
+  EXPECT_EQ(
+      base::NumberToString(root_view_size.height()) + "px",
+      EvalJs(shell(), "getComputedStyle(target).marginBottom").ExtractString());
+  EXPECT_EQ(
+      base::NumberToString(emulated_display_feature.offset) + "px",
+      EvalJs(shell(), "getComputedStyle(target).marginLeft").ExtractString());
+  EXPECT_EQ(base::NumberToString(emulated_display_feature.mask_length) + "px",
+            EvalJs(shell(), "getComputedStyle(target).width").ExtractString());
+  EXPECT_EQ(base::NumberToString(root_view_size.height()) + "px",
+            EvalJs(shell(), "getComputedStyle(target).height").ExtractString());
+
+  EXPECT_EQ(
+      "0.2",
+      EvalJs(shell(), "getComputedStyle(target).opacity").ExtractString());
+
+  emulated_display_feature.orientation =
+      DisplayFeature::Orientation::kHorizontal;
+  emulated_display_feature.offset =
+      root_view_size.height() / 2 - kDisplayFeatureLength / 2,
+  view()->SetDisplayFeatureForTesting(emulated_display_feature);
+  host()->SynchronizeVisualProperties();
+
+  EXPECT_EQ(
+      base::NumberToString(emulated_display_feature.offset) + "px",
+      EvalJs(shell(), "getComputedStyle(target).marginTop").ExtractString());
+  EXPECT_EQ(
+      base::NumberToString(root_view_size.width()) + "px",
+      EvalJs(shell(), "getComputedStyle(target).marginRight").ExtractString());
+  EXPECT_EQ(
+      base::NumberToString(emulated_display_feature.offset +
+                           emulated_display_feature.mask_length) +
+          "px",
+      EvalJs(shell(), "getComputedStyle(target).marginBottom").ExtractString());
+  EXPECT_EQ(
+      "0px",
+      EvalJs(shell(), "getComputedStyle(target).marginLeft").ExtractString());
+  EXPECT_EQ(base::NumberToString(root_view_size.width()) + "px",
+            EvalJs(shell(), "getComputedStyle(target).width").ExtractString());
+  EXPECT_EQ(base::NumberToString(emulated_display_feature.mask_length) + "px",
+            EvalJs(shell(), "getComputedStyle(target).height").ExtractString());
+
+  EXPECT_EQ(
+      "0.3",
+      EvalJs(shell(), "getComputedStyle(target).opacity").ExtractString());
+
+  view()->SetDisplayFeatureForTesting(base::nullopt);
+  host()->SynchronizeVisualProperties();
+
+  EXPECT_EQ(
+      "1px",
+      EvalJs(shell(), "getComputedStyle(target).marginTop").ExtractString());
+  EXPECT_EQ(
+      "1px",
+      EvalJs(shell(), "getComputedStyle(target).marginRight").ExtractString());
+  EXPECT_EQ(
+      "1px",
+      EvalJs(shell(), "getComputedStyle(target).marginBottom").ExtractString());
+  EXPECT_EQ(
+      "1px",
+      EvalJs(shell(), "getComputedStyle(target).marginLeft").ExtractString());
+  EXPECT_EQ("1px",
+            EvalJs(shell(), "getComputedStyle(target).width").ExtractString());
+  EXPECT_EQ("1px",
+            EvalJs(shell(), "getComputedStyle(target).height").ExtractString());
+
+  EXPECT_EQ(
+      "0.1",
+      EvalJs(shell(), "getComputedStyle(target).opacity").ExtractString());
+}
+
 class RenderWidgetHostDelegatedInkMetadataTest
     : public RenderWidgetHostTouchEmulatorBrowserTest {
  public:
diff --git a/content/browser/tracing/background_tracing_manager_impl.cc b/content/browser/tracing/background_tracing_manager_impl.cc
index 42225d2d..1ab8ed8 100644
--- a/content/browser/tracing/background_tracing_manager_impl.cc
+++ b/content/browser/tracing/background_tracing_manager_impl.cc
@@ -130,9 +130,15 @@
 #if defined(OS_ANDROID)
   config_impl = BackgroundReachedCodeTracingObserver::GetInstance()
                     .IncludeReachedCodeConfigIfNeeded(std::move(config_impl));
+
+  if (BackgroundReachedCodeTracingObserver::GetInstance()
+          .enabled_in_current_session()) {
+    data_filtering = DataFiltering::ANONYMIZE_DATA;
+    RecordMetric(Metrics::REACHED_CODE_SCENARIO_TRIGGERED);
+  } else
 #endif
-  if (BackgroundStartupTracingObserver::GetInstance()
-          ->enabled_in_current_session()) {
+      if (BackgroundStartupTracingObserver::GetInstance()
+              ->enabled_in_current_session()) {
     // Anonymize data for startup tracing by default. We currently do not
     // support storing the config in preferences for next session.
     data_filtering = DataFiltering::ANONYMIZE_DATA;
diff --git a/content/browser/tracing/background_tracing_manager_impl.h b/content/browser/tracing/background_tracing_manager_impl.h
index 3725e2e..43548a14 100644
--- a/content/browser/tracing/background_tracing_manager_impl.h
+++ b/content/browser/tracing/background_tracing_manager_impl.h
@@ -86,6 +86,7 @@
     STARTUP_SCENARIO_TRIGGERED = 12,
     LARGE_UPLOAD_WAITING_TO_RETRY = 13,
     SYSTEM_TRIGGERED = 14,
+    REACHED_CODE_SCENARIO_TRIGGERED = 15,
     NUMBER_OF_BACKGROUND_TRACING_METRICS,
   };
   static void RecordMetric(Metrics metric);
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 1a7c573..7a843f5 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -451,6 +451,11 @@
 const base::Feature kProcessSharingWithStrictSiteInstances{
     "ProcessSharingWithStrictSiteInstances", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Tells the RenderFrameHost to send beforeunload messages on a different
+// local frame interface which will handle the messages at a higher priority.
+const base::Feature kHighPriorityBeforeUnload{
+    "HighPriorityBeforeUnload", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Under this flag bootstrap (aka startup) tasks will be prioritized. This flag
 // is used by various modules to determine whether special scheduling
 // arrangements need to be made to prioritize certain tasks.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 558dcf6..cb4b9bb 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -99,6 +99,7 @@
 CONTENT_EXPORT extern const base::Feature kPepper3DImageChromium;
 CONTENT_EXPORT extern const base::Feature kPepperCrossOriginRedirectRestriction;
 CONTENT_EXPORT extern const base::Feature kPreferCompositingToLCDText;
+CONTENT_EXPORT extern const base::Feature kHighPriorityBeforeUnload;
 CONTENT_EXPORT extern const base::Feature kPrioritizeBootstrapTasks;
 CONTENT_EXPORT extern const base::Feature kProactivelySwapBrowsingInstance;
 CONTENT_EXPORT extern const base::Feature
diff --git a/content/renderer/accessibility/ax_image_annotator.cc b/content/renderer/accessibility/ax_image_annotator.cc
index ffff4842..4290e3d 100644
--- a/content/renderer/accessibility/ax_image_annotator.cc
+++ b/content/renderer/accessibility/ax_image_annotator.cc
@@ -18,6 +18,8 @@
 #include "content/renderer/accessibility/ax_image_stopwords.h"
 #include "content/renderer/render_frame_impl.h"
 #include "crypto/sha2.h"
+#include "services/metrics/public/cpp/mojo_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 #include "third_party/blink/public/strings/grit/blink_strings.h"
 #include "third_party/blink/public/web/web_ax_object.h"
 #include "third_party/blink/public/web/web_document.h"
@@ -317,16 +319,20 @@
     return;
   }
 
+  bool has_ocr = false;
+  bool has_description = false;
   std::vector<std::string> contextualized_strings;
   for (const mojo::InlinedStructPtr<image_annotation::mojom::Annotation>&
            annotation : result->get_annotations()) {
     int message_id = 0;
     switch (annotation->type) {
       case image_annotation::mojom::AnnotationType::kOcr:
+        has_ocr = true;
         message_id = IDS_AX_IMAGE_ANNOTATION_OCR_CONTEXT;
         break;
       case image_annotation::mojom::AnnotationType::kCaption:
       case image_annotation::mojom::AnnotationType::kLabel:
+        has_description = true;
         message_id = IDS_AX_IMAGE_ANNOTATION_DESCRIPTION_CONTEXT;
         break;
     }
@@ -365,6 +371,18 @@
     return;
   }
 
+  ax::mojom::NameFrom name_from;
+  blink::WebVector<blink::WebAXObject> name_objects;
+  blink::WebString name = image.GetName(name_from, name_objects);
+  bool has_existing_label = !name.IsEmpty();
+
+  ukm::builders::Accessibility_ImageDescriptions(
+      render_accessibility_->GetMainDocument().GetUkmSourceId())
+      .SetOCR(has_ocr)
+      .SetDescription(has_description)
+      .SetImageAlreadyHasLabel(has_existing_label)
+      .Record(render_accessibility_->ukm_recorder());
+
   image_annotations_.at(image.AxID())
       .set_status(ax::mojom::ImageAnnotationStatus::kAnnotationSucceeded);
   // TODO(accessibility): join two sentences together in a more i18n-friendly
diff --git a/content/renderer/accessibility/render_accessibility_impl.h b/content/renderer/accessibility/render_accessibility_impl.h
index d0652414..05b1f05 100644
--- a/content/renderer/accessibility/render_accessibility_impl.h
+++ b/content/renderer/accessibility/render_accessibility_impl.h
@@ -148,6 +148,9 @@
   // Returns the page language.
   std::string GetLanguage();
 
+  // Access the UKM recorder.
+  ukm::MojoUkmRecorder* ukm_recorder() const { return ukm_recorder_.get(); }
+
  protected:
   // Send queued events from the renderer to the browser.
   void SendPendingAccessibilityEvents();
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 84e217f..d2cf0b54 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -137,11 +137,9 @@
 #include "ipc/ipc_message.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/data_url.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -1057,58 +1055,6 @@
   }
 }
 
-// TODO(lukasza): https://crbug.com/1098938: Remove this ad-hoc URLLoaderFactory
-// after the CHECKs below played their role in establishing that
-// CreateDefaultURLLoaderFactoryBundle is only used with opaque initiators.
-class FactoryWrapperToOnlyAllowOpaqueInitiators
-    : public network::mojom::URLLoaderFactory {
- public:
-  explicit FactoryWrapperToOnlyAllowOpaqueInitiators(
-      mojo::PendingRemote<network::mojom::URLLoaderFactory>
-          pending_factory_to_wrap)
-      : wrapped_factory_(std::move(pending_factory_to_wrap)) {}
-
-  ~FactoryWrapperToOnlyAllowOpaqueInitiators() override = default;
-
- private:
-  void CreateLoaderAndStart(
-      mojo::PendingReceiver<network::mojom::URLLoader> loader,
-      int32_t routing_id,
-      int32_t request_id,
-      uint32_t options,
-      const network::ResourceRequest& request,
-      mojo::PendingRemote<network::mojom::URLLoaderClient> client,
-      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
-      override {
-    CHECK(request.request_initiator.has_value());
-    CHECK(request.request_initiator.value().opaque());
-
-    if (!wrapped_factory_)
-      return;
-    wrapped_factory_->CreateLoaderAndStart(
-        std::move(loader), routing_id, request_id, options, request,
-        std::move(client), traffic_annotation);
-  }
-
-  void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
-      override {
-    if (!wrapped_factory_)
-      return;
-
-    mojo::PendingRemote<network::mojom::URLLoaderFactory>
-        cloned_wrapped_factory;
-    wrapped_factory_->Clone(
-        cloned_wrapped_factory.InitWithNewPipeAndPassReceiver());
-
-    mojo::StrongBinding<network::mojom::URLLoaderFactory>::Create(
-        std::make_unique<FactoryWrapperToOnlyAllowOpaqueInitiators>(
-            std::move(cloned_wrapped_factory)),
-        std::move(receiver));
-  }
-
-  mojo::Remote<network::mojom::URLLoaderFactory> wrapped_factory_;
-};
-
 // Asks RenderProcessHostImpl::CreateURLLoaderFactoryForRendererProcess in the
 // browser process for a URLLoaderFactory.
 //
@@ -1117,18 +1063,10 @@
 CreateDefaultURLLoaderFactory() {
   RenderThreadImpl* render_thread = RenderThreadImpl::current();
   DCHECK(render_thread);
-  mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_factory;
+  mojo::PendingRemote<network::mojom::URLLoaderFactory> factory_remote;
   ChildThread::Get()->BindHostReceiver(
-      pending_factory.InitWithNewPipeAndPassReceiver());
-
-  mojo::PendingRemote<network::mojom::URLLoaderFactory>
-      pending_asserting_factory;
-  mojo::StrongBinding<network::mojom::URLLoaderFactory>::Create(
-      std::make_unique<FactoryWrapperToOnlyAllowOpaqueInitiators>(
-          std::move(pending_factory)),
-      pending_asserting_factory.InitWithNewPipeAndPassReceiver());
-
-  return pending_asserting_factory;
+      factory_remote.InitWithNewPipeAndPassReceiver());
+  return factory_remote;
 }
 
 // Returns a non-null pointer to a URLLoaderFactory bundle that is not
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index f3b4253..6337b36b 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -693,26 +693,7 @@
 #if defined(OS_ANDROID)
   if (!command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode) &&
       media::MediaCodecUtil::IsMediaCodecAvailable()) {
-    bool accelerated_video_decode_blacklisted = false;
-    if (!command_line.HasSwitch(switches::kIgnoreGpuBlacklist)) {
-      int32_t major_version = 0, minor_version = 0, bugfix_version = 0;
-      base::SysInfo::OperatingSystemVersionNumbers(
-          &major_version, &minor_version, &bugfix_version);
-      if (major_version < 5) {
-        // Currently accelerated video decode is only blacklisted on
-        // Android older than Lollipop.
-        scoped_refptr<gpu::GpuChannelHost> gpu_channel_host =
-            EstablishGpuChannelSync();
-        if (!gpu_channel_host ||
-            gpu_channel_host->gpu_feature_info().status_values
-                    [gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE] !=
-                gpu::kGpuFeatureStatusEnabled) {
-          accelerated_video_decode_blacklisted = true;
-        }
-      }
-    }
-    if (!accelerated_video_decode_blacklisted)
-      media::EnablePlatformDecoderSupport();
+    media::EnablePlatformDecoderSupport();
   }
 #endif
 
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index cecd7a0b..5ceb511 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -291,7 +291,12 @@
                       }),
         PixelTestPage('pixel_video_backdrop_filter.html',
                       base_name + '_Video_BackdropFilter',
-                      test_rect=[0, 0, 240, 135]),
+                      test_rect=[0, 0, 240, 135],
+                      matching_algorithm=algo.SobelMatchingAlgorithm(
+                          max_different_pixels=1000,
+                          pixel_delta_threshold=20,
+                          edge_threshold=40,
+                          ignored_border_thickness=1)),
         PixelTestPage('pixel_webgl_premultiplied_alpha_false.html',
                       base_name + '_WebGL_PremultipliedAlpha_False',
                       test_rect=[0, 0, 150, 150]),
diff --git a/docs/android_build_instructions.md b/docs/android_build_instructions.md
index df0d7f3b..8cad7fc6 100644
--- a/docs/android_build_instructions.md
+++ b/docs/android_build_instructions.md
@@ -184,29 +184,27 @@
 feature to target 4 different versions using 4 different ninja targets:
 
 1. `chrome_public_apk` (ChromePublic.apk)
+   * Used for local development and tests (simpler than using bundle targets).
+   * Same configuration as chrome_modern_public_bundle.
+2. `chrome_modern_public_bundle` (MonochromePublic.aab)
    * `minSdkVersion=21` (Lollipop).
    * Uses [Crazy Linker](https://cs.chromium.org/chromium/src/base/android/linker/BUILD.gn?rcl=6bb29391a86f2be58c626170156cbfaa2cbc5c91&l=9).
-   * Stores libchrome.so uncompressed within the APK.
-     * This APK is bigger, but the installation size is smaller since there is
-       no need to extract the .so file.
-   * Historically known as "chrome_modern_public_apk".
-2. `monochrome_public_apk` (MonochromePublic.apk)
+   * Stores native library with "crazy." prefix to prevent extraction.
+3. `monochrome_public_bundle` (MonochromePublic.aab)
    * `minSdkVersion=24` (Nougat).
    * Contains both WebView and Chrome within the same APK.
-     * This APK is even bigger, but much smaller than SystemWebView.apk + ChromePublic.apk.
-   * Stores libmonochrome.so uncompressed within the APK.
+     * This bundle is larger than ChromeModern, but much smaller than SUM(SystemWebView, ChromeModern)
    * Does not use Crazy Linker (WebView requires system linker).
      * But system linker supports crazy linker features now anyways.
-3. `trichrome_chrome_bundle` and `trichrome_library_apk` (TrichromeChrome.aab and TrichromeLibrary.apk)
+4. `trichrome_chrome_bundle` and `trichrome_library_apk` (TrichromeChrome.aab and TrichromeLibrary.apk)
    * `minSdkVersion=Q` (Q).
    * TrichromeChrome contains only the Chrome code that is not shared with WebView.
-   * TrichromeLibrary contains the shared code and is a "static shared library APK", which must be installed prior to TrichromeChrome.
+   * TrichromeLibrary contains the shared code and is a "static shared library APK".
    * Stores libmonochrome.so uncompressed within TrichromeLibrary.apk.
-   * Does not use Crazy Linker (WebView requires system linker).
-     * But system linker supports crazy linker features now anyways.
+   * Uses `android_dlopen_ext` to load native libraries with shared RELRO's
 
-**Note**: These instructions use `chrome_public_apk`, but either of the other
-two targets can be substituted.
+**Note**: These instructions use `chrome_public_apk`, but any of the other
+targets can be substituted.
 
 **Note**: These targets are actually the open-source equivalents to the
 closed-source targets that get shipped to the Play Store.
diff --git a/docs/android_native_libraries.md b/docs/android_native_libraries.md
index ec3b23e..50096d3 100644
--- a/docs/android_native_libraries.md
+++ b/docs/android_native_libraries.md
@@ -5,13 +5,28 @@
 [TOC]
 
 ## Library Packaging
- * Android L & M (ChromePublic.apk):
-   * `libchrome.so` is stored uncompressed within the apk (with the name `crazy.libchrome.so` to avoid extraction).
-   * It is loaded directly from the apk (without extracting) by `mmap()`'ing it.
- * Android N, O & P (MonochromePublic.apk):
-   * `libmonochrome.so` is stored uncompressed (AndroidManifest.xml attribute disables extraction) and loaded directly from the apk (functionality now supported by the system linker).
- * Android Q (TrichromeChrome.aab+TrichromeLibrary.apk):
-   * `libmonochrome.so` is stored in the shared library apk (TrichromeLibrary.apk) instead of in the Chrome apk, so that it can be shared with TrichromeWebView. It's stored uncompressed and loaded directly from the apk the same way as on N-P. Trichrome uses the same native library as Monochrome, so it's still called `libmonochrome.so`.
+ * Android L & M (ChromeModernPublic.aab):
+   * `libchrome.so` is stored uncompressed within the apk (with the name
+     `crazy.libchrome.so` to avoid extraction).
+   * It is loaded directly from the apk via `libchromium_android_linker.so`.
+   * Only JNI_OnLoad is exported, since manual JNI registration is required
+     (see [//base/android/jni_generator/README.md]).
+ * Android N, O & P (MonochromePublic.aab):
+   * `libmonochrome.so` is stored uncompressed within the apk (an
+     AndroidManifest.xml attribute disables extraction).
+   * It is loaded directly from the apk by the system linker.
+   * It exports all JNI symbols and does not use explicit JNI registration.
+   * It is not loaded by `libchromium_android_linker.so` and relies on the
+     system's webview zygote for RELRO sharing.
+ * Android Q (TrichromeChrome.aab + TrichromeLibrary.apk):
+   * Trichrome uses the exact same native library as Monochrome:
+     `libmonochrome.so`.
+   * `libmonochrome.so` is stored in the shared library (TrichromeLibrary.apk)
+     so that it can be shared with TrichromeWebView.
+   * It is loaded by `libchromium_android_linker.so` using
+     `android_dlopen_ext()` to enable RELRO sharing.
+
+[//base/android/jni_generator/README.md]: /base/android/jni_generator/README.md
 
 ## Build Variants (eg. monochrome_64_32_apk)
 The packaging above extends to cover both 32-bit and 64-bit device
@@ -180,10 +195,15 @@
    * For renderer processes, the OS starts all Monochrome renderer processes by `fork()`ing the WebView zygote rather than the normal application zygote.
      * In this case, RELRO sharing would be redundant since the entire process' memory is shared with the zygote with copy-on-write semantics.
  * For Android Q+ (Trichrome):
-   * For non-renderer processes, TrichromeChrome no longer shares its RELRO data with WebView and no RELRO sharing occurs. TrichromeWebView works the same way as on Android N-P.
-   * For renderer processes, TrichromeChrome `fork()`s from a chrome-specific app zygote. `libmonochrome.so` is loaded in the zygote before `fork()`.
-     * Similar to O-P, app zygote provides copy-on-write memory semantics so RELRO sharing is redundant.
-   * For renderer processes, TrichromeWebView works the same way as on Android N-P.
+   * TrichromeWebView works the same way as on Android N-P.
+   * TrichromeChrome uses `android_dlopen_ext()` and `ASharedMemory_create()` to
+     perform RELRO sharing, and then relies on a subsequent call to
+     `System.loadLibrary()` to enable JNI method resolution without loading the
+     library a second time.
+   * For renderer processes, TrichromeChrome `fork()`s from a chrome-specific
+     app zygote. `libmonochrome.so` is loaded in the zygote before `fork()`.
+     * Similar to O-P, app zygote provides copy-on-write memory semantics so
+       RELRO sharing is redundant.
 
 ## Partitioned libraries
 Some Chrome code is placed in feature-specific libraries and delivered via
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index ca41086..511a8a7 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -428,6 +428,38 @@
   feature_flags_.gpu_memory_buffer_formats.Add(gfx::BufferFormat::RGBA_F16);
 }
 
+void FeatureInfo::EnableANGLEInstancedArrayIfPossible(
+    const gfx::ExtensionSet& extensions) {
+  if (!feature_flags_.angle_instanced_arrays) {
+    if (gfx::HasExtension(extensions, "GL_ANGLE_instanced_arrays") ||
+        (gfx::HasExtension(extensions, "GL_ARB_instanced_arrays") &&
+         gfx::HasExtension(extensions, "GL_ARB_draw_instanced")) ||
+        gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile) {
+      AddExtensionString("GL_ANGLE_instanced_arrays");
+      feature_flags_.angle_instanced_arrays = true;
+      validators_.vertex_attribute.AddValue(
+          GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
+    }
+  }
+}
+
+void FeatureInfo::EnableWEBGLMultiDrawIfPossible(
+    const gfx::ExtensionSet& extensions) {
+  if (!feature_flags_.webgl_multi_draw) {
+    if (!is_passthrough_cmd_decoder_ ||
+        gfx::HasExtension(extensions, "GL_ANGLE_multi_draw")) {
+      if (gfx::HasExtension(extensions, "GL_ANGLE_instanced_arrays") ||
+          feature_flags_.angle_instanced_arrays || gl_version_info_->is_es3 ||
+          gl_version_info_->is_desktop_core_profile) {
+        feature_flags_.webgl_multi_draw = true;
+        AddExtensionString("GL_WEBGL_multi_draw");
+
+        EnableANGLEInstancedArrayIfPossible(extensions);
+      }
+    }
+  }
+}
+
 void FeatureInfo::InitializeFeatures() {
   // Figure out what extensions to turn on.
   std::string extensions_string(gl::GetGLExtensionsFromCurrentContext());
@@ -1246,14 +1278,7 @@
         !have_arb_occlusion_query2;
   }
 
-  if (gfx::HasExtension(extensions, "GL_ANGLE_instanced_arrays") ||
-      (gfx::HasExtension(extensions, "GL_ARB_instanced_arrays") &&
-       gfx::HasExtension(extensions, "GL_ARB_draw_instanced")) ||
-      gl_version_info_->is_es3 || gl_version_info_->is_desktop_core_profile) {
-    AddExtensionString("GL_ANGLE_instanced_arrays");
-    feature_flags_.angle_instanced_arrays = true;
-    validators_.vertex_attribute.AddValue(GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
-  }
+  EnableANGLEInstancedArrayIfPossible(extensions);
 
   bool have_es2_draw_buffers_vendor_agnostic =
       gl_version_info_->is_desktop_core_profile ||
@@ -1628,16 +1653,7 @@
     feature_flags_.khr_robust_buffer_access_behavior = true;
   }
 
-  if (!is_passthrough_cmd_decoder_ ||
-      gfx::HasExtension(extensions, "GL_ANGLE_multi_draw")) {
-
-    if (gfx::HasExtension(extensions, "GL_ANGLE_instanced_arrays") ||
-        feature_flags_.angle_instanced_arrays || gl_version_info_->is_es3 ||
-        gl_version_info_->is_desktop_core_profile) {
-      feature_flags_.webgl_multi_draw = true;
-      AddExtensionString("GL_WEBGL_multi_draw");
-    }
-  }
+  EnableWEBGLMultiDrawIfPossible(extensions);
 
 #if defined(OS_MACOSX)
   if (is_passthrough_cmd_decoder_ &&
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index ac6c4d8e..86ac127 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -249,6 +249,9 @@
   void InitializeFeatures();
   void InitializeFloatAndHalfFloatFeatures(const gfx::ExtensionSet& extensions);
 
+  void EnableANGLEInstancedArrayIfPossible(const gfx::ExtensionSet& extensions);
+  void EnableWEBGLMultiDrawIfPossible(const gfx::ExtensionSet& extensions);
+
   bool initialized_ = false;
 
   Validators validators_;
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index 5f8d4190..f75f518f 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -1349,329 +1349,6 @@
   }
 }
 config_groups {
-  name: "cq-m83"
-  gerrit {
-    url: "https://chromium-review.googlesource.com"
-    projects {
-      name: "chromium/src"
-      ref_regexp: "refs/branch-heads/4103"
-    }
-  }
-  verifiers {
-    gerrit_cq_ability {
-      committer_list: "project-chromium-committers"
-      dry_run_access_list: "project-chromium-tryjob-access"
-    }
-    tryjob {
-      builders {
-        name: "chromium/try-m83/android-binary-size"
-      }
-      builders {
-        name: "chromium/try-m83/android-cronet-arm-dbg"
-        location_regexp: ".+/[+]/components/cronet/.+"
-        location_regexp: ".+/[+]/components/grpc_support/.+"
-        location_regexp: ".+/[+]/build/android/.+"
-        location_regexp: ".+/[+]/build/config/android/.+"
-        location_regexp_exclude: ".+/[+]/components/cronet/ios/.+"
-      }
-      builders {
-        name: "chromium/try-m83/android-lollipop-arm-rel"
-      }
-      builders {
-        name: "chromium/try-m83/android-marshmallow-arm64-rel"
-      }
-      builders {
-        name: "chromium/try-m83/android-pie-arm64-dbg"
-        location_regexp: ".+/[+]/chrome/android/features/vr/.+"
-        location_regexp: ".+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/chrome/android/javatests/src/org/chromium/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/third_party/gvr-android-sdk/.+"
-        location_regexp: ".+/[+]/third_party/arcore-android-sdk/.+"
-        location_regexp: ".+/[+]/third_party/arcore-android-sdk-client/.+"
-      }
-      builders {
-        name: "chromium/try-m83/android-pie-arm64-rel"
-      }
-      builders {
-        name: "chromium/try-m83/android_compile_dbg"
-      }
-      builders {
-        name: "chromium/try-m83/android_compile_x64_dbg"
-        location_regexp: ".+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/sandbox/linux/seccomp-bpf/.+"
-        location_regexp: ".+/[+]/sandbox/linux/seccomp-bpf-helpers/.+"
-        location_regexp: ".+/[+]/sandbox/linux/system_headers/.+"
-        location_regexp: ".+/[+]/sandbox/linux/tests/.+"
-        location_regexp: ".+/[+]/third_party/gvr-android-sdk/.+"
-      }
-      builders {
-        name: "chromium/try-m83/android_compile_x86_dbg"
-        location_regexp: ".+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/sandbox/linux/seccomp-bpf/.+"
-        location_regexp: ".+/[+]/sandbox/linux/seccomp-bpf-helpers/.+"
-        location_regexp: ".+/[+]/sandbox/linux/system_headers/.+"
-        location_regexp: ".+/[+]/sandbox/linux/tests/.+"
-        location_regexp: ".+/[+]/third_party/gvr-android-sdk/.+"
-      }
-      builders {
-        name: "chromium/try-m83/android_cronet"
-      }
-      builders {
-        name: "chromium/try-m83/android_optional_gpu_tests_rel"
-        location_regexp: ".+/[+]/cc/.+"
-        location_regexp: ".+/[+]/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/components/viz/.+"
-        location_regexp: ".+/[+]/content/test/gpu/.+"
-        location_regexp: ".+/[+]/gpu/.+"
-        location_regexp: ".+/[+]/media/audio/.+"
-        location_regexp: ".+/[+]/media/filters/.+"
-        location_regexp: ".+/[+]/media/gpu/.+"
-        location_regexp: ".+/[+]/services/viz/.+"
-        location_regexp: ".+/[+]/testing/trigger_scripts/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgl/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/platform/graphics/gpu/.+"
-        location_regexp: ".+/[+]/tools/clang/scripts/update.py"
-        location_regexp: ".+/[+]/ui/gl/.+"
-      }
-      builders {
-        name: "chromium/try-m83/cast_shell_android"
-      }
-      builders {
-        name: "chromium/try-m83/cast_shell_linux"
-      }
-      builders {
-        name: "chromium/try-m83/chromeos-amd64-generic-dbg"
-        location_regexp: ".+/[+]/content/gpu/.+"
-        location_regexp: ".+/[+]/media/.+"
-      }
-      builders {
-        name: "chromium/try-m83/chromeos-amd64-generic-rel"
-      }
-      builders {
-        name: "chromium/try-m83/chromeos-arm-generic-rel"
-      }
-      builders {
-        name: "chromium/try-m83/chromium_presubmit"
-        disable_reuse: true
-      }
-      builders {
-        name: "chromium/try-m83/closure_compilation"
-        location_regexp: ".+/[+]/third_party/closure_compiler/.+"
-      }
-      builders {
-        name: "chromium/try-m83/dawn-linux-x64-deps-rel"
-        location_regexp: ".+/[+]/gpu/.+"
-        location_regexp: ".+/[+]/testing/buildbot/chromium.dawn.json"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/external/wpt/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/wpt_internal/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/WebGPUExpectations"
-        location_regexp: ".+/[+]/third_party/dawn/.+"
-        location_regexp: ".+/[+]/tools/clang/scripts/update.py"
-        location_regexp: ".+/[+]/ui/gl/features.gni"
-      }
-      builders {
-        name: "chromium/try-m83/dawn-mac-x64-deps-rel"
-        location_regexp: ".+/[+]/gpu/.+"
-        location_regexp: ".+/[+]/testing/buildbot/chromium.dawn.json"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/external/wpt/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/wpt_internal/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/WebGPUExpectations"
-        location_regexp: ".+/[+]/third_party/dawn/.+"
-        location_regexp: ".+/[+]/tools/clang/scripts/update.py"
-        location_regexp: ".+/[+]/ui/gl/features.gni"
-      }
-      builders {
-        name: "chromium/try-m83/dawn-win10-x64-deps-rel"
-        location_regexp: ".+/[+]/gpu/.+"
-        location_regexp: ".+/[+]/testing/buildbot/chromium.dawn.json"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/external/wpt/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/wpt_internal/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/WebGPUExpectations"
-        location_regexp: ".+/[+]/third_party/dawn/.+"
-        location_regexp: ".+/[+]/tools/clang/scripts/update.py"
-        location_regexp: ".+/[+]/ui/gl/features.gni"
-      }
-      builders {
-        name: "chromium/try-m83/dawn-win10-x86-deps-rel"
-        location_regexp: ".+/[+]/gpu/.+"
-        location_regexp: ".+/[+]/testing/buildbot/chromium.dawn.json"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/external/wpt/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/wpt_internal/webgpu/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/WebGPUExpectations"
-        location_regexp: ".+/[+]/third_party/dawn/.+"
-        location_regexp: ".+/[+]/tools/clang/scripts/update.py"
-        location_regexp: ".+/[+]/ui/gl/features.gni"
-      }
-      builders {
-        name: "chromium/try-m83/fuchsia-arm64-cast"
-        location_regexp: ".+/[+]/chromecast/.+"
-      }
-      builders {
-        name: "chromium/try-m83/fuchsia-x64-cast"
-      }
-      builders {
-        name: "chromium/try-m83/fuchsia_arm64"
-      }
-      builders {
-        name: "chromium/try-m83/fuchsia_x64"
-      }
-      builders {
-        name: "chromium/try-m83/ios-simulator"
-      }
-      builders {
-        name: "chromium/try-m83/ios-simulator-cronet"
-        location_regexp: ".+/[+]/components/cronet/.+"
-        location_regexp: ".+/[+]/components/grpc_support/.+"
-        location_regexp: ".+/[+]/ios/.+"
-        location_regexp_exclude: ".+/[+]/components/cronet/android/.+"
-      }
-      builders {
-        name: "chromium/try-m83/ios-simulator-full-configs"
-        location_regexp: ".+/[+]/ios/.+"
-      }
-      builders {
-        name: "chromium/try-m83/linux-blink-rel"
-        location_regexp: ".+/[+]/cc/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/core/paint/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/core/svg/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/platform/graphics/.+"
-      }
-      builders {
-        name: "chromium/try-m83/linux-chromeos-compile-dbg"
-      }
-      builders {
-        name: "chromium/try-m83/linux-chromeos-rel"
-        cancel_stale: NO
-      }
-      builders {
-        name: "chromium/try-m83/linux-libfuzzer-asan-rel"
-      }
-      builders {
-        name: "chromium/try-m83/linux-ozone-rel"
-      }
-      builders {
-        name: "chromium/try-m83/linux-rel"
-      }
-      builders {
-        name: "chromium/try-m83/linux_chromium_asan_rel_ng"
-      }
-      builders {
-        name: "chromium/try-m83/linux_chromium_compile_dbg_ng"
-      }
-      builders {
-        name: "chromium/try-m83/linux_chromium_dbg_ng"
-        location_regexp: ".+/[+]/build/.*check_gn_headers.*"
-      }
-      builders {
-        name: "chromium/try-m83/linux_chromium_tsan_rel_ng"
-      }
-      builders {
-        name: "chromium/try-m83/linux_layout_tests_composite_after_paint"
-        location_regexp: ".+/[+]/third_party/blink/renderer/core/paint/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/core/svg/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/platform/graphics/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/.+"
-      }
-      builders {
-        name: "chromium/try-m83/linux_layout_tests_layout_ng_disabled"
-        location_regexp: ".+/[+]/third_party/blink/renderer/core/editing/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/core/layout/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/core/paint/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/core/svg/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/platform/fonts/shaping/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/platform/graphics/.+"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/FlagExpectations/disable-layout-ng"
-        location_regexp: ".+/[+]/third_party/blink/web_tests/flag-specific/disable-layout-ng/.+"
-      }
-      builders {
-        name: "chromium/try-m83/linux_optional_gpu_tests_rel"
-        location_regexp: ".+/[+]/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/content/test/gpu/.+"
-        location_regexp: ".+/[+]/gpu/.+"
-        location_regexp: ".+/[+]/media/audio/.+"
-        location_regexp: ".+/[+]/media/filters/.+"
-        location_regexp: ".+/[+]/media/gpu/.+"
-        location_regexp: ".+/[+]/testing/buildbot/chromium.gpu.fyi.json"
-        location_regexp: ".+/[+]/testing/trigger_scripts/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgl/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/platform/graphics/gpu/.+"
-        location_regexp: ".+/[+]/tools/clang/scripts/update.py"
-        location_regexp: ".+/[+]/ui/gl/.+"
-      }
-      builders {
-        name: "chromium/try-m83/linux_vr"
-        location_regexp: ".+/[+]/chrome/browser/vr/.+"
-      }
-      builders {
-        name: "chromium/try-m83/mac-rel"
-      }
-      builders {
-        name: "chromium/try-m83/mac_chromium_compile_dbg_ng"
-      }
-      builders {
-        name: "chromium/try-m83/mac_optional_gpu_tests_rel"
-        location_regexp: ".+/[+]/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/content/test/gpu/.+"
-        location_regexp: ".+/[+]/gpu/.+"
-        location_regexp: ".+/[+]/media/audio/.+"
-        location_regexp: ".+/[+]/media/filters/.+"
-        location_regexp: ".+/[+]/media/gpu/.+"
-        location_regexp: ".+/[+]/services/shape_detection/.+"
-        location_regexp: ".+/[+]/testing/buildbot/chromium.gpu.fyi.json"
-        location_regexp: ".+/[+]/testing/trigger_scripts/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgl/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/platform/graphics/gpu/.+"
-        location_regexp: ".+/[+]/tools/clang/scripts/update.py"
-        location_regexp: ".+/[+]/ui/gl/.+"
-      }
-      builders {
-        name: "chromium/try-m83/win-libfuzzer-asan-rel"
-        cancel_stale: NO
-      }
-      builders {
-        name: "chromium/try-m83/win10_chromium_x64_rel_ng"
-        cancel_stale: NO
-      }
-      builders {
-        name: "chromium/try-m83/win_chromium_compile_dbg_ng"
-        cancel_stale: NO
-      }
-      builders {
-        name: "chromium/try-m83/win_optional_gpu_tests_rel"
-        location_regexp: ".+/[+]/chrome/browser/vr/.+"
-        location_regexp: ".+/[+]/content/test/gpu/.+"
-        location_regexp: ".+/[+]/device/vr/.+"
-        location_regexp: ".+/[+]/gpu/.+"
-        location_regexp: ".+/[+]/media/audio/.+"
-        location_regexp: ".+/[+]/media/filters/.+"
-        location_regexp: ".+/[+]/media/gpu/.+"
-        location_regexp: ".+/[+]/testing/buildbot/chromium.gpu.fyi.json"
-        location_regexp: ".+/[+]/testing/trigger_scripts/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/vr/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgl/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/modules/xr/.+"
-        location_regexp: ".+/[+]/third_party/blink/renderer/platform/graphics/gpu/.+"
-        location_regexp: ".+/[+]/tools/clang/scripts/update.py"
-        location_regexp: ".+/[+]/ui/gl/.+"
-      }
-      retry_config {
-        single_quota: 1
-        global_quota: 2
-        failure_weight: 1
-        transient_failure_weight: 1
-        timeout_weight: 2
-      }
-    }
-  }
-}
-config_groups {
   name: "cq-m84"
   gerrit {
     url: "https://chromium-review.googlesource.com"
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index a8b5e56..364260a2 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -11824,2421 +11824,6 @@
   }
 }
 buckets {
-  name: "ci-m83"
-  acls {
-    role: WRITER
-    group: "google/luci-task-force@google.com"
-  }
-  acls {
-    group: "all"
-  }
-  acls {
-    role: SCHEDULER
-    group: "project-chromium-ci-schedulers"
-  }
-  swarming {
-    builders {
-      name: "Android Release (Nexus 5X)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.gpu\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Android WebView M (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Android WebView N (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Android WebView O (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Android WebView P (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Android arm Builder (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 14400
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Android arm64 Builder (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 14400
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Android x64 Builder (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 14400
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Android x86 Builder (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Cast Android (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Cast Linux"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":50,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Linux x64 DEPS Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Linux x64 DEPS Release (Intel HD 630)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Linux x64 DEPS Release (NVIDIA)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Mac x64 DEPS Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:Dawn Mac x64 DEPS Builder"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Mac x64 DEPS Release (AMD)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Mac x64 DEPS Release (Intel)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Win10 x64 DEPS Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Win10 x64 DEPS Release (Intel HD 630)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Win10 x64 DEPS Release (NVIDIA)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Win10 x86 DEPS Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Win10 x86 DEPS Release (Intel HD 630)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Dawn Win10 x86 DEPS Release (NVIDIA)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.dawn\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Fuchsia ARM64"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Fuchsia x64"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "GPU Linux Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.gpu\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "GPU Mac Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:GPU Mac Builder"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.gpu\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "GPU Win x64 Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.gpu\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux ASan LSan Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:1"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.memory\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux ASan LSan Tests (1)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.memory\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux ASan Tests (sandboxed)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.memory\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux Builder (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux Ozone Tester (Headless)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux Ozone Tester (Wayland)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux Ozone Tester (X11)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux Release (NVIDIA)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.gpu\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux TSan Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.memory\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux TSan Tests"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.memory\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux Tests"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"jobs\":500},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Linux Tests (dbg)(1)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:Mac Builder"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.14"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac Builder (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:Mac Builder (dbg)"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac Release (Intel)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.gpu\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac Retina Release (AMD)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.gpu\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac10.10 Tests"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac10.11 Tests"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac10.12 Tests"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac10.13 Tests"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac10.13 Tests (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Mac10.14 Tests"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Marshmallow 64 bit Tester"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Nougat Phone Tester"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Oreo Phone Tester"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "VR Linux"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.fyi\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 36000
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "WebKit Mac10.13 (retina)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Win 7 Tests x64 (1)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:Win 7 Tests x64 (1)"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows-7"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.win\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Win Builder (dbg)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:Win Builder (dbg)"
-      dimensions: "cores:32"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.win\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Win x64 Builder"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:Win x64 Builder"
-      dimensions: "cores:32"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.win\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Win10 Tests x64"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:Win10 Tests x64"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows-10"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.win\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Win10 Tests x64 1803"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:Win10 Tests x64 1803"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows-10"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.fyi\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 36000
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Win10 x64 Release (NVIDIA)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:2"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.gpu\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "Win7 Tests (dbg)(1)"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:Win7 Tests (dbg)(1)"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows-7"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.win\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-cronet-arm-dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-cronet-arm-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-cronet-kitkat-arm-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-cronet-lollipop-arm-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-lollipop-arm-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-marshmallow-arm64-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-pie-arm64-dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-pie-arm64-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.android\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "chromeos-amd64-generic-dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.chromiumos\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "chromeos-amd64-generic-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.chromiumos\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "chromeos-arm-generic-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.chromiumos\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "fuchsia-arm64-cast"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "fuchsia-x64-cast"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "ios-simulator"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:ios-simulator"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.15"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"ios/unified_builder_tester\",\"xcode_build_version\":\"11e146\"}"
-      execution_timeout_secs: 10800
-      caches {
-        name: "xcode_ios_11e146"
-        path: "xcode_ios_11e146.app"
-      }
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "ios-simulator-cronet"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:ios-simulator-cronet"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.15"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.fyi\",\"recipe\":\"chromium\",\"xcode_build_version\":\"11c29\"}"
-      execution_timeout_secs: 36000
-      caches {
-        name: "xcode_ios_11e146"
-        path: "xcode_ios_11e146.app"
-      }
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "ios-simulator-full-configs"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:ios-simulator-full-configs"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.15"
-      dimensions: "pool:luci.chromium.ci"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.mac\",\"recipe\":\"ios/unified_builder_tester\",\"xcode_build_version\":\"11e146\"}"
-      execution_timeout_secs: 10800
-      caches {
-        name: "xcode_ios_11e146"
-        path: "xcode_ios_11e146.app"
-      }
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux-chromeos-dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.chromiumos\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux-chromeos-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.chromiumos\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux-ozone-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":500,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.linux\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "mac-osxbeta-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/chromium_tests\":{\"bucketed_triggers\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"chromium.fyi\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 36000
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-      }
-    }
-  }
-}
-buckets {
   name: "ci-m84"
   acls {
     role: WRITER
@@ -30978,1887 +28563,6 @@
   }
 }
 buckets {
-  name: "try-m83"
-  acls {
-    role: WRITER
-    group: "service-account-chromium-tryserver"
-  }
-  acls {
-    group: "all"
-  }
-  acls {
-    role: SCHEDULER
-    identity: "user:findit-for-me@appspot.gserviceaccount.com"
-  }
-  acls {
-    role: SCHEDULER
-    identity: "user:tricium-prod@appspot.gserviceaccount.com"
-  }
-  acls {
-    role: SCHEDULER
-    group: "project-chromium-tryjob-access"
-  }
-  acls {
-    role: SCHEDULER
-    group: "service-account-chromeperf"
-  }
-  acls {
-    role: SCHEDULER
-    group: "service-account-cq"
-  }
-  swarming {
-    builders {
-      name: "android-binary-size"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"binary_size_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-cronet-arm-dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-lollipop-arm-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-marshmallow-arm64-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:16"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:1"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/code_coverage\":{\"use_java_coverage\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":300,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-pie-arm64-dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android-pie-arm64-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:16"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:1"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"jobs\":300,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android_compile_dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android_compile_x64_dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android_compile_x86_dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android_cronet"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "android_optional_gpu_tests_rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:android_optional_gpu_tests_rel"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 21600
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "cast_shell_android"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "cast_shell_linux"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "chromeos-amd64-generic-dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.chromiumos\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "chromeos-amd64-generic-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.chromiumos\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "chromeos-arm-generic-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.chromiumos\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "chromium_presubmit"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$depot_tools/presubmit\":{\"runhooks\":true,\"timeout_s\":480},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"presubmit\",\"repo_name\":\"chromium\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "closure_compilation"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"closure_compilation\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "dawn-linux-x64-deps-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:dawn-linux-x64-deps-rel"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.dawn\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "dawn-mac-x64-deps-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:dawn-mac-x64-deps-rel"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.dawn\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "dawn-win10-x64-deps-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:dawn-win10-x64-deps-rel"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.dawn\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "dawn-win10-x86-deps-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:dawn-win10-x86-deps-rel"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.dawn\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "fuchsia-arm64-cast"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "fuchsia-x64-cast"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "fuchsia_arm64"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "fuchsia_x64"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "ios-simulator"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:ios-simulator"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.15"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.mac\",\"recipe\":\"ios/try\",\"xcode_build_version\":\"11e146\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      caches {
-        name: "xcode_ios_11e146"
-        path: "xcode_ios_11e146.app"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "ios-simulator-cronet"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:ios-simulator-cronet"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.15"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.mac\",\"recipe\":\"chromium_trybot\",\"xcode_build_version\":\"11e146\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      caches {
-        name: "xcode_ios_11e146"
-        path: "xcode_ios_11e146.app"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "ios-simulator-full-configs"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:ios-simulator-full-configs"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.15"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.mac\",\"recipe\":\"ios/try\",\"xcode_build_version\":\"11e146\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      caches {
-        name: "xcode_ios_11e146"
-        path: "xcode_ios_11e146.app"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux-blink-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.blink\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux-chromeos-compile-dbg"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.chromiumos\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux-chromeos-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/code_coverage\":{\"use_clang_coverage\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.chromiumos\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux-libfuzzer-asan-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_libfuzzer_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux-ozone-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/code_coverage\":{\"use_clang_coverage\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux_chromium_asan_rel_ng"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:1"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux_chromium_compile_dbg_ng"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "builder"
-        path: "linux_debug"
-      }
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux_chromium_dbg_ng"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "builder"
-        path: "linux_debug"
-      }
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux_chromium_tsan_rel_ng"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux_layout_tests_composite_after_paint"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux_layout_tests_layout_ng_disabled"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux_optional_gpu_tests_rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:linux_optional_gpu_tests_rel"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 21600
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "linux_vr"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.linux\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "mac-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:1"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.mac\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "mac_chromium_compile_dbg_ng"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac-10.13"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:1"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.mac\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "mac_optional_gpu_tests_rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:mac_optional_gpu_tests_rel"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.mac\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 21600
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "win-libfuzzer-asan-rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:win-libfuzzer-asan-rel"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.win\",\"recipe\":\"chromium_libfuzzer_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "win10_chromium_x64_rel_ng"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows-10"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:1"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/code_coverage\":{\"use_clang_coverage\":true},\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.win\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "win_chromium_compile_dbg_ng"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows-10"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"jobs\":150,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.win\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-    builders {
-      name: "win_optional_gpu_tests_rel"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Windows-10"
-      dimensions: "pool:luci.chromium.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\"},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"mastername\":\"tryserver.chromium.win\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 21600
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-      }
-    }
-  }
-}
-buckets {
   name: "try-m84"
   acls {
     role: WRITER
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index a95c696..63ff21f 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -718,677 +718,6 @@
   }
 }
 consoles {
-  id: "main-m83"
-  name: "Chromium M83 Console"
-  repo_url: "https://chromium.googlesource.com/chromium/src"
-  refs: "regexp:refs/branch-heads/4103"
-  manifest_name: "REVISION"
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win x64 Builder"
-    category: "chromium.win|release|builder"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win 7 Tests x64 (1)"
-    category: "chromium.win|release|tester"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win10 Tests x64"
-    category: "chromium.win|release|tester"
-    short_name: "w10"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win Builder (dbg)"
-    category: "chromium.win|debug|builder"
-    short_name: "32"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win7 Tests (dbg)(1)"
-    category: "chromium.win|debug|tester"
-    short_name: "7"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac Builder"
-    category: "chromium.mac|release"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.10 Tests"
-    category: "chromium.mac|release"
-    short_name: "10"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.11 Tests"
-    category: "chromium.mac|release"
-    short_name: "11"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.12 Tests"
-    category: "chromium.mac|release"
-    short_name: "12"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.13 Tests"
-    category: "chromium.mac|release"
-    short_name: "13"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.14 Tests"
-    category: "chromium.mac|release"
-    short_name: "14"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/WebKit Mac10.13 (retina)"
-    category: "chromium.mac|release"
-    short_name: "ret"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac Builder (dbg)"
-    category: "chromium.mac|debug"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.13 Tests (dbg)"
-    category: "chromium.mac|debug"
-    short_name: "13"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/ios-simulator"
-    category: "chromium.mac|ios|default"
-    short_name: "sim"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/ios-simulator-full-configs"
-    category: "chromium.mac|ios|default"
-    short_name: "ful"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Builder"
-    category: "chromium.linux|release"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Tests"
-    category: "chromium.linux|release"
-    short_name: "tst"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/linux-ozone-rel"
-    category: "chromium.linux|release"
-    short_name: "ozo"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Builder (dbg)"
-    category: "chromium.linux|debug|builder"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Tests (dbg)(1)"
-    category: "chromium.linux|debug|tester"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Cast Linux"
-    category: "chromium.linux|cast"
-    short_name: "vid"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Fuchsia ARM64"
-    category: "chromium.linux|fuchsia|a64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/fuchsia-arm64-cast"
-    category: "chromium.linux|fuchsia|cast"
-    short_name: "a64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/fuchsia-x64-cast"
-    category: "chromium.linux|fuchsia|cast"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Fuchsia x64"
-    category: "chromium.linux|fuchsia|x64"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/linux-chromeos-rel"
-    category: "chromium.chromiumos|default"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/linux-chromeos-dbg"
-    category: "chromium.chromiumos|default"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/chromeos-arm-generic-rel"
-    category: "chromium.chromiumos|simple|release"
-    short_name: "arm"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/chromeos-amd64-generic-rel"
-    category: "chromium.chromiumos|simple|release|x64"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/chromeos-amd64-generic-dbg"
-    category: "chromium.chromiumos|simple|debug|x64"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-cronet-arm-dbg"
-    category: "chromium.android|cronet|arm"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-cronet-arm-rel"
-    category: "chromium.android|cronet|arm"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-cronet-kitkat-arm-rel"
-    category: "chromium.android|cronet|test"
-    short_name: "k"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-cronet-lollipop-arm-rel"
-    category: "chromium.android|cronet|test"
-    short_name: "l"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android arm Builder (dbg)"
-    category: "chromium.android|builder|arm"
-    short_name: "32"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android arm64 Builder (dbg)"
-    category: "chromium.android|builder|arm"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android x86 Builder (dbg)"
-    category: "chromium.android|builder|x86"
-    short_name: "32"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android x64 Builder (dbg)"
-    category: "chromium.android|builder|x86"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Marshmallow 64 bit Tester"
-    category: "chromium.android|tester|phone"
-    short_name: "M"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Nougat Phone Tester"
-    category: "chromium.android|tester|phone"
-    short_name: "N"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Oreo Phone Tester"
-    category: "chromium.android|tester|phone"
-    short_name: "O"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-pie-arm64-dbg"
-    category: "chromium.android|tester|phone"
-    short_name: "P"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android WebView M (dbg)"
-    category: "chromium.android|tester|webview"
-    short_name: "M"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android WebView N (dbg)"
-    category: "chromium.android|tester|webview"
-    short_name: "N"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android WebView O (dbg)"
-    category: "chromium.android|tester|webview"
-    short_name: "O"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android WebView P (dbg)"
-    category: "chromium.android|tester|webview"
-    short_name: "P"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-lollipop-arm-rel"
-    category: "chromium.android|on_cq"
-    short_name: "L"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-marshmallow-arm64-rel"
-    category: "chromium.android|on_cq"
-    short_name: "M"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-pie-arm64-rel"
-    category: "chromium.android|on_cq"
-    short_name: "P"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Cast Android (dbg)"
-    category: "chromium.android|on_cq"
-    short_name: "cst"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux TSan Builder"
-    category: "chromium.memory|linux|TSan v2"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux TSan Tests"
-    category: "chromium.memory|linux|TSan v2"
-    short_name: "tst"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux ASan LSan Builder"
-    category: "chromium.memory|linux|asan lsan"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux ASan LSan Tests (1)"
-    category: "chromium.memory|linux|asan lsan"
-    short_name: "tst"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux ASan Tests (sandboxed)"
-    category: "chromium.memory|linux|asan lsan"
-    short_name: "sbx"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Linux x64 DEPS Builder"
-    category: "chromium.dawn|DEPS|Linux|Builder"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Linux x64 DEPS Release (Intel HD 630)"
-    category: "chromium.dawn|DEPS|Linux|Intel"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Linux x64 DEPS Release (NVIDIA)"
-    category: "chromium.dawn|DEPS|Linux|Nvidia"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Mac x64 DEPS Builder"
-    category: "chromium.dawn|DEPS|Mac|Builder"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Mac x64 DEPS Release (AMD)"
-    category: "chromium.dawn|DEPS|Mac|AMD"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Mac x64 DEPS Release (Intel)"
-    category: "chromium.dawn|DEPS|Mac|Intel"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x86 DEPS Builder"
-    category: "chromium.dawn|DEPS|Windows|Builder"
-    short_name: "x86"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x64 DEPS Builder"
-    category: "chromium.dawn|DEPS|Windows|Builder"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x86 DEPS Release (Intel HD 630)"
-    category: "chromium.dawn|DEPS|Windows|Intel"
-    short_name: "x86"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x64 DEPS Release (Intel HD 630)"
-    category: "chromium.dawn|DEPS|Windows|Intel"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x86 DEPS Release (NVIDIA)"
-    category: "chromium.dawn|DEPS|Windows|Nvidia"
-    short_name: "x86"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x64 DEPS Release (NVIDIA)"
-    category: "chromium.dawn|DEPS|Windows|Nvidia"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/GPU Win x64 Builder"
-    category: "chromium.gpu|Windows"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win10 x64 Release (NVIDIA)"
-    category: "chromium.gpu|Windows"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/GPU Mac Builder"
-    category: "chromium.gpu|Mac"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac Release (Intel)"
-    category: "chromium.gpu|Mac"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac Retina Release (AMD)"
-    category: "chromium.gpu|Mac"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/GPU Linux Builder"
-    category: "chromium.gpu|Linux"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Release (NVIDIA)"
-    category: "chromium.gpu|Linux"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android Release (Nexus 5X)"
-    category: "chromium.gpu|Android"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/ios-simulator-cronet"
-    category: "chromium.fyi|cronet"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/mac-osxbeta-rel"
-    category: "chromium.fyi|mac"
-    short_name: "beta"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/VR Linux"
-    category: "chromium.fyi|linux"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Ozone Tester (Headless)"
-    category: "chromium.fyi|linux"
-    short_name: "loh"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Ozone Tester (Wayland)"
-    category: "chromium.fyi|linux"
-    short_name: "low"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Ozone Tester (X11)"
-    category: "chromium.fyi|linux"
-    short_name: "lox"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win10 Tests x64 1803"
-    category: "chromium.fyi|win10|1803"
-  }
-  header {
-    oncalls {
-      name: "Chromium"
-      url: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
-    }
-    oncalls {
-      name: "Android"
-      url: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-android-sheriff"
-    }
-    oncalls {
-      name: "iOS"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_ios.json"
-    }
-    oncalls {
-      name: "GPU"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_gpu.json"
-    }
-    oncalls {
-      name: "Angle"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_angle.json"
-    }
-    oncalls {
-      name: "Perf"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_perf.json"
-    }
-    oncalls {
-      name: "Perfbot"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_perfbot.json"
-    }
-    oncalls {
-      name: "Trooper"
-      url: "https://rota-ng.appspot.com/legacy/trooper.json"
-    }
-    links {
-      name: "Builds"
-      links {
-        text: "continuous"
-        url: "https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html"
-        alt: "Continuous browser snapshots"
-      }
-      links {
-        text: "symbols"
-        url: "https://www.chromium.org/developers/how-tos/debugging-on-windows"
-        alt: "Windows Symbols"
-      }
-      links {
-        text: "status"
-        url: "https://chromium-status.appspot.com/"
-        alt: "Current tree status"
-      }
-    }
-    links {
-      name: "Dashboards"
-      links {
-        text: "perf"
-        url: "https://chromeperf.appspot.com/"
-        alt: "Chrome perf dashboard"
-      }
-      links {
-        text: "flake-portal"
-        url: "https://analysis.chromium.org/p/chromium/flake-portal"
-        alt: "New flake portal"
-      }
-      links {
-        text: "legacy-flakiness"
-        url: "https://test-results.appspot.com/dashboards/flakiness_dashboard.html"
-        alt: "Legacy flakiness dashboard"
-      }
-    }
-    links {
-      name: "Chromium"
-      links {
-        text: "source"
-        url: "https://chromium.googlesource.com/chromium/src"
-        alt: "Chromium source code repository"
-      }
-      links {
-        text: "reviews"
-        url: "https://chromium-review.googlesource.com"
-        alt: "Chromium code review tool"
-      }
-      links {
-        text: "bugs"
-        url: "https://crbug.com"
-        alt: "Chromium bug tracker"
-      }
-      links {
-        text: "coverage"
-        url: "https://analysis.chromium.org/p/chromium/coverage"
-        alt: "Chromium code coverage dashboard"
-      }
-      links {
-        text: "dev"
-        url: "https://dev.chromium.org/Home"
-        alt: "Chromium developer home page"
-      }
-      links {
-        text: "support"
-        url: "https://support.google.com/chrome/#topic=7438008"
-        alt: "Google Chrome help center"
-      }
-    }
-    links {
-      name: "Consoles"
-      links {
-        text: "android"
-        url: "/p/chromium/g/chromium.android"
-        alt: "Chromium Android console"
-      }
-      links {
-        text: "clang"
-        url: "/p/chromium/g/chromium.clang"
-        alt: "Chromium Clang console"
-      }
-      links {
-        text: "dawn"
-        url: "/p/chromium/g/chromium.dawn"
-        alt: "Chromium Dawn console"
-      }
-      links {
-        text: "fuzz"
-        url: "/p/chromium/g/chromium.fuzz"
-        alt: "Chromium Fuzz console"
-      }
-      links {
-        text: "fyi"
-        url: "/p/chromium/g/chromium.fyi"
-        alt: "Chromium FYI console"
-      }
-      links {
-        text: "gpu"
-        url: "/p/chromium/g/chromium.gpu"
-        alt: "Chromium GPU console"
-      }
-      links {
-        text: "perf"
-        url: "/p/chrome/g/chrome.perf/console"
-        alt: "Chromium Perf console"
-      }
-      links {
-        text: "perf.fyi"
-        url: "/p/chrome/g/chrome.perf.fyi/console"
-        alt: "Chromium Perf FYI console"
-      }
-      links {
-        text: "swangle"
-        url: "/p/chromium/g/chromium.swangle"
-        alt: "Chromium SWANGLE console"
-      }
-      links {
-        text: "webrtc"
-        url: "/p/chromium/g/chromium.webrtc"
-        alt: "Chromium WebRTC console"
-      }
-      links {
-        text: "chromiumos"
-        url: "/p/chromium/g/chromium.chromiumos"
-        alt: "ChromiumOS console"
-      }
-    }
-    links {
-      name: "Branch Consoles"
-      links {
-        text: "m85"
-        url: "/p/chromium/g/main-m85/console"
-        alt: "Beta branch console"
-      }
-      links {
-        text: "m84"
-        url: "/p/chromium/g/main-m84/console"
-        alt: "Stable branch console"
-      }
-      links {
-        text: "trunk"
-        url: "/p/chromium/g/main/console"
-        alt: "Trunk (ToT) console"
-      }
-    }
-    links {
-      name: "Tryservers"
-      links {
-        text: "android"
-        url: "/p/chromium/g/tryserver.chromium.android/builders"
-        alt: "Android"
-      }
-      links {
-        text: "angle"
-        url: "/p/chromium/g/tryserver.chromium.angle/builders"
-        alt: "Angle"
-      }
-      links {
-        text: "blink"
-        url: "/p/chromium/g/tryserver.blink/builders"
-        alt: "Blink"
-      }
-      links {
-        text: "chrome"
-        url: "/p/chrome/g/tryserver.chrome/builders"
-        alt: "Chrome"
-      }
-      links {
-        text: "chromiumos"
-        url: "/p/chromium/g/tryserver.chromium.chromiumos/builders"
-        alt: "ChromiumOS"
-      }
-      links {
-        text: "linux"
-        url: "/p/chromium/g/tryserver.chromium.linux/builders"
-        alt: "Linux"
-      }
-      links {
-        text: "mac"
-        url: "/p/chromium/g/tryserver.chromium.mac/builders"
-        alt: "Mac"
-      }
-      links {
-        text: "swangle"
-        url: "/p/chromium/g/tryserver.chromium.swangle/builders"
-        alt: "SWANGLE"
-      }
-      links {
-        text: "win"
-        url: "/p/chromium/g/tryserver.chromium.win/builders"
-        alt: "Win"
-      }
-    }
-    links {
-      name: "Navigate"
-      links {
-        text: "about"
-        url: "http://dev.chromium.org/developers/testing/chromium-build-infrastructure/tour-of-the-chromium-buildbot"
-        alt: "Tour of the console"
-      }
-      links {
-        text: "customize"
-        url: "https://chromium.googlesource.com/chromium/src/+/master/infra/config/luci-milo.cfg"
-        alt: "Customize this console"
-      }
-    }
-    console_groups {
-      title {
-        text: "Tree Closers"
-        url: "https://chromium-status.appspot.com/"
-      }
-      console_ids: "chromium/chromium"
-      console_ids: "chromium/chromium.win"
-      console_ids: "chromium/chromium.mac"
-      console_ids: "chromium/chromium.linux"
-      console_ids: "chromium/chromium.chromiumos"
-      console_ids: "chrome/chrome"
-      console_ids: "chromium/chromium.memory"
-      console_ids: "chromium/chromium.gpu"
-    }
-    console_groups {
-      console_ids: "chromium/chromium.android"
-      console_ids: "chrome/chrome.perf"
-      console_ids: "chromium/chromium.gpu.fyi"
-      console_ids: "chromium/chromium.fuzz"
-    }
-    tree_status_host: "chromium-status.appspot.com"
-  }
-}
-consoles {
   id: "main-m84"
   name: "Chromium M84 Console"
   repo_url: "https://chromium.googlesource.com/chromium/src"
@@ -3465,677 +2794,6 @@
   }
 }
 consoles {
-  id: "mirrors-m83"
-  name: "Chromium M83 CQ Mirrors Console"
-  repo_url: "https://chromium.googlesource.com/chromium/src"
-  refs: "regexp:refs/branch-heads/4103"
-  manifest_name: "REVISION"
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win x64 Builder"
-    category: "chromium.win|release|builder"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win 7 Tests x64 (1)"
-    category: "chromium.win|release|tester"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win10 Tests x64"
-    category: "chromium.win|release|tester"
-    short_name: "w10"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win Builder (dbg)"
-    category: "chromium.win|debug|builder"
-    short_name: "32"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win7 Tests (dbg)(1)"
-    category: "chromium.win|debug|tester"
-    short_name: "7"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac Builder"
-    category: "chromium.mac|release"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.10 Tests"
-    category: "chromium.mac|release"
-    short_name: "10"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.11 Tests"
-    category: "chromium.mac|release"
-    short_name: "11"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.12 Tests"
-    category: "chromium.mac|release"
-    short_name: "12"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.13 Tests"
-    category: "chromium.mac|release"
-    short_name: "13"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.14 Tests"
-    category: "chromium.mac|release"
-    short_name: "14"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/WebKit Mac10.13 (retina)"
-    category: "chromium.mac|release"
-    short_name: "ret"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac Builder (dbg)"
-    category: "chromium.mac|debug"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac10.13 Tests (dbg)"
-    category: "chromium.mac|debug"
-    short_name: "13"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/ios-simulator"
-    category: "chromium.mac|ios|default"
-    short_name: "sim"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/ios-simulator-full-configs"
-    category: "chromium.mac|ios|default"
-    short_name: "ful"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Builder"
-    category: "chromium.linux|release"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Tests"
-    category: "chromium.linux|release"
-    short_name: "tst"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/linux-ozone-rel"
-    category: "chromium.linux|release"
-    short_name: "ozo"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Builder (dbg)"
-    category: "chromium.linux|debug|builder"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Tests (dbg)(1)"
-    category: "chromium.linux|debug|tester"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Cast Linux"
-    category: "chromium.linux|cast"
-    short_name: "vid"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Fuchsia ARM64"
-    category: "chromium.linux|fuchsia|a64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/fuchsia-arm64-cast"
-    category: "chromium.linux|fuchsia|cast"
-    short_name: "a64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/fuchsia-x64-cast"
-    category: "chromium.linux|fuchsia|cast"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Fuchsia x64"
-    category: "chromium.linux|fuchsia|x64"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/linux-chromeos-rel"
-    category: "chromium.chromiumos|default"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/linux-chromeos-dbg"
-    category: "chromium.chromiumos|default"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/chromeos-arm-generic-rel"
-    category: "chromium.chromiumos|simple|release"
-    short_name: "arm"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/chromeos-amd64-generic-rel"
-    category: "chromium.chromiumos|simple|release|x64"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/chromeos-amd64-generic-dbg"
-    category: "chromium.chromiumos|simple|debug|x64"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-cronet-arm-dbg"
-    category: "chromium.android|cronet|arm"
-    short_name: "dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-cronet-arm-rel"
-    category: "chromium.android|cronet|arm"
-    short_name: "rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-cronet-kitkat-arm-rel"
-    category: "chromium.android|cronet|test"
-    short_name: "k"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-cronet-lollipop-arm-rel"
-    category: "chromium.android|cronet|test"
-    short_name: "l"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android arm Builder (dbg)"
-    category: "chromium.android|builder|arm"
-    short_name: "32"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android arm64 Builder (dbg)"
-    category: "chromium.android|builder|arm"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android x86 Builder (dbg)"
-    category: "chromium.android|builder|x86"
-    short_name: "32"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android x64 Builder (dbg)"
-    category: "chromium.android|builder|x86"
-    short_name: "64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Marshmallow 64 bit Tester"
-    category: "chromium.android|tester|phone"
-    short_name: "M"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Nougat Phone Tester"
-    category: "chromium.android|tester|phone"
-    short_name: "N"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Oreo Phone Tester"
-    category: "chromium.android|tester|phone"
-    short_name: "O"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-pie-arm64-dbg"
-    category: "chromium.android|tester|phone"
-    short_name: "P"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android WebView M (dbg)"
-    category: "chromium.android|tester|webview"
-    short_name: "M"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android WebView N (dbg)"
-    category: "chromium.android|tester|webview"
-    short_name: "N"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android WebView O (dbg)"
-    category: "chromium.android|tester|webview"
-    short_name: "O"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android WebView P (dbg)"
-    category: "chromium.android|tester|webview"
-    short_name: "P"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-lollipop-arm-rel"
-    category: "chromium.android|on_cq"
-    short_name: "L"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-marshmallow-arm64-rel"
-    category: "chromium.android|on_cq"
-    short_name: "M"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/android-pie-arm64-rel"
-    category: "chromium.android|on_cq"
-    short_name: "P"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Cast Android (dbg)"
-    category: "chromium.android|on_cq"
-    short_name: "cst"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux TSan Builder"
-    category: "chromium.memory|linux|TSan v2"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux TSan Tests"
-    category: "chromium.memory|linux|TSan v2"
-    short_name: "tst"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux ASan LSan Builder"
-    category: "chromium.memory|linux|asan lsan"
-    short_name: "bld"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux ASan LSan Tests (1)"
-    category: "chromium.memory|linux|asan lsan"
-    short_name: "tst"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux ASan Tests (sandboxed)"
-    category: "chromium.memory|linux|asan lsan"
-    short_name: "sbx"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Linux x64 DEPS Builder"
-    category: "chromium.dawn|DEPS|Linux|Builder"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Linux x64 DEPS Release (Intel HD 630)"
-    category: "chromium.dawn|DEPS|Linux|Intel"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Linux x64 DEPS Release (NVIDIA)"
-    category: "chromium.dawn|DEPS|Linux|Nvidia"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Mac x64 DEPS Builder"
-    category: "chromium.dawn|DEPS|Mac|Builder"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Mac x64 DEPS Release (AMD)"
-    category: "chromium.dawn|DEPS|Mac|AMD"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Mac x64 DEPS Release (Intel)"
-    category: "chromium.dawn|DEPS|Mac|Intel"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x86 DEPS Builder"
-    category: "chromium.dawn|DEPS|Windows|Builder"
-    short_name: "x86"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x64 DEPS Builder"
-    category: "chromium.dawn|DEPS|Windows|Builder"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x86 DEPS Release (Intel HD 630)"
-    category: "chromium.dawn|DEPS|Windows|Intel"
-    short_name: "x86"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x64 DEPS Release (Intel HD 630)"
-    category: "chromium.dawn|DEPS|Windows|Intel"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x86 DEPS Release (NVIDIA)"
-    category: "chromium.dawn|DEPS|Windows|Nvidia"
-    short_name: "x86"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Dawn Win10 x64 DEPS Release (NVIDIA)"
-    category: "chromium.dawn|DEPS|Windows|Nvidia"
-    short_name: "x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/GPU Win x64 Builder"
-    category: "chromium.gpu|Windows"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win10 x64 Release (NVIDIA)"
-    category: "chromium.gpu|Windows"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/GPU Mac Builder"
-    category: "chromium.gpu|Mac"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac Release (Intel)"
-    category: "chromium.gpu|Mac"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Mac Retina Release (AMD)"
-    category: "chromium.gpu|Mac"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/GPU Linux Builder"
-    category: "chromium.gpu|Linux"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Release (NVIDIA)"
-    category: "chromium.gpu|Linux"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Android Release (Nexus 5X)"
-    category: "chromium.gpu|Android"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/ios-simulator-cronet"
-    category: "chromium.fyi|cronet"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/mac-osxbeta-rel"
-    category: "chromium.fyi|mac"
-    short_name: "beta"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/VR Linux"
-    category: "chromium.fyi|linux"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Ozone Tester (Headless)"
-    category: "chromium.fyi|linux"
-    short_name: "loh"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Ozone Tester (Wayland)"
-    category: "chromium.fyi|linux"
-    short_name: "low"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Linux Ozone Tester (X11)"
-    category: "chromium.fyi|linux"
-    short_name: "lox"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci-m83/Win10 Tests x64 1803"
-    category: "chromium.fyi|win10|1803"
-  }
-  header {
-    oncalls {
-      name: "Chromium"
-      url: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
-    }
-    oncalls {
-      name: "Android"
-      url: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-android-sheriff"
-    }
-    oncalls {
-      name: "iOS"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_ios.json"
-    }
-    oncalls {
-      name: "GPU"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_gpu.json"
-    }
-    oncalls {
-      name: "Angle"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_angle.json"
-    }
-    oncalls {
-      name: "Perf"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_perf.json"
-    }
-    oncalls {
-      name: "Perfbot"
-      url: "https://rota-ng.appspot.com/legacy/sheriff_perfbot.json"
-    }
-    oncalls {
-      name: "Trooper"
-      url: "https://rota-ng.appspot.com/legacy/trooper.json"
-    }
-    links {
-      name: "Builds"
-      links {
-        text: "continuous"
-        url: "https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html"
-        alt: "Continuous browser snapshots"
-      }
-      links {
-        text: "symbols"
-        url: "https://www.chromium.org/developers/how-tos/debugging-on-windows"
-        alt: "Windows Symbols"
-      }
-      links {
-        text: "status"
-        url: "https://chromium-status.appspot.com/"
-        alt: "Current tree status"
-      }
-    }
-    links {
-      name: "Dashboards"
-      links {
-        text: "perf"
-        url: "https://chromeperf.appspot.com/"
-        alt: "Chrome perf dashboard"
-      }
-      links {
-        text: "flake-portal"
-        url: "https://analysis.chromium.org/p/chromium/flake-portal"
-        alt: "New flake portal"
-      }
-      links {
-        text: "legacy-flakiness"
-        url: "https://test-results.appspot.com/dashboards/flakiness_dashboard.html"
-        alt: "Legacy flakiness dashboard"
-      }
-    }
-    links {
-      name: "Chromium"
-      links {
-        text: "source"
-        url: "https://chromium.googlesource.com/chromium/src"
-        alt: "Chromium source code repository"
-      }
-      links {
-        text: "reviews"
-        url: "https://chromium-review.googlesource.com"
-        alt: "Chromium code review tool"
-      }
-      links {
-        text: "bugs"
-        url: "https://crbug.com"
-        alt: "Chromium bug tracker"
-      }
-      links {
-        text: "coverage"
-        url: "https://analysis.chromium.org/p/chromium/coverage"
-        alt: "Chromium code coverage dashboard"
-      }
-      links {
-        text: "dev"
-        url: "https://dev.chromium.org/Home"
-        alt: "Chromium developer home page"
-      }
-      links {
-        text: "support"
-        url: "https://support.google.com/chrome/#topic=7438008"
-        alt: "Google Chrome help center"
-      }
-    }
-    links {
-      name: "Consoles"
-      links {
-        text: "android"
-        url: "/p/chromium/g/chromium.android"
-        alt: "Chromium Android console"
-      }
-      links {
-        text: "clang"
-        url: "/p/chromium/g/chromium.clang"
-        alt: "Chromium Clang console"
-      }
-      links {
-        text: "dawn"
-        url: "/p/chromium/g/chromium.dawn"
-        alt: "Chromium Dawn console"
-      }
-      links {
-        text: "fuzz"
-        url: "/p/chromium/g/chromium.fuzz"
-        alt: "Chromium Fuzz console"
-      }
-      links {
-        text: "fyi"
-        url: "/p/chromium/g/chromium.fyi"
-        alt: "Chromium FYI console"
-      }
-      links {
-        text: "gpu"
-        url: "/p/chromium/g/chromium.gpu"
-        alt: "Chromium GPU console"
-      }
-      links {
-        text: "perf"
-        url: "/p/chrome/g/chrome.perf/console"
-        alt: "Chromium Perf console"
-      }
-      links {
-        text: "perf.fyi"
-        url: "/p/chrome/g/chrome.perf.fyi/console"
-        alt: "Chromium Perf FYI console"
-      }
-      links {
-        text: "swangle"
-        url: "/p/chromium/g/chromium.swangle"
-        alt: "Chromium SWANGLE console"
-      }
-      links {
-        text: "webrtc"
-        url: "/p/chromium/g/chromium.webrtc"
-        alt: "Chromium WebRTC console"
-      }
-      links {
-        text: "chromiumos"
-        url: "/p/chromium/g/chromium.chromiumos"
-        alt: "ChromiumOS console"
-      }
-    }
-    links {
-      name: "Branch Consoles"
-      links {
-        text: "m85"
-        url: "/p/chromium/g/main-m85/console"
-        alt: "Beta branch console"
-      }
-      links {
-        text: "m84"
-        url: "/p/chromium/g/main-m84/console"
-        alt: "Stable branch console"
-      }
-      links {
-        text: "trunk"
-        url: "/p/chromium/g/main/console"
-        alt: "Trunk (ToT) console"
-      }
-    }
-    links {
-      name: "Tryservers"
-      links {
-        text: "android"
-        url: "/p/chromium/g/tryserver.chromium.android/builders"
-        alt: "Android"
-      }
-      links {
-        text: "angle"
-        url: "/p/chromium/g/tryserver.chromium.angle/builders"
-        alt: "Angle"
-      }
-      links {
-        text: "blink"
-        url: "/p/chromium/g/tryserver.blink/builders"
-        alt: "Blink"
-      }
-      links {
-        text: "chrome"
-        url: "/p/chrome/g/tryserver.chrome/builders"
-        alt: "Chrome"
-      }
-      links {
-        text: "chromiumos"
-        url: "/p/chromium/g/tryserver.chromium.chromiumos/builders"
-        alt: "ChromiumOS"
-      }
-      links {
-        text: "linux"
-        url: "/p/chromium/g/tryserver.chromium.linux/builders"
-        alt: "Linux"
-      }
-      links {
-        text: "mac"
-        url: "/p/chromium/g/tryserver.chromium.mac/builders"
-        alt: "Mac"
-      }
-      links {
-        text: "swangle"
-        url: "/p/chromium/g/tryserver.chromium.swangle/builders"
-        alt: "SWANGLE"
-      }
-      links {
-        text: "win"
-        url: "/p/chromium/g/tryserver.chromium.win/builders"
-        alt: "Win"
-      }
-    }
-    links {
-      name: "Navigate"
-      links {
-        text: "about"
-        url: "http://dev.chromium.org/developers/testing/chromium-build-infrastructure/tour-of-the-chromium-buildbot"
-        alt: "Tour of the console"
-      }
-      links {
-        text: "customize"
-        url: "https://chromium.googlesource.com/chromium/src/+/master/infra/config/luci-milo.cfg"
-        alt: "Customize this console"
-      }
-    }
-    console_groups {
-      title {
-        text: "Tree Closers"
-        url: "https://chromium-status.appspot.com/"
-      }
-      console_ids: "chromium/chromium"
-      console_ids: "chromium/chromium.win"
-      console_ids: "chromium/chromium.mac"
-      console_ids: "chromium/chromium.linux"
-      console_ids: "chromium/chromium.chromiumos"
-      console_ids: "chrome/chrome"
-      console_ids: "chromium/chromium.memory"
-      console_ids: "chromium/chromium.gpu"
-    }
-    console_groups {
-      console_ids: "chromium/chromium.android"
-      console_ids: "chrome/chrome.perf"
-      console_ids: "chromium/chromium.gpu.fyi"
-      console_ids: "chromium/chromium.fuzz"
-    }
-    tree_status_host: "chromium-status.appspot.com"
-  }
-}
-consoles {
   id: "mirrors-m84"
   name: "Chromium M84 CQ Mirrors Console"
   repo_url: "https://chromium.googlesource.com/chromium/src"
@@ -5989,161 +4647,6 @@
   builder_view_only: true
 }
 consoles {
-  id: "try-m83"
-  name: "Chromium M83 CQ console"
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android-binary-size"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android-cronet-arm-dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android-lollipop-arm-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android-marshmallow-arm64-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android-pie-arm64-dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android-pie-arm64-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android_compile_dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android_compile_x64_dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android_compile_x86_dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android_cronet"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/android_optional_gpu_tests_rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/cast_shell_android"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/cast_shell_linux"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/chromeos-amd64-generic-dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/chromeos-amd64-generic-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/chromeos-arm-generic-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/chromium_presubmit"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/closure_compilation"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/dawn-linux-x64-deps-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/dawn-mac-x64-deps-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/dawn-win10-x64-deps-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/dawn-win10-x86-deps-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/fuchsia-arm64-cast"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/fuchsia-x64-cast"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/fuchsia_arm64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/fuchsia_x64"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/ios-simulator"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/ios-simulator-cronet"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/ios-simulator-full-configs"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux-blink-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux-chromeos-compile-dbg"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux-chromeos-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux-libfuzzer-asan-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux-ozone-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux_chromium_asan_rel_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux_chromium_compile_dbg_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux_chromium_dbg_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux_chromium_tsan_rel_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux_layout_tests_composite_after_paint"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux_layout_tests_layout_ng_disabled"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux_optional_gpu_tests_rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/linux_vr"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/mac-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/mac_chromium_compile_dbg_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/mac_optional_gpu_tests_rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/win-libfuzzer-asan-rel"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/win10_chromium_x64_rel_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/win_chromium_compile_dbg_ng"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.try-m83/win_optional_gpu_tests_rel"
-  }
-  builder_view_only: true
-}
-consoles {
   id: "try-m84"
   name: "Chromium M84 CQ console"
   builders {
diff --git a/infra/config/generated/luci-notify.cfg b/infra/config/generated/luci-notify.cfg
index 1a0b219b..908b2bd2 100644
--- a/infra/config/generated/luci-notify.cfg
+++ b/infra/config/generated/luci-notify.cfg
@@ -2044,766 +2044,6 @@
     }
   }
   builders {
-    bucket: "ci-m83"
-    name: "Android Release (Nexus 5X)"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Cast Linux"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  notifications {
-    on_change: true
-    email {
-      recipients: "cr-fuchsia+bot@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Fuchsia ARM64"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  notifications {
-    on_change: true
-    email {
-      recipients: "cr-fuchsia+bot@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Fuchsia x64"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+gpu-test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "GPU Linux Builder"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+gpu-test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "GPU Mac Builder"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+gpu-test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "GPU Win x64 Builder"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux ASan LSan Builder"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux ASan LSan Tests (1)"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux ASan Tests (sandboxed)"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux Builder"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux Builder (dbg)"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux Ozone Tester (Headless)"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux Ozone Tester (Wayland)"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux Ozone Tester (X11)"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+gpu-test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux Release (NVIDIA)"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux TSan Builder"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux TSan Tests"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux Tests"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Linux Tests (dbg)(1)"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+gpu-test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Mac Release (Intel)"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+gpu-test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Mac Retina Release (AMD)"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+gpu-test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "Win10 x64 Release (NVIDIA)"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_change: true
-    email {
-      recipients: "cronet-bots-observer@google.com"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "android-cronet-arm-dbg"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-}
-notifiers {
-  notifications {
-    on_change: true
-    email {
-      recipients: "cronet-bots-observer@google.com"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "android-cronet-arm-rel"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-}
-notifiers {
-  notifications {
-    on_change: true
-    email {
-      recipients: "cronet-bots-observer@google.com"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "android-cronet-kitkat-arm-rel"
-  }
-}
-notifiers {
-  notifications {
-    on_change: true
-    email {
-      recipients: "cronet-bots-observer@google.com"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "android-cronet-lollipop-arm-rel"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "chromeos-amd64-generic-dbg"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "chromeos-amd64-generic-rel"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "chromeos-arm-generic-rel"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  notifications {
-    on_change: true
-    email {
-      recipients: "cr-fuchsia+bot@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "fuchsia-arm64-cast"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  notifications {
-    on_change: true
-    email {
-      recipients: "cr-fuchsia+bot@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "fuchsia-x64-cast"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_change: true
-    email {
-      recipients: "cronet-bots-observer@google.com"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "ios-simulator-cronet"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "linux-chromeos-dbg"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "linux-chromeos-rel"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci-m83"
-    name: "linux-ozone-rel"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-  tree_closers {
-    tree_status_host: "chromium-status.appspot.com"
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+test-tree-closing-notifier@chromium.org"
-    }
-  }
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
-    email {
-      recipients: "orodley+gpu-test-tree-closing-notifier@chromium.org"
-    }
-  }
-  builders {
     bucket: "ci-m84"
     name: "Android Release (Nexus 5X)"
     repository: "https://chromium.googlesource.com/chromium/src"
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg
index 2d0df7e..ccc990d 100644
--- a/infra/config/generated/luci-scheduler.cfg
+++ b/infra/config/generated/luci-scheduler.cfg
@@ -8230,921 +8230,6 @@
   }
 }
 job {
-  id: "ci-m83-Android Release (Nexus 5X)"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Android Release (Nexus 5X)"
-  }
-}
-job {
-  id: "ci-m83-Android WebView M (dbg)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Android WebView M (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Android WebView N (dbg)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Android WebView N (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Android WebView O (dbg)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Android WebView O (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Android WebView P (dbg)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Android WebView P (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Android arm Builder (dbg)"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Android arm Builder (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Android arm64 Builder (dbg)"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Android arm64 Builder (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Android x64 Builder (dbg)"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Android x64 Builder (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Android x86 Builder (dbg)"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Android x86 Builder (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Cast Android (dbg)"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Cast Android (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Cast Linux"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Cast Linux"
-  }
-}
-job {
-  id: "ci-m83-Dawn Linux x64 DEPS Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Linux x64 DEPS Builder"
-  }
-}
-job {
-  id: "ci-m83-Dawn Linux x64 DEPS Release (Intel HD 630)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Linux x64 DEPS Release (Intel HD 630)"
-  }
-}
-job {
-  id: "ci-m83-Dawn Linux x64 DEPS Release (NVIDIA)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Linux x64 DEPS Release (NVIDIA)"
-  }
-}
-job {
-  id: "ci-m83-Dawn Mac x64 DEPS Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Mac x64 DEPS Builder"
-  }
-}
-job {
-  id: "ci-m83-Dawn Mac x64 DEPS Release (AMD)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Mac x64 DEPS Release (AMD)"
-  }
-}
-job {
-  id: "ci-m83-Dawn Mac x64 DEPS Release (Intel)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Mac x64 DEPS Release (Intel)"
-  }
-}
-job {
-  id: "ci-m83-Dawn Win10 x64 DEPS Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Win10 x64 DEPS Builder"
-  }
-}
-job {
-  id: "ci-m83-Dawn Win10 x64 DEPS Release (Intel HD 630)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Win10 x64 DEPS Release (Intel HD 630)"
-  }
-}
-job {
-  id: "ci-m83-Dawn Win10 x64 DEPS Release (NVIDIA)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Win10 x64 DEPS Release (NVIDIA)"
-  }
-}
-job {
-  id: "ci-m83-Dawn Win10 x86 DEPS Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Win10 x86 DEPS Builder"
-  }
-}
-job {
-  id: "ci-m83-Dawn Win10 x86 DEPS Release (Intel HD 630)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Win10 x86 DEPS Release (Intel HD 630)"
-  }
-}
-job {
-  id: "ci-m83-Dawn Win10 x86 DEPS Release (NVIDIA)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Dawn Win10 x86 DEPS Release (NVIDIA)"
-  }
-}
-job {
-  id: "ci-m83-Fuchsia ARM64"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Fuchsia ARM64"
-  }
-}
-job {
-  id: "ci-m83-Fuchsia x64"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Fuchsia x64"
-  }
-}
-job {
-  id: "ci-m83-GPU Linux Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "GPU Linux Builder"
-  }
-}
-job {
-  id: "ci-m83-GPU Mac Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "GPU Mac Builder"
-  }
-}
-job {
-  id: "ci-m83-GPU Win x64 Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "GPU Win x64 Builder"
-  }
-}
-job {
-  id: "ci-m83-Linux ASan LSan Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux ASan LSan Builder"
-  }
-}
-job {
-  id: "ci-m83-Linux ASan LSan Tests (1)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux ASan LSan Tests (1)"
-  }
-}
-job {
-  id: "ci-m83-Linux ASan Tests (sandboxed)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux ASan Tests (sandboxed)"
-  }
-}
-job {
-  id: "ci-m83-Linux Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux Builder"
-  }
-}
-job {
-  id: "ci-m83-Linux Builder (dbg)"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux Builder (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Linux Ozone Tester (Headless)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux Ozone Tester (Headless)"
-  }
-}
-job {
-  id: "ci-m83-Linux Ozone Tester (Wayland)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux Ozone Tester (Wayland)"
-  }
-}
-job {
-  id: "ci-m83-Linux Ozone Tester (X11)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux Ozone Tester (X11)"
-  }
-}
-job {
-  id: "ci-m83-Linux Release (NVIDIA)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux Release (NVIDIA)"
-  }
-}
-job {
-  id: "ci-m83-Linux TSan Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux TSan Builder"
-  }
-}
-job {
-  id: "ci-m83-Linux TSan Tests"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux TSan Tests"
-  }
-}
-job {
-  id: "ci-m83-Linux Tests"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux Tests"
-  }
-}
-job {
-  id: "ci-m83-Linux Tests (dbg)(1)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Linux Tests (dbg)(1)"
-  }
-}
-job {
-  id: "ci-m83-Mac Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac Builder"
-  }
-}
-job {
-  id: "ci-m83-Mac Builder (dbg)"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac Builder (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Mac Release (Intel)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac Release (Intel)"
-  }
-}
-job {
-  id: "ci-m83-Mac Retina Release (AMD)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac Retina Release (AMD)"
-  }
-}
-job {
-  id: "ci-m83-Mac10.10 Tests"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac10.10 Tests"
-  }
-}
-job {
-  id: "ci-m83-Mac10.11 Tests"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac10.11 Tests"
-  }
-}
-job {
-  id: "ci-m83-Mac10.12 Tests"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac10.12 Tests"
-  }
-}
-job {
-  id: "ci-m83-Mac10.13 Tests"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac10.13 Tests"
-  }
-}
-job {
-  id: "ci-m83-Mac10.13 Tests (dbg)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac10.13 Tests (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Mac10.14 Tests"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Mac10.14 Tests"
-  }
-}
-job {
-  id: "ci-m83-Marshmallow 64 bit Tester"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Marshmallow 64 bit Tester"
-  }
-}
-job {
-  id: "ci-m83-Nougat Phone Tester"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Nougat Phone Tester"
-  }
-}
-job {
-  id: "ci-m83-Oreo Phone Tester"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Oreo Phone Tester"
-  }
-}
-job {
-  id: "ci-m83-VR Linux"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "VR Linux"
-  }
-}
-job {
-  id: "ci-m83-WebKit Mac10.13 (retina)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "WebKit Mac10.13 (retina)"
-  }
-}
-job {
-  id: "ci-m83-Win 7 Tests x64 (1)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Win 7 Tests x64 (1)"
-  }
-}
-job {
-  id: "ci-m83-Win Builder (dbg)"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Win Builder (dbg)"
-  }
-}
-job {
-  id: "ci-m83-Win x64 Builder"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Win x64 Builder"
-  }
-}
-job {
-  id: "ci-m83-Win10 Tests x64"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Win10 Tests x64"
-  }
-}
-job {
-  id: "ci-m83-Win10 Tests x64 1803"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Win10 Tests x64 1803"
-  }
-}
-job {
-  id: "ci-m83-Win10 x64 Release (NVIDIA)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Win10 x64 Release (NVIDIA)"
-  }
-}
-job {
-  id: "ci-m83-Win7 Tests (dbg)(1)"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "Win7 Tests (dbg)(1)"
-  }
-}
-job {
-  id: "ci-m83-android-cronet-arm-dbg"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "android-cronet-arm-dbg"
-  }
-}
-job {
-  id: "ci-m83-android-cronet-arm-rel"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "android-cronet-arm-rel"
-  }
-}
-job {
-  id: "ci-m83-android-cronet-kitkat-arm-rel"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "android-cronet-kitkat-arm-rel"
-  }
-}
-job {
-  id: "ci-m83-android-cronet-lollipop-arm-rel"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "android-cronet-lollipop-arm-rel"
-  }
-}
-job {
-  id: "ci-m83-android-lollipop-arm-rel"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "android-lollipop-arm-rel"
-  }
-}
-job {
-  id: "ci-m83-android-marshmallow-arm64-rel"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "android-marshmallow-arm64-rel"
-  }
-}
-job {
-  id: "ci-m83-android-pie-arm64-dbg"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "android-pie-arm64-dbg"
-  }
-}
-job {
-  id: "ci-m83-android-pie-arm64-rel"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "android-pie-arm64-rel"
-  }
-}
-job {
-  id: "ci-m83-chromeos-amd64-generic-dbg"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "chromeos-amd64-generic-dbg"
-  }
-}
-job {
-  id: "ci-m83-chromeos-amd64-generic-rel"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "chromeos-amd64-generic-rel"
-  }
-}
-job {
-  id: "ci-m83-chromeos-arm-generic-rel"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "chromeos-arm-generic-rel"
-  }
-}
-job {
-  id: "ci-m83-fuchsia-arm64-cast"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "fuchsia-arm64-cast"
-  }
-}
-job {
-  id: "ci-m83-fuchsia-x64-cast"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "fuchsia-x64-cast"
-  }
-}
-job {
-  id: "ci-m83-ios-simulator"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "ios-simulator"
-  }
-}
-job {
-  id: "ci-m83-ios-simulator-cronet"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "ios-simulator-cronet"
-  }
-}
-job {
-  id: "ci-m83-ios-simulator-full-configs"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "ios-simulator-full-configs"
-  }
-}
-job {
-  id: "ci-m83-linux-chromeos-dbg"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "linux-chromeos-dbg"
-  }
-}
-job {
-  id: "ci-m83-linux-chromeos-rel"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "linux-chromeos-rel"
-  }
-}
-job {
-  id: "ci-m83-linux-ozone-rel"
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "linux-ozone-rel"
-  }
-}
-job {
-  id: "ci-m83-mac-osxbeta-rel"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci-m83"
-    builder: "mac-osxbeta-rel"
-  }
-}
-job {
   id: "ci-m84-Android Release (Nexus 5X)"
   acl_sets: "ci-m84"
   buildbucket {
@@ -12218,16 +11303,6 @@
   }
 }
 job {
-  id: "ci-m83-Android WebView L (dbg)"
-  schedule: "triggered"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  noop {}
-}
-job {
   id: "ci-m84-Android WebView L (dbg)"
   schedule: "triggered"
   acls {
@@ -12248,16 +11323,6 @@
   noop {}
 }
 job {
-  id: "ci-m83-Lollipop Phone Tester"
-  schedule: "triggered"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  noop {}
-}
-job {
   id: "ci-m84-Lollipop Phone Tester"
   schedule: "triggered"
   acls {
@@ -12278,16 +11343,6 @@
   noop {}
 }
 job {
-  id: "ci-m83-Lollipop Tablet Tester"
-  schedule: "triggered"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  noop {}
-}
-job {
   id: "ci-m84-Lollipop Tablet Tester"
   schedule: "triggered"
   acls {
@@ -12308,16 +11363,6 @@
   noop {}
 }
 job {
-  id: "ci-m83-Marshmallow Tablet Tester"
-  schedule: "triggered"
-  acls {
-    role: TRIGGERER
-    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  acl_sets: "ci-m83"
-  noop {}
-}
-job {
   id: "ci-m84-Marshmallow Tablet Tester"
   schedule: "triggered"
   acls {
@@ -12338,55 +11383,6 @@
   noop {}
 }
 trigger {
-  id: "m83-gitiles-trigger"
-  acl_sets: "ci-m83"
-  triggers: "ci-m83-Android Release (Nexus 5X)"
-  triggers: "ci-m83-Android arm Builder (dbg)"
-  triggers: "ci-m83-Android arm64 Builder (dbg)"
-  triggers: "ci-m83-Android x64 Builder (dbg)"
-  triggers: "ci-m83-Android x86 Builder (dbg)"
-  triggers: "ci-m83-Cast Android (dbg)"
-  triggers: "ci-m83-Cast Linux"
-  triggers: "ci-m83-Dawn Linux x64 DEPS Builder"
-  triggers: "ci-m83-Dawn Mac x64 DEPS Builder"
-  triggers: "ci-m83-Dawn Win10 x64 DEPS Builder"
-  triggers: "ci-m83-Dawn Win10 x86 DEPS Builder"
-  triggers: "ci-m83-Fuchsia ARM64"
-  triggers: "ci-m83-Fuchsia x64"
-  triggers: "ci-m83-GPU Linux Builder"
-  triggers: "ci-m83-GPU Mac Builder"
-  triggers: "ci-m83-GPU Win x64 Builder"
-  triggers: "ci-m83-Linux ASan LSan Builder"
-  triggers: "ci-m83-Linux Builder"
-  triggers: "ci-m83-Linux Builder (dbg)"
-  triggers: "ci-m83-Linux TSan Builder"
-  triggers: "ci-m83-Mac Builder"
-  triggers: "ci-m83-Mac Builder (dbg)"
-  triggers: "ci-m83-VR Linux"
-  triggers: "ci-m83-Win Builder (dbg)"
-  triggers: "ci-m83-Win x64 Builder"
-  triggers: "ci-m83-android-cronet-arm-dbg"
-  triggers: "ci-m83-android-cronet-arm-rel"
-  triggers: "ci-m83-android-lollipop-arm-rel"
-  triggers: "ci-m83-android-marshmallow-arm64-rel"
-  triggers: "ci-m83-android-pie-arm64-rel"
-  triggers: "ci-m83-chromeos-amd64-generic-dbg"
-  triggers: "ci-m83-chromeos-amd64-generic-rel"
-  triggers: "ci-m83-chromeos-arm-generic-rel"
-  triggers: "ci-m83-fuchsia-arm64-cast"
-  triggers: "ci-m83-fuchsia-x64-cast"
-  triggers: "ci-m83-ios-simulator"
-  triggers: "ci-m83-ios-simulator-cronet"
-  triggers: "ci-m83-ios-simulator-full-configs"
-  triggers: "ci-m83-linux-chromeos-dbg"
-  triggers: "ci-m83-linux-chromeos-rel"
-  triggers: "ci-m83-linux-ozone-rel"
-  gitiles {
-    repo: "https://chromium.googlesource.com/chromium/src"
-    refs: "regexp:refs/branch-heads/4103"
-  }
-}
-trigger {
   id: "m84-gitiles-trigger"
   acl_sets: "ci-m84"
   triggers: "ci-m84-Android Release (Nexus 5X)"
@@ -12882,16 +11878,6 @@
   }
 }
 acl_sets {
-  name: "ci-m83"
-  acls {
-    role: OWNER
-    granted_to: "group:project-chromium-admins"
-  }
-  acls {
-    granted_to: "group:all"
-  }
-}
-acl_sets {
   name: "ci-m84"
   acls {
     role: OWNER
diff --git a/infra/config/generated/realms.cfg b/infra/config/generated/realms.cfg
index dbbaf48..64a4b5d 100644
--- a/infra/config/generated/realms.cfg
+++ b/infra/config/generated/realms.cfg
@@ -50,26 +50,6 @@
   }
 }
 realms {
-  name: "ci-m83"
-  bindings {
-    role: "role/buildbucket.builderServiceAccount"
-    principals: "user:chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-    principals: "user:chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  bindings {
-    role: "role/buildbucket.owner"
-    principals: "group:google/luci-task-force@google.com"
-  }
-  bindings {
-    role: "role/buildbucket.reader"
-    principals: "group:all"
-  }
-  bindings {
-    role: "role/buildbucket.triggerer"
-    principals: "group:project-chromium-ci-schedulers"
-  }
-}
-realms {
   name: "ci-m84"
   bindings {
     role: "role/buildbucket.builderServiceAccount"
@@ -174,30 +154,6 @@
   }
 }
 realms {
-  name: "try-m83"
-  bindings {
-    role: "role/buildbucket.builderServiceAccount"
-    principals: "user:chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
-    principals: "user:chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-  }
-  bindings {
-    role: "role/buildbucket.owner"
-    principals: "group:service-account-chromium-tryserver"
-  }
-  bindings {
-    role: "role/buildbucket.reader"
-    principals: "group:all"
-  }
-  bindings {
-    role: "role/buildbucket.triggerer"
-    principals: "group:project-chromium-tryjob-access"
-    principals: "group:service-account-chromeperf"
-    principals: "group:service-account-cq"
-    principals: "user:findit-for-me@appspot.gserviceaccount.com"
-    principals: "user:tricium-prod@appspot.gserviceaccount.com"
-  }
-}
-realms {
   name: "try-m84"
   bindings {
     role: "role/buildbucket.builderServiceAccount"
diff --git a/infra/config/generators/scheduler-noop-jobs.star b/infra/config/generators/scheduler-noop-jobs.star
index b8c28e6..f5f754d 100644
--- a/infra/config/generators/scheduler-noop-jobs.star
+++ b/infra/config/generators/scheduler-noop-jobs.star
@@ -8,7 +8,7 @@
 
 
 _BRANCH_NOOP_CONFIG = struct(
-    buckets = ['ci-m83', 'ci-m84', 'ci-m85'],
+    buckets = ['ci-m84', 'ci-m85'],
     fmt = '{bucket}-{builder}',
 ) if settings.is_master else struct(
     buckets = ['ci'],
diff --git a/infra/config/subprojects/chromium/master-only/ci.star b/infra/config/subprojects/chromium/master-only/ci.star
index 3750c18b..236cdf9 100644
--- a/infra/config/subprojects/chromium/master-only/ci.star
+++ b/infra/config/subprojects/chromium/master-only/ci.star
@@ -8,7 +8,6 @@
 
 # Execute the versioned files to define all of the per-branch entities
 # (bucket, builders, console, poller, etc.)
-exec('../versioned/m83/buckets/ci.star')
 exec('../versioned/m84/buckets/ci.star')
 exec('../versioned/m85/buckets/ci.star')
 
diff --git a/infra/config/subprojects/chromium/master-only/try.star b/infra/config/subprojects/chromium/master-only/try.star
index 7049cc03..e574107 100644
--- a/infra/config/subprojects/chromium/master-only/try.star
+++ b/infra/config/subprojects/chromium/master-only/try.star
@@ -8,7 +8,6 @@
 
 # Execute the versioned files to define all of the per-branch entities
 # (bucket, builders, console, cq_group, etc.)
-exec('../versioned/m83/buckets/try.star')
 exec('../versioned/m84/buckets/try.star')
 exec('../versioned/m85/buckets/try.star')
 
diff --git a/infra/config/subprojects/chromium/versioned/README.md b/infra/config/subprojects/chromium/versioned/README.md
index 82d33a8..7998f0a 100644
--- a/infra/config/subprojects/chromium/versioned/README.md
+++ b/infra/config/subprojects/chromium/versioned/README.md
@@ -2,7 +2,7 @@
 
 Contents:
 
-* **m83**, **m84**, **m85**
+* **m84**, **m85**
   * contains subdirectories that contain the versioned configuration for the
   active milestones
   * non-dimension changes should be infrequent
diff --git a/infra/config/subprojects/chromium/versioned/m83/buckets/ci.star b/infra/config/subprojects/chromium/versioned/m83/buckets/ci.star
deleted file mode 100644
index d9d62ee..0000000
--- a/infra/config/subprojects/chromium/versioned/m83/buckets/ci.star
+++ /dev/null
@@ -1,802 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-load('//lib/builders.star', 'builder_name', 'cpu', 'goma', 'os')
-load('//lib/ci.star', 'ci')
-# Load this using relative path so that the load statement doesn't
-# need to be changed when making a new milestone
-load('../vars.star', 'vars')
-
-
-ci.set_defaults(
-    vars,
-    bucketed_triggers = True,
-    main_console_view = vars.main_console_name,
-    cq_mirrors_console_view = vars.cq_mirrors_console_name,
-)
-
-ci.declare_bucket(vars)
-
-
-# Builders are sorted first lexicographically by the function used to define
-# them, then lexicographically by their name
-
-
-ci.android_builder(
-    name = 'Android WebView M (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'tester|webview',
-        short_name = 'M',
-    ),
-    triggered_by = [builder_name('Android arm64 Builder (dbg)')],
-)
-
-ci.android_builder(
-    name = 'Android WebView N (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'tester|webview',
-        short_name = 'N',
-    ),
-    triggered_by = [builder_name('Android arm64 Builder (dbg)')],
-)
-
-ci.android_builder(
-    name = 'Android WebView O (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'tester|webview',
-        short_name = 'O',
-    ),
-    triggered_by = [builder_name('Android arm64 Builder (dbg)')],
-)
-
-ci.android_builder(
-    name = 'Android WebView P (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'tester|webview',
-        short_name = 'P',
-    ),
-    triggered_by = [builder_name('Android arm64 Builder (dbg)')],
-)
-
-ci.android_builder(
-    name = 'Android arm Builder (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'builder|arm',
-        short_name = '32',
-    ),
-    execution_timeout = 4 * time.hour,
-)
-
-ci.android_builder(
-    name = 'Android arm64 Builder (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'builder|arm',
-        short_name = '64',
-    ),
-    goma_jobs = goma.jobs.MANY_JOBS_FOR_CI,
-    execution_timeout = 4 * time.hour,
-)
-
-ci.android_builder(
-    name = 'Android x64 Builder (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'builder|x86',
-        short_name = '64',
-    ),
-    execution_timeout = 4 * time.hour,
-)
-
-ci.android_builder(
-    name = 'Android x86 Builder (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'builder|x86',
-        short_name = '32',
-    ),
-)
-
-ci.android_builder(
-    name = 'Cast Android (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'on_cq',
-        short_name = 'cst',
-    ),
-)
-
-ci.android_builder(
-    name = 'Marshmallow 64 bit Tester',
-    console_view_entry = ci.console_view_entry(
-        category = 'tester|phone',
-        short_name = 'M',
-    ),
-    triggered_by = [builder_name('Android arm64 Builder (dbg)')],
-)
-
-ci.android_builder(
-    name = 'Nougat Phone Tester',
-    console_view_entry = ci.console_view_entry(
-        category = 'tester|phone',
-        short_name = 'N',
-    ),
-    triggered_by = [builder_name('Android arm64 Builder (dbg)')],
-)
-
-ci.android_builder(
-    name = 'Oreo Phone Tester',
-    console_view_entry = ci.console_view_entry(
-        category = 'tester|phone',
-        short_name = 'O',
-    ),
-    triggered_by = [builder_name('Android arm64 Builder (dbg)')],
-)
-
-ci.android_builder(
-    name = 'android-cronet-arm-dbg',
-    console_view_entry = ci.console_view_entry(
-        category = 'cronet|arm',
-        short_name = 'dbg',
-    ),
-    notifies = ['cronet'],
-)
-
-ci.android_builder(
-    name = 'android-cronet-arm-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'cronet|arm',
-        short_name = 'rel',
-    ),
-    notifies = ['cronet'],
-)
-
-ci.android_builder(
-    name = 'android-cronet-kitkat-arm-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'cronet|test',
-        short_name = 'k',
-    ),
-    notifies = ['cronet'],
-    triggered_by = [builder_name('android-cronet-arm-rel')],
-)
-
-ci.android_builder(
-    name = 'android-cronet-lollipop-arm-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'cronet|test',
-        short_name = 'l',
-    ),
-    notifies = ['cronet'],
-    triggered_by = [builder_name('android-cronet-arm-rel')],
-)
-
-ci.android_builder(
-    name = 'android-lollipop-arm-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'on_cq',
-        short_name = 'L',
-    ),
-)
-
-ci.android_builder(
-    name = 'android-marshmallow-arm64-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'on_cq',
-        short_name = 'M',
-    ),
-)
-
-ci.android_builder(
-    name = 'android-pie-arm64-dbg',
-    console_view_entry = ci.console_view_entry(
-        category = 'tester|phone',
-        short_name = 'P',
-    ),
-    triggered_by = [builder_name('Android arm64 Builder (dbg)')],
-)
-
-ci.android_builder(
-    name = 'android-pie-arm64-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'on_cq',
-        short_name = 'P',
-    ),
-)
-
-
-ci.chromiumos_builder(
-    name = 'chromeos-amd64-generic-dbg',
-    console_view_entry = ci.console_view_entry(
-        category = 'simple|debug|x64',
-        short_name = 'dbg',
-    ),
-)
-
-ci.chromiumos_builder(
-    name = 'chromeos-amd64-generic-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'simple|release|x64',
-        short_name = 'rel',
-    ),
-)
-
-ci.chromiumos_builder(
-    name = 'chromeos-arm-generic-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'simple|release',
-        short_name = 'arm',
-    ),
-)
-
-ci.chromiumos_builder(
-    name = 'linux-chromeos-dbg',
-    console_view_entry = ci.console_view_entry(
-        category = 'default',
-        short_name = 'dbg',
-    ),
-)
-
-ci.chromiumos_builder(
-    name = 'linux-chromeos-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'default',
-        short_name = 'rel',
-    ),
-)
-
-
-ci.dawn_builder(
-    name = 'Dawn Linux x64 DEPS Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Linux|Builder',
-        short_name = 'x64',
-    ),
-)
-
-ci.dawn_builder(
-    name = 'Dawn Linux x64 DEPS Release (Intel HD 630)',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Linux|Intel',
-        short_name = 'x64',
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = [builder_name('Dawn Linux x64 DEPS Builder')],
-)
-
-ci.dawn_builder(
-    name = 'Dawn Linux x64 DEPS Release (NVIDIA)',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Linux|Nvidia',
-        short_name = 'x64',
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = [builder_name('Dawn Linux x64 DEPS Builder')],
-)
-
-ci.dawn_builder(
-    name = 'Dawn Mac x64 DEPS Builder',
-    builderless = False,
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Mac|Builder',
-        short_name = 'x64',
-    ),
-    cores = None,
-    os = os.MAC_ANY,
-)
-
-# Note that the Mac testers are all thin Linux VMs, triggering jobs on the
-# physical Mac hardware in the Swarming pool which is why they run on linux
-ci.dawn_builder(
-    name = 'Dawn Mac x64 DEPS Release (AMD)',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Mac|AMD',
-        short_name = 'x64',
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = [builder_name('Dawn Mac x64 DEPS Builder')],
-)
-
-ci.dawn_builder(
-    name = 'Dawn Mac x64 DEPS Release (Intel)',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Mac|Intel',
-        short_name = 'x64',
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = [builder_name('Dawn Mac x64 DEPS Builder')],
-)
-
-ci.dawn_builder(
-    name = 'Dawn Win10 x64 DEPS Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Windows|Builder',
-        short_name = 'x64',
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.dawn_builder(
-    name = 'Dawn Win10 x64 DEPS Release (Intel HD 630)',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Windows|Intel',
-        short_name = 'x64',
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = [builder_name('Dawn Win10 x64 DEPS Builder')],
-)
-
-ci.dawn_builder(
-    name = 'Dawn Win10 x64 DEPS Release (NVIDIA)',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Windows|Nvidia',
-        short_name = 'x64',
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = [builder_name('Dawn Win10 x64 DEPS Builder')],
-)
-
-ci.dawn_builder(
-    name = 'Dawn Win10 x86 DEPS Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Windows|Builder',
-        short_name = 'x86',
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.dawn_builder(
-    name = 'Dawn Win10 x86 DEPS Release (Intel HD 630)',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Windows|Intel',
-        short_name = 'x86',
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = [builder_name('Dawn Win10 x86 DEPS Builder')],
-)
-
-ci.dawn_builder(
-    name = 'Dawn Win10 x86 DEPS Release (NVIDIA)',
-    console_view_entry = ci.console_view_entry(
-        category = 'DEPS|Windows|Nvidia',
-        short_name = 'x86',
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = [builder_name('Dawn Win10 x86 DEPS Builder')],
-)
-
-
-ci.fyi_builder(
-    name = 'VR Linux',
-    console_view_entry = ci.console_view_entry(
-        category = 'linux',
-    ),
-)
-
-# This is launching & collecting entirely isolated tests.
-# OS shouldn't matter.
-ci.fyi_builder(
-    name = 'mac-osxbeta-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'mac',
-        short_name = 'beta',
-    ),
-    goma_backend = None,
-    triggered_by = [builder_name('Mac Builder')],
-)
-
-
-ci.fyi_ios_builder(
-    name = 'ios-simulator-cronet',
-    console_view_entry = ci.console_view_entry(
-        category = 'cronet',
-    ),
-    executable = 'recipe:chromium',
-    notifies = ['cronet'],
-    properties = {
-        'xcode_build_version': '11c29',
-    },
-)
-
-
-ci.fyi_windows_builder(
-    name = 'Win10 Tests x64 1803',
-    console_view_entry = ci.console_view_entry(
-        category = 'win10|1803',
-    ),
-    goma_backend = None,
-    os = os.WINDOWS_10,
-    triggered_by = [builder_name('Win x64 Builder')],
-)
-
-
-ci.gpu_builder(
-    name = 'Android Release (Nexus 5X)',
-    console_view_entry = ci.console_view_entry(
-        category = 'Android',
-    ),
-)
-
-ci.gpu_builder(
-    name = 'GPU Linux Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'Linux',
-    ),
-)
-
-ci.gpu_builder(
-    name = 'GPU Mac Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'Mac',
-    ),
-    cores = None,
-    os = os.MAC_ANY,
-)
-
-ci.gpu_builder(
-    name = 'GPU Win x64 Builder',
-    builderless = True,
-    console_view_entry = ci.console_view_entry(
-        category = 'Windows',
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-
-ci.gpu_thin_tester(
-    name = 'Linux Release (NVIDIA)',
-    console_view_entry = ci.console_view_entry(
-        category = 'Linux',
-    ),
-    triggered_by = [builder_name('GPU Linux Builder')],
-)
-
-ci.gpu_thin_tester(
-    name = 'Mac Release (Intel)',
-    console_view_entry = ci.console_view_entry(
-        category = 'Mac',
-    ),
-    triggered_by = [builder_name('GPU Mac Builder')],
-)
-
-ci.gpu_thin_tester(
-    name = 'Mac Retina Release (AMD)',
-    console_view_entry = ci.console_view_entry(
-        category = 'Mac',
-    ),
-    triggered_by = [builder_name('GPU Mac Builder')],
-)
-
-ci.gpu_thin_tester(
-    name = 'Win10 x64 Release (NVIDIA)',
-    console_view_entry = ci.console_view_entry(
-        category = 'Windows',
-    ),
-    triggered_by = [builder_name('GPU Win x64 Builder')],
-)
-
-
-ci.linux_builder(
-    name = 'Cast Linux',
-    console_view_entry = ci.console_view_entry(
-        category = 'cast',
-        short_name = 'vid',
-    ),
-    goma_jobs = goma.jobs.J50,
-)
-
-ci.linux_builder(
-    name = 'Fuchsia ARM64',
-    console_view_entry = ci.console_view_entry(
-        category = 'fuchsia|a64',
-    ),
-    extra_notifies = ['cr-fuchsia'],
-)
-
-ci.linux_builder(
-    name = 'Fuchsia x64',
-    console_view_entry = ci.console_view_entry(
-        category = 'fuchsia|x64',
-        short_name = 'rel',
-    ),
-    extra_notifies = ['cr-fuchsia'],
-)
-
-ci.linux_builder(
-    name = 'Linux Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = 'bld',
-    ),
-)
-
-ci.linux_builder(
-    name = 'Linux Builder (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'debug|builder',
-        short_name = '64',
-    ),
-)
-
-ci.linux_builder(
-    name = 'Linux Tests',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = 'tst',
-    ),
-    goma_backend = None,
-    triggered_by = [builder_name('Linux Builder')],
-)
-
-ci.linux_builder(
-    name = 'Linux Tests (dbg)(1)',
-    console_view_entry = ci.console_view_entry(
-        category = 'debug|tester',
-        short_name = '64',
-    ),
-    triggered_by = [builder_name('Linux Builder (dbg)')],
-)
-
-ci.linux_builder(
-    name = 'fuchsia-arm64-cast',
-    console_view_entry = ci.console_view_entry(
-        category = 'fuchsia|cast',
-        short_name = 'a64',
-    ),
-    extra_notifies = ['cr-fuchsia'],
-)
-
-ci.linux_builder(
-    name = 'fuchsia-x64-cast',
-    console_view_entry = ci.console_view_entry(
-        category = 'fuchsia|cast',
-        short_name = 'x64',
-    ),
-    extra_notifies = ['cr-fuchsia'],
-)
-
-ci.linux_builder(
-    name = 'linux-ozone-rel',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = 'ozo',
-    ),
-)
-
-ci.linux_builder(
-    name = 'Linux Ozone Tester (Headless)',
-    console_view = 'chromium.fyi',
-    console_view_entry = ci.console_view_entry(
-        category = 'linux',
-        short_name = 'loh',
-    ),
-    triggered_by = [builder_name('linux-ozone-rel')],
-)
-
-ci.linux_builder(
-    name = 'Linux Ozone Tester (Wayland)',
-    console_view = 'chromium.fyi',
-    console_view_entry = ci.console_view_entry(
-        category = 'linux',
-        short_name = 'low',
-    ),
-    triggered_by = [builder_name('linux-ozone-rel')],
-)
-
-ci.linux_builder(
-    name = 'Linux Ozone Tester (X11)',
-    console_view = 'chromium.fyi',
-    console_view_entry = ci.console_view_entry(
-        category = 'linux',
-        short_name = 'lox',
-    ),
-    triggered_by = [builder_name('linux-ozone-rel')],
-)
-
-
-ci.mac_builder(
-    name = 'Mac Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = 'bld',
-    ),
-    os = os.MAC_10_14,
-)
-
-ci.mac_builder(
-    name = 'Mac Builder (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'debug',
-        short_name = 'bld',
-    ),
-    os = os.MAC_ANY,
-)
-
-ci.thin_tester(
-    name = 'Mac10.10 Tests',
-    mastername = 'chromium.mac',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = '10',
-    ),
-    triggered_by = [builder_name('Mac Builder')],
-)
-
-ci.thin_tester(
-    name = 'Mac10.11 Tests',
-    mastername = 'chromium.mac',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = '11',
-    ),
-    triggered_by = [builder_name('Mac Builder')],
-)
-
-ci.thin_tester(
-    name = 'Mac10.12 Tests',
-    mastername = 'chromium.mac',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = '12',
-    ),
-    triggered_by = [builder_name('Mac Builder')],
-)
-
-ci.thin_tester(
-    name = 'Mac10.13 Tests',
-    mastername = 'chromium.mac',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = '13',
-    ),
-    triggered_by = [builder_name('Mac Builder')],
-)
-
-ci.thin_tester(
-    name = 'Mac10.14 Tests',
-    mastername = 'chromium.mac',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = '14',
-    ),
-    triggered_by = [builder_name('Mac Builder')],
-)
-
-ci.thin_tester(
-    name = 'Mac10.13 Tests (dbg)',
-    mastername = 'chromium.mac',
-    console_view_entry = ci.console_view_entry(
-        category = 'debug',
-        short_name = '13',
-    ),
-    triggered_by = [builder_name('Mac Builder (dbg)')],
-)
-
-ci.thin_tester(
-    name = 'WebKit Mac10.13 (retina)',
-    mastername = 'chromium.mac',
-    console_view_entry = ci.console_view_entry(
-        category = 'release',
-        short_name = 'ret',
-    ),
-    triggered_by = [builder_name('Mac Builder')],
-)
-
-
-ci.mac_ios_builder(
-    name = 'ios-simulator',
-    console_view_entry = ci.console_view_entry(
-        category = 'ios|default',
-        short_name = 'sim',
-    ),
-    executable = 'recipe:ios/unified_builder_tester'
-)
-
-ci.mac_ios_builder(
-    name = 'ios-simulator-full-configs',
-    console_view_entry = ci.console_view_entry(
-        category = 'ios|default',
-        short_name = 'ful',
-    ),
-    executable = 'recipe:ios/unified_builder_tester',
-)
-
-
-ci.memory_builder(
-    name = 'Linux ASan LSan Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'linux|asan lsan',
-        short_name = 'bld',
-    ),
-    ssd = True,
-)
-
-ci.memory_builder(
-    name = 'Linux ASan LSan Tests (1)',
-    console_view_entry = ci.console_view_entry(
-        category = 'linux|asan lsan',
-        short_name = 'tst',
-    ),
-    triggered_by = [builder_name('Linux ASan LSan Builder')],
-)
-
-ci.memory_builder(
-    name = 'Linux ASan Tests (sandboxed)',
-    console_view_entry = ci.console_view_entry(
-        category = 'linux|asan lsan',
-        short_name = 'sbx',
-    ),
-    triggered_by = [builder_name('Linux ASan LSan Builder')],
-)
-
-ci.memory_builder(
-    name = 'Linux TSan Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'linux|TSan v2',
-        short_name = 'bld',
-    ),
-)
-
-ci.memory_builder(
-    name = 'Linux TSan Tests',
-    console_view_entry = ci.console_view_entry(
-        category = 'linux|TSan v2',
-        short_name = 'tst',
-    ),
-    triggered_by = [builder_name('Linux TSan Builder')],
-)
-
-
-ci.win_builder(
-    name = 'Win7 Tests (dbg)(1)',
-    console_view_entry = ci.console_view_entry(
-        category = 'debug|tester',
-        short_name = '7',
-    ),
-    os = os.WINDOWS_7,
-    triggered_by = [builder_name('Win Builder (dbg)')],
-)
-
-ci.win_builder(
-    name = 'Win 7 Tests x64 (1)',
-    console_view_entry = ci.console_view_entry(
-        category = 'release|tester',
-        short_name = '64',
-    ),
-    os = os.WINDOWS_7,
-    triggered_by = [builder_name('Win x64 Builder')],
-)
-
-ci.win_builder(
-    name = 'Win Builder (dbg)',
-    console_view_entry = ci.console_view_entry(
-        category = 'debug|builder',
-        short_name = '32',
-    ),
-    cores = 32,
-    os = os.WINDOWS_ANY,
-)
-
-ci.win_builder(
-    name = 'Win x64 Builder',
-    console_view_entry = ci.console_view_entry(
-        category = 'release|builder',
-        short_name = '64',
-    ),
-    cores = 32,
-    os = os.WINDOWS_ANY,
-)
-
-ci.win_builder(
-    name = 'Win10 Tests x64',
-    console_view_entry = ci.console_view_entry(
-        category = 'release|tester',
-        short_name = 'w10',
-    ),
-    triggered_by = [builder_name('Win x64 Builder')],
-)
diff --git a/infra/config/subprojects/chromium/versioned/m83/buckets/try.star b/infra/config/subprojects/chromium/versioned/m83/buckets/try.star
deleted file mode 100644
index 9f4576e..0000000
--- a/infra/config/subprojects/chromium/versioned/m83/buckets/try.star
+++ /dev/null
@@ -1,559 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-load('//lib/builders.star', 'cpu', 'goma', 'os')
-load('//lib/try.star', 'try_')
-# Load this using relative path so that the load statement doesn't
-# need to be changed when making a new milestone
-load('../vars.star', 'vars')
-
-
-try_.declare_bucket(vars)
-
-try_.set_defaults(
-    vars,
-    main_list_view = vars.main_list_view_name,
-)
-
-
-# Builders are sorted first lexicographically by the function used to define
-# them, then lexicographically by their name
-
-
-try_.blink_builder(
-    name = 'linux-blink-rel',
-    goma_backend = goma.backend.RBE_PROD,
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/cc/.+',
-            '.+/[+]/third_party/blink/renderer/core/paint/.+',
-            '.+/[+]/third_party/blink/renderer/core/svg/.+',
-            '.+/[+]/third_party/blink/renderer/platform/graphics/.+',
-        ],
-    ),
-)
-
-
-try_.chromium_android_builder(
-    name = 'android-binary-size',
-    executable = 'recipe:binary_size_trybot',
-    goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(),
-)
-
-try_.chromium_android_builder(
-    name = 'android-cronet-arm-dbg',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/components/cronet/.+',
-            '.+/[+]/components/grpc_support/.+',
-            '.+/[+]/build/android/.+',
-            '.+/[+]/build/config/android/.+',
-        ],
-        location_regexp_exclude = [
-            '.+/[+]/components/cronet/ios/.+',
-        ],
-    ),
-)
-
-try_.chromium_android_builder(
-    name = 'android-lollipop-arm-rel',
-    goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(),
-)
-
-try_.chromium_android_builder(
-    name = 'android-marshmallow-arm64-rel',
-    cores = 16,
-    goma_jobs = goma.jobs.J300,
-    ssd = True,
-    use_java_coverage = True,
-    tryjob = try_.job(),
-)
-
-try_.chromium_android_builder(
-    name = 'android-pie-arm64-dbg',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/chrome/android/features/vr/.+',
-            '.+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+',
-            '.+/[+]/chrome/android/javatests/src/org/chromium/chrome/browser/vr/.+',
-            '.+/[+]/chrome/browser/vr/.+',
-            '.+/[+]/third_party/gvr-android-sdk/.+',
-            '.+/[+]/third_party/arcore-android-sdk/.+',
-            '.+/[+]/third_party/arcore-android-sdk-client/.+',
-        ],
-    ),
-)
-
-try_.chromium_android_builder(
-    name = 'android-pie-arm64-rel',
-    cores = 16,
-    goma_jobs = goma.jobs.J300,
-    ssd = True,
-    tryjob = try_.job(),
-)
-
-try_.chromium_android_builder(
-    name = 'android_compile_dbg',
-    goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(),
-)
-
-try_.chromium_android_builder(
-    name = 'android_compile_x64_dbg',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+',
-            '.+/[+]/chrome/browser/vr/.+',
-            '.+/[+]/sandbox/linux/seccomp-bpf/.+',
-            '.+/[+]/sandbox/linux/seccomp-bpf-helpers/.+',
-            '.+/[+]/sandbox/linux/system_headers/.+',
-            '.+/[+]/sandbox/linux/tests/.+',
-            '.+/[+]/third_party/gvr-android-sdk/.+',
-        ],
-    ),
-)
-
-try_.chromium_android_builder(
-    name = 'android_compile_x86_dbg',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+',
-            '.+/[+]/chrome/browser/vr/.+',
-            '.+/[+]/sandbox/linux/seccomp-bpf/.+',
-            '.+/[+]/sandbox/linux/seccomp-bpf-helpers/.+',
-            '.+/[+]/sandbox/linux/system_headers/.+',
-            '.+/[+]/sandbox/linux/tests/.+',
-            '.+/[+]/third_party/gvr-android-sdk/.+',
-        ],
-    ),
-)
-
-try_.chromium_android_builder(
-    name = 'android_cronet',
-    tryjob = try_.job(),
-)
-
-try_.chromium_android_builder(
-    name = 'cast_shell_android',
-    tryjob = try_.job(),
-)
-
-
-try_.chromium_chromiumos_builder(
-    name = 'chromeos-amd64-generic-dbg',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/content/gpu/.+',
-            '.+/[+]/media/.+',
-        ],
-    ),
-)
-
-try_.chromium_chromiumos_builder(
-    name = 'chromeos-amd64-generic-rel',
-    tryjob = try_.job(),
-)
-
-try_.chromium_chromiumos_builder(
-    name = 'chromeos-arm-generic-rel',
-    tryjob = try_.job(),
-)
-
-try_.chromium_chromiumos_builder(
-    name = 'linux-chromeos-compile-dbg',
-    tryjob = try_.job(),
-)
-
-try_.chromium_chromiumos_builder(
-    name = 'linux-chromeos-rel',
-    goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(cancel_stale = False),
-    use_clang_coverage = True,
-)
-
-
-try_.chromium_dawn_builder(
-    name = 'dawn-linux-x64-deps-rel',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/gpu/.+',
-            '.+/[+]/testing/buildbot/chromium.dawn.json',
-            '.+/[+]/third_party/blink/renderer/modules/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/external/wpt/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/wpt_internal/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/WebGPUExpectations',
-            '.+/[+]/third_party/dawn/.+',
-            '.+/[+]/tools/clang/scripts/update.py',
-            '.+/[+]/ui/gl/features.gni',
-        ],
-    ),
-)
-
-try_.chromium_dawn_builder(
-    name = 'dawn-mac-x64-deps-rel',
-    os = os.MAC_ANY,
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/gpu/.+',
-            '.+/[+]/testing/buildbot/chromium.dawn.json',
-            '.+/[+]/third_party/blink/renderer/modules/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/external/wpt/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/wpt_internal/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/WebGPUExpectations',
-            '.+/[+]/third_party/dawn/.+',
-            '.+/[+]/tools/clang/scripts/update.py',
-            '.+/[+]/ui/gl/features.gni',
-        ],
-    ),
-)
-
-try_.chromium_dawn_builder(
-    name = 'dawn-win10-x64-deps-rel',
-    os = os.WINDOWS_ANY,
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/gpu/.+',
-            '.+/[+]/testing/buildbot/chromium.dawn.json',
-            '.+/[+]/third_party/blink/renderer/modules/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/external/wpt/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/wpt_internal/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/WebGPUExpectations',
-            '.+/[+]/third_party/dawn/.+',
-            '.+/[+]/tools/clang/scripts/update.py',
-            '.+/[+]/ui/gl/features.gni',
-        ],
-    ),
-)
-
-try_.chromium_dawn_builder(
-    name = 'dawn-win10-x86-deps-rel',
-    os = os.WINDOWS_ANY,
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/gpu/.+',
-            '.+/[+]/testing/buildbot/chromium.dawn.json',
-            '.+/[+]/third_party/blink/renderer/modules/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/external/wpt/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/wpt_internal/webgpu/.+',
-            '.+/[+]/third_party/blink/web_tests/WebGPUExpectations',
-            '.+/[+]/third_party/dawn/.+',
-            '.+/[+]/tools/clang/scripts/update.py',
-            '.+/[+]/ui/gl/features.gni',
-        ],
-    ),
-)
-
-
-try_.chromium_linux_builder(
-    name = 'cast_shell_linux',
-    tryjob = try_.job(),
-)
-
-try_.chromium_linux_builder(
-    name = 'closure_compilation',
-    executable = 'recipe:closure_compilation',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/third_party/closure_compiler/.+',
-        ],
-    ),
-)
-
-try_.chromium_linux_builder(
-    name = 'chromium_presubmit',
-    executable = 'recipe:presubmit',
-    goma_backend = None,
-    properties = {
-        '$depot_tools/presubmit': {
-            'runhooks': True,
-            'timeout_s': 480,
-        },
-        'repo_name': 'chromium',
-    },
-    tryjob = try_.job(
-        disable_reuse = True,
-    ),
-)
-
-try_.chromium_linux_builder(
-    name = 'fuchsia-arm64-cast',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/chromecast/.+',
-        ],
-    ),
-)
-
-try_.chromium_linux_builder(
-    name = 'fuchsia-x64-cast',
-    tryjob = try_.job(),
-)
-
-try_.chromium_linux_builder(
-    name = 'fuchsia_arm64',
-    tryjob = try_.job(),
-)
-
-try_.chromium_linux_builder(
-    name = 'fuchsia_x64',
-    tryjob = try_.job(),
-)
-
-try_.chromium_linux_builder(
-    name = 'linux-libfuzzer-asan-rel',
-    executable = 'recipe:chromium_libfuzzer_trybot',
-    tryjob = try_.job(),
-)
-
-try_.chromium_linux_builder(
-    name = 'linux-ozone-rel',
-    tryjob = try_.job(),
-)
-
-try_.chromium_linux_builder(
-    name = 'linux-rel',
-    goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(),
-    use_clang_coverage = True,
-)
-
-try_.chromium_linux_builder(
-    name = 'linux_chromium_asan_rel_ng',
-    goma_jobs = goma.jobs.J150,
-    ssd = True,
-    tryjob = try_.job(),
-)
-
-try_.chromium_linux_builder(
-    name = 'linux_chromium_compile_dbg_ng',
-    caches = [
-        swarming.cache(
-            name = 'builder',
-            path = 'linux_debug',
-        ),
-    ],
-    goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(),
-)
-
-try_.chromium_linux_builder(
-    name = 'linux_chromium_dbg_ng',
-    caches = [
-        swarming.cache(
-            name = 'builder',
-            path = 'linux_debug',
-        ),
-    ],
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/build/.*check_gn_headers.*',
-        ],
-    ),
-)
-
-try_.chromium_linux_builder(
-    name = 'linux_chromium_tsan_rel_ng',
-    goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(),
-)
-
-try_.chromium_linux_builder(
-    name = 'linux_layout_tests_composite_after_paint',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/third_party/blink/renderer/core/paint/.+',
-            '.+/[+]/third_party/blink/renderer/core/svg/.+',
-            '.+/[+]/third_party/blink/renderer/platform/graphics/.+',
-            '.+/[+]/third_party/blink/web_tests/.+',
-        ],
-    ),
-)
-
-try_.chromium_linux_builder(
-    name = 'linux_layout_tests_layout_ng_disabled',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/third_party/blink/renderer/core/editing/.+',
-            '.+/[+]/third_party/blink/renderer/core/layout/.+',
-            '.+/[+]/third_party/blink/renderer/core/paint/.+',
-            '.+/[+]/third_party/blink/renderer/core/svg/.+',
-            '.+/[+]/third_party/blink/renderer/platform/fonts/shaping/.+',
-            '.+/[+]/third_party/blink/renderer/platform/graphics/.+',
-            '.+/[+]/third_party/blink/web_tests/FlagExpectations/disable-layout-ng',
-            '.+/[+]/third_party/blink/web_tests/flag-specific/disable-layout-ng/.+',
-        ],
-    ),
-)
-
-try_.chromium_linux_builder(
-    name = 'linux_vr',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/chrome/browser/vr/.+',
-        ],
-    ),
-)
-
-
-try_.chromium_mac_builder(
-    name = 'mac-rel',
-    goma_jobs = goma.jobs.J150,
-    os = os.MAC_10_13,
-    tryjob = try_.job(),
-)
-
-try_.chromium_mac_builder(
-    name = 'mac_chromium_compile_dbg_ng',
-    goma_jobs = goma.jobs.J150,
-    os = os.MAC_10_13,
-    tryjob = try_.job(),
-)
-
-
-try_.chromium_mac_ios_builder(
-    name = 'ios-simulator',
-    tryjob = try_.job(),
-)
-
-try_.chromium_mac_ios_builder(
-    name = 'ios-simulator-cronet',
-    executable = 'recipe:chromium_trybot',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/components/cronet/.+',
-            '.+/[+]/components/grpc_support/.+',
-            '.+/[+]/ios/.+',
-        ],
-        location_regexp_exclude = [
-            '.+/[+]/components/cronet/android/.+',
-        ],
-    ),
-)
-
-try_.chromium_mac_ios_builder(
-    name = 'ios-simulator-full-configs',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/ios/.+',
-        ],
-    ),
-)
-
-
-try_.chromium_win_builder(
-    name = 'win-libfuzzer-asan-rel',
-    builderless = False,
-    executable = 'recipe:chromium_libfuzzer_trybot',
-    os = os.WINDOWS_ANY,
-    tryjob = try_.job(cancel_stale = False),
-)
-
-try_.chromium_win_builder(
-    name = 'win_chromium_compile_dbg_ng',
-    goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(cancel_stale = False),
-)
-
-try_.chromium_win_builder(
-    name = 'win10_chromium_x64_rel_ng',
-    goma_jobs = goma.jobs.J150,
-    os = os.WINDOWS_10,
-    ssd = True,
-    use_clang_coverage = True,
-    tryjob = try_.job(cancel_stale = False),
-)
-
-
-try_.gpu_chromium_android_builder(
-    name = 'android_optional_gpu_tests_rel',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/cc/.+',
-            '.+/[+]/chrome/browser/vr/.+',
-            '.+/[+]/components/viz/.+',
-            '.+/[+]/content/test/gpu/.+',
-            '.+/[+]/gpu/.+',
-            '.+/[+]/media/audio/.+',
-            '.+/[+]/media/filters/.+',
-            '.+/[+]/media/gpu/.+',
-            '.+/[+]/services/viz/.+',
-            '.+/[+]/testing/trigger_scripts/.+',
-            '.+/[+]/third_party/blink/renderer/modules/webgl/.+',
-            '.+/[+]/third_party/blink/renderer/platform/graphics/gpu/.+',
-            '.+/[+]/tools/clang/scripts/update.py',
-            '.+/[+]/ui/gl/.+',
-        ],
-    ),
-)
-
-
-try_.gpu_chromium_linux_builder(
-    name = 'linux_optional_gpu_tests_rel',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/chrome/browser/vr/.+',
-            '.+/[+]/content/test/gpu/.+',
-            '.+/[+]/gpu/.+',
-            '.+/[+]/media/audio/.+',
-            '.+/[+]/media/filters/.+',
-            '.+/[+]/media/gpu/.+',
-            '.+/[+]/testing/buildbot/chromium.gpu.fyi.json',
-            '.+/[+]/testing/trigger_scripts/.+',
-            '.+/[+]/third_party/blink/renderer/modules/webgl/.+',
-            '.+/[+]/third_party/blink/renderer/platform/graphics/gpu/.+',
-            '.+/[+]/tools/clang/scripts/update.py',
-            '.+/[+]/ui/gl/.+',
-        ],
-    ),
-)
-
-
-try_.gpu_chromium_mac_builder(
-    name = 'mac_optional_gpu_tests_rel',
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/chrome/browser/vr/.+',
-            '.+/[+]/content/test/gpu/.+',
-            '.+/[+]/gpu/.+',
-            '.+/[+]/media/audio/.+',
-            '.+/[+]/media/filters/.+',
-            '.+/[+]/media/gpu/.+',
-            '.+/[+]/services/shape_detection/.+',
-            '.+/[+]/testing/buildbot/chromium.gpu.fyi.json',
-            '.+/[+]/testing/trigger_scripts/.+',
-            '.+/[+]/third_party/blink/renderer/modules/webgl/.+',
-            '.+/[+]/third_party/blink/renderer/platform/graphics/gpu/.+',
-            '.+/[+]/tools/clang/scripts/update.py',
-            '.+/[+]/ui/gl/.+',
-        ],
-    ),
-)
-
-
-try_.gpu_chromium_win_builder(
-    name = 'win_optional_gpu_tests_rel',
-    builderless = True,
-    os = os.WINDOWS_DEFAULT,
-    tryjob = try_.job(
-        location_regexp = [
-            '.+/[+]/chrome/browser/vr/.+',
-            '.+/[+]/content/test/gpu/.+',
-            '.+/[+]/device/vr/.+',
-            '.+/[+]/gpu/.+',
-            '.+/[+]/media/audio/.+',
-            '.+/[+]/media/filters/.+',
-            '.+/[+]/media/gpu/.+',
-            '.+/[+]/testing/buildbot/chromium.gpu.fyi.json',
-            '.+/[+]/testing/trigger_scripts/.+',
-            '.+/[+]/third_party/blink/renderer/modules/vr/.+',
-            '.+/[+]/third_party/blink/renderer/modules/webgl/.+',
-            '.+/[+]/third_party/blink/renderer/modules/xr/.+',
-            '.+/[+]/third_party/blink/renderer/platform/graphics/gpu/.+',
-            '.+/[+]/tools/clang/scripts/update.py',
-            '.+/[+]/ui/gl/.+',
-        ],
-    ),
-)
diff --git a/infra/config/subprojects/chromium/versioned/m83/vars.star b/infra/config/subprojects/chromium/versioned/m83/vars.star
deleted file mode 100644
index a53b239..0000000
--- a/infra/config/subprojects/chromium/versioned/m83/vars.star
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-vars = struct(
-    is_master = False,
-    ref = 'refs/branch-heads/4103',
-    ci_bucket = 'ci-m83',
-    ci_poller = 'm83-gitiles-trigger',
-    main_console_name = 'main-m83',
-    main_console_title = 'Chromium M83 Console',
-    cq_mirrors_console_name = 'mirrors-m83',
-    cq_mirrors_console_title = 'Chromium M83 CQ Mirrors Console',
-    try_bucket = 'try-m83',
-    try_triggering_projects = [],
-    cq_group = 'cq-m83',
-    cq_ref_regexp = 'refs/branch-heads/4103',
-    main_list_view_name = 'try-m83',
-    main_list_view_title = 'Chromium M83 CQ console',
-    tree_status_host = None,
-)
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 591e5cb..50c9d604 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -209,6 +209,7 @@
     "//ios/chrome/browser/omaha",
     "//ios/chrome/browser/passwords",
     "//ios/chrome/browser/reading_list",
+    "//ios/chrome/browser/screenshot",
     "//ios/chrome/browser/search_engines",
     "//ios/chrome/browser/search_engines:extension_search_engine_data_updater",
     "//ios/chrome/browser/share_extension",
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 89c7191..bfc937fcc 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -71,6 +71,7 @@
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h"
 #import "ios/chrome/browser/omaha/omaha_service.h"
 #include "ios/chrome/browser/pref_names.h"
+#import "ios/chrome/browser/screenshot/screenshot_metrics_recorder.h"
 #import "ios/chrome/browser/search_engines/extension_search_engine_data_updater.h"
 #include "ios/chrome/browser/search_engines/search_engines_util.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
@@ -269,6 +270,10 @@
 // The ChromeBrowserState associated with the main (non-OTR) browsing mode.
 @property(nonatomic, assign) ChromeBrowserState* mainBrowserState;  // Weak.
 
+// Handles collecting metrics on user triggered screenshots
+@property(nonatomic, strong)
+    ScreenshotMetricsRecorder* screenshotMetricsRecorder;
+
 // Returns whether the restore infobar should be displayed.
 - (bool)mustShowRestoreInfobar;
 // Returns the set of the sessions ids of the tabs in the given |webStateList|.
@@ -563,6 +568,9 @@
 
   // Now that everything is properly set up, run the tests.
   tests_hook::RunTestsIfPresent();
+
+  self.screenshotMetricsRecorder = [[ScreenshotMetricsRecorder alloc] init];
+  [self.screenshotMetricsRecorder startRecordingMetrics];
 }
 
 - (void)startUpBrowserForegroundInitialization {
diff --git a/ios/chrome/browser/screenshot/BUILD.gn b/ios/chrome/browser/screenshot/BUILD.gn
new file mode 100644
index 0000000..a9664b8d
--- /dev/null
+++ b/ios/chrome/browser/screenshot/BUILD.gn
@@ -0,0 +1,25 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("screenshot") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "screenshot_metrics_recorder.h",
+    "screenshot_metrics_recorder.mm",
+  ]
+  deps = [ "//base" ]
+}
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [ "screenshot_metrics_recorder_unittest.mm" ]
+  deps = [
+    ":screenshot",
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/test:test_support",
+    "//third_party/ocmock",
+  ]
+}
diff --git a/ios/chrome/browser/screenshot/screenshot_metrics_recorder.h b/ios/chrome/browser/screenshot/screenshot_metrics_recorder.h
new file mode 100644
index 0000000..745a63a
--- /dev/null
+++ b/ios/chrome/browser/screenshot/screenshot_metrics_recorder.h
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium 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 <Foundation/Foundation.h>
+
+#ifndef IOS_CHROME_BROWSER_SCREENSHOT_SCREENSHOT_METRICS_RECORDER_H_
+#define IOS_CHROME_BROWSER_SCREENSHOT_SCREENSHOT_METRICS_RECORDER_H_
+
+// ScreenshotMetricsRecorder presents the public interface for
+// the screenshot metric collection.
+@interface ScreenshotMetricsRecorder : NSObject
+
+// Will start recording UMA metrics.
+- (void)startRecordingMetrics;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_SCREENSHOT_SCREENSHOT_METRICS_RECORDER_H_
diff --git a/ios/chrome/browser/screenshot/screenshot_metrics_recorder.mm b/ios/chrome/browser/screenshot/screenshot_metrics_recorder.mm
new file mode 100644
index 0000000..eafe2db
--- /dev/null
+++ b/ios/chrome/browser/screenshot/screenshot_metrics_recorder.mm
@@ -0,0 +1,78 @@
+// Copyright 2020 The Chromium 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/screenshot/screenshot_metrics_recorder.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// UMA metric name for single screen screenshot captures.
+char const* kSingleScreenUserActionName = "MobileSingleScreenScreenshot";
+}  // namespace
+
+@implementation ScreenshotMetricsRecorder
+
+#pragma mark - Public
+
+- (void)startRecordingMetrics {
+  [[NSNotificationCenter defaultCenter]
+      addObserver:self
+         selector:@selector(collectMetricFromNotification:)
+             name:@"UIApplicationUserDidTakeScreenshotNotification"
+           object:nil];
+}
+
+#pragma mark - Private
+
+- (void)collectMetricFromNotification:(NSNotification*)notification {
+  // If the device does not support multiple scenes or if the iOS version is
+  // bellow iOS13 it will record the SingleScreenUserActionName metric.
+  // Otherwise it will record the SingleScreenUserActionName metric only if
+  // there is a single window in the foreground.
+  UIApplication* sharedApplication = [UIApplication sharedApplication];
+  NSInteger countForegroundScenes = 1;
+  if (@available(iOS 13, *)) {
+    if (sharedApplication.supportsMultipleScenes) {
+      countForegroundScenes =
+          [self countForegroundScenes:[sharedApplication connectedScenes]];
+    }
+  }
+
+  // Only register screenshots taken of chrome in a single screen in the
+  // foreground.
+  if (countForegroundScenes == 1)
+    base::RecordAction(base::UserMetricsAction(kSingleScreenUserActionName));
+}
+
+#pragma mark - Private
+
+- (NSInteger)countForegroundScenes:(NSSet<UIScene*>*)scenes
+    NS_AVAILABLE_IOS(13.0) {
+  // Inspect the connectScenes and return the number of scenes
+  // in the foreground.
+  NSInteger foregroundSceneCount = 0;
+  for (UIScene* scene in scenes) {
+    switch (scene.activationState) {
+      case UISceneActivationStateForegroundInactive:
+      case UISceneActivationStateForegroundActive:
+        foregroundSceneCount++;
+        break;
+      default:
+        // Catch for UISceneActivationStateUnattached
+        // and UISceneActivationStateBackground.
+        // TODO (crbug.com/1091818): Add state inpection to identify other
+        // scenarios.
+        break;
+    }
+  }
+  return foregroundSceneCount;
+}
+@end
diff --git a/ios/chrome/browser/screenshot/screenshot_metrics_recorder_unittest.mm b/ios/chrome/browser/screenshot/screenshot_metrics_recorder_unittest.mm
new file mode 100644
index 0000000..0c4e8685
--- /dev/null
+++ b/ios/chrome/browser/screenshot/screenshot_metrics_recorder_unittest.mm
@@ -0,0 +1,152 @@
+// Copyright 2020 The Chromium 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/screenshot/screenshot_metrics_recorder.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/test/metrics/user_action_tester.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// UMA metric name for single screen screenshot captures.
+char const* kSingleScreenUserActionName = "MobileSingleScreenScreenshot";
+}  // namespace
+
+class ScreenshotMetricsRecorderTest : public PlatformTest {
+ protected:
+  ScreenshotMetricsRecorderTest() {}
+  ~ScreenshotMetricsRecorderTest() override {}
+
+  void SetUp() override {
+    application_partial_mock_ =
+        OCMPartialMock([UIApplication sharedApplication]);
+    screenshot_metrics_recorder_ = [[ScreenshotMetricsRecorder alloc] init];
+    [screenshot_metrics_recorder_ startRecordingMetrics];
+    if (@available(iOS 13, *))
+      window_scene_mock_ = OCMClassMock([UIWindowScene class]);
+  }
+
+  void SendScreenshotNotification() {
+    [NSNotificationCenter.defaultCenter
+        postNotificationName:@"UIApplicationUserDidTakeScreenshotNotification"
+                      object:nil
+                    userInfo:nil];
+  }
+
+  id application_partial_mock_;
+  id window_scene_mock_;
+  base::UserActionTester user_action_tester_;
+  ScreenshotMetricsRecorder* screenshot_metrics_recorder_;
+};
+
+// Tests when a UIApplicationUserDidTakeScreenshotNotification
+// happens on a device with an iOS less than 13.
+TEST_F(ScreenshotMetricsRecorderTest, iOS12Screenshot) {
+  // Expected: Metric recorded
+  if (@available(iOS 13, *))
+    // If iOS13 test will automatically pass
+    return;
+
+  SendScreenshotNotification();
+  EXPECT_EQ(1, user_action_tester_.GetActionCount(kSingleScreenUserActionName));
+}
+
+// Tests when a UIApplicationUserDidTakeScreenshotNotification
+// happens on a device where multiple windows are not enabled.
+TEST_F(ScreenshotMetricsRecorderTest, iOS13MultiWindowNotEnabled) {
+  // Expected: Metric recorded
+  if (@available(iOS 13, *)) {
+    OCMStub([application_partial_mock_ supportsMultipleScenes]).andReturn(NO);
+    SendScreenshotNotification();
+    EXPECT_EQ(1,
+              user_action_tester_.GetActionCount(kSingleScreenUserActionName));
+  }
+}
+
+// Tests that a metric is logged if there's a single screen with a single window
+// and a UIApplicationUserDidTakeScreenshotNotification is sent.
+TEST_F(ScreenshotMetricsRecorderTest, iOS13SingleScreenSingleWindow) {
+  // Expected: Metric recorded
+  if (@available(iOS 13, *)) {
+    OCMStub([application_partial_mock_ supportsMultipleScenes]).andReturn(YES);
+
+    id window_scene_mock_ = OCMClassMock([UIWindowScene class]);
+    // Mark the window as foregroundActive
+    OCMStub([window_scene_mock_ activationState])
+        .andReturn(UISceneActivationStateForegroundActive);
+
+    NSSet* scenes = [NSSet setWithObject:window_scene_mock_];
+    // Attach it to the sharedApplication
+    OCMStub([application_partial_mock_ connectedScenes]).andReturn(scenes);
+    SendScreenshotNotification();
+    EXPECT_EQ(1,
+              user_action_tester_.GetActionCount(kSingleScreenUserActionName));
+  }
+}
+
+// Tests that a metric is logged if there're are multiple screens each with
+// a single window and a UIApplicationUserDidTakeScreenshotNotification is
+// sent.
+TEST_F(ScreenshotMetricsRecorderTest, iOS13MultiScreenSingleWindow) {
+  // Expected: Metric recorded
+  if (@available(iOS 13, *)) {
+    OCMStub([application_partial_mock_ supportsMultipleScenes]).andReturn(YES);
+
+    // Mark the window as foregroundActive.
+    id foreground_window_scene_mock = OCMClassMock([UIWindowScene class]);
+    OCMStub([window_scene_mock_ activationState])
+        .andReturn(UISceneActivationStateForegroundActive);
+
+    // Mark the window as Background.
+    id background_window_scene_mock = OCMClassMock([UIWindowScene class]);
+    OCMStub([background_window_scene_mock activationState])
+        .andReturn(UISceneActivationStateBackground);
+
+    NSSet* scenes =
+        [[NSSet alloc] initWithObjects:foreground_window_scene_mock,
+                                       background_window_scene_mock, nil];
+    // Attatch the Scene State to the sharedApplication.
+    OCMStub([application_partial_mock_ connectedScenes]).andReturn(scenes);
+    SendScreenshotNotification();
+    EXPECT_EQ(1,
+              user_action_tester_.GetActionCount(kSingleScreenUserActionName));
+  }
+}
+
+// Tests that a metric is not logged if there is a multi-window screen in the
+// foreground and a UIApplicationUserDidTakeScreenshotNotification is sent.
+TEST_F(ScreenshotMetricsRecorderTest, iOS13MultiScreenMultiWindow) {
+  // Expected: Metric not recorded
+  if (@available(iOS 13, *)) {
+    OCMStub([application_partial_mock_ supportsMultipleScenes]).andReturn(YES);
+
+    // Mark the window as foregroundActive.
+    id first_foreground_window_scene_mock = OCMClassMock([UIWindowScene class]);
+    OCMStub([window_scene_mock_ activationState])
+        .andReturn(UISceneActivationStateForegroundActive);
+
+    // Mark the window as foregroundActive.
+    id second_foreground_window_scene_mock =
+        OCMClassMock([UIWindowScene class]);
+    OCMStub([second_foreground_window_scene_mock activationState])
+        .andReturn(UISceneActivationStateForegroundActive);
+
+    NSSet* scenes = [[NSSet alloc]
+        initWithObjects:first_foreground_window_scene_mock,
+                        second_foreground_window_scene_mock, nil];
+    // Attatch the Scene State to the sharedApplication.
+    OCMStub([application_partial_mock_ connectedScenes]).andReturn(scenes);
+    SendScreenshotNotification();
+    EXPECT_EQ(0,
+              user_action_tester_.GetActionCount(kSingleScreenUserActionName));
+  }
+}
diff --git a/ios/chrome/browser/ui/authentication/signin/add_account_signin/add_account_signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/add_account_signin/add_account_signin_coordinator.mm
index fc2247e0..775c71c 100644
--- a/ios/chrome/browser/ui/authentication/signin/add_account_signin/add_account_signin_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/add_account_signin/add_account_signin_coordinator.mm
@@ -42,8 +42,6 @@
 @property(nonatomic, assign) PromoAction promoAction;
 // Add account sign-in intent.
 @property(nonatomic, assign, readonly) AddAccountSigninIntent signinIntent;
-// Called when the sign-in dialog is interrupted.
-@property(nonatomic, copy) ProceduralBlock interruptCompletion;
 
 @end
 
@@ -82,24 +80,17 @@
   }
 
   DCHECK(self.identityInteractionManager);
-  // IdentityInteractionManager |cancelAndDismissAnimated| will trigger the call
-  // to add account completion in the AddAccountMediator, however we must also
-  // ensure that the interrupt completion is called on sign-in completion.
-  // TODO(crbug.com/1072347): Update IdentityInteractionManager dismiss API.
-  self.interruptCompletion = completion;
-  self.manager.signinInterrupted = YES;
   switch (action) {
-    // SSO doesn't support cancel without dismiss, so to make sure the cancel
-    // is properly done, -[ChromeIdentityInteractionManager
-    // cancelAndDismissAnimated:NO] has to be called.
     case SigninCoordinatorInterruptActionNoDismiss:
     case SigninCoordinatorInterruptActionDismissWithoutAnimation:
-      [self.identityInteractionManager cancelAddAccountWithAnimation:NO
-                                                          completion:nil];
+      [self.identityInteractionManager
+          cancelAddAccountWithAnimation:NO
+                             completion:completion];
       break;
     case SigninCoordinatorInterruptActionDismissWithAnimation:
-      [self.identityInteractionManager cancelAddAccountWithAnimation:YES
-                                                          completion:nil];
+      [self.identityInteractionManager
+          cancelAddAccountWithAnimation:YES
+                             completion:completion];
       break;
   }
 }
@@ -204,9 +195,6 @@
   [self runCompletionCallbackWithSigninResult:signinResult
                                      identity:identity
                    showAdvancedSettingsSignin:NO];
-  if (self.interruptCompletion) {
-    self.interruptCompletion();
-  }
 }
 
 // Presents the user consent screen with |identity| pre-selected.
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
index e32880be..d3f15305 100644
--- a/ios/chrome/browser/ui/history/BUILD.gn
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -70,7 +70,8 @@
   deps = [
     ":constants",
     "public",
-    "resources:empty_history",
+    "resources:history_empty",
+    "resources:legacy_empty_history",
     "//base",
     "//base:i18n",
     "//components/browsing_data/core",
diff --git a/ios/chrome/browser/ui/history/history_table_view_controller.mm b/ios/chrome/browser/ui/history/history_table_view_controller.mm
index 2a9db00..684c1b47 100644
--- a/ios/chrome/browser/ui/history/history_table_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_table_view_controller.mm
@@ -67,6 +67,10 @@
   ItemTypeEntriesStatusWithLink,
   ItemTypeActivityIndicator,
 };
+// Name of the asset to use when history is empty.
+// TODO(crbug.com/1101842): When changing this const with the new asset, delete
+// the old asset.
+NSString* const kEmptyStateImage = @"legacy_empty_history";
 // Section identifier for the header (sync information) section.
 const NSInteger kEntriesStatusSectionIdentifier = kSectionIdentifierEnumZero;
 // Maximum number of entries to retrieve in a single query to history service.
@@ -290,7 +294,7 @@
   // If there are no results and no URLs have been loaded, report that no
   // history entries were found.
   if (results.empty() && self.empty && !self.searchInProgress) {
-    UIImage* emptyImage = [[UIImage imageNamed:@"empty_history"]
+    UIImage* emptyImage = [[UIImage imageNamed:kEmptyStateImage]
         imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
     [self addEmptyTableViewWithMessage:l10n_util::GetNSString(
                                            IDS_HISTORY_NO_RESULTS)
@@ -737,7 +741,7 @@
   if ([self.tableViewModel numberOfSections] == 1) {
     self.empty = YES;
     if (!self.searchInProgress) {
-      UIImage* emptyImage = [[UIImage imageNamed:@"empty_history"]
+      UIImage* emptyImage = [[UIImage imageNamed:kEmptyStateImage]
           imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
       [self addEmptyTableViewWithMessage:l10n_util::GetNSString(
                                              IDS_HISTORY_NO_RESULTS)
diff --git a/ios/chrome/browser/ui/history/resources/BUILD.gn b/ios/chrome/browser/ui/history/resources/BUILD.gn
index ed006a2..f93d3ac 100644
--- a/ios/chrome/browser/ui/history/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/history/resources/BUILD.gn
@@ -4,10 +4,18 @@
 
 import("//build/config/ios/asset_catalog.gni")
 
-imageset("empty_history") {
+imageset("history_empty") {
   sources = [
-    "empty_history.imageset/Contents.json",
-    "empty_history.imageset/empty_history@2x.png",
-    "empty_history.imageset/empty_history@3x.png",
+    "history_empty.imageset/Contents.json",
+    "history_empty.imageset/history_empty.pdf",
+    "history_empty.imageset/history_empty_dark.pdf",
+  ]
+}
+
+imageset("legacy_empty_history") {
+  sources = [
+    "legacy_empty_history.imageset/Contents.json",
+    "legacy_empty_history.imageset/legacy_empty_history@2x.png",
+    "legacy_empty_history.imageset/legacy_empty_history@3x.png",
   ]
 }
diff --git a/ios/chrome/browser/ui/history/resources/empty_history.imageset/Contents.json b/ios/chrome/browser/ui/history/resources/empty_history.imageset/Contents.json
deleted file mode 100644
index 08f9c17..0000000
--- a/ios/chrome/browser/ui/history/resources/empty_history.imageset/Contents.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "empty_history@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "empty_history@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/history/resources/history_empty.imageset/Contents.json b/ios/chrome/browser/ui/history/resources/history_empty.imageset/Contents.json
new file mode 100644
index 0000000..18a10aa
--- /dev/null
+++ b/ios/chrome/browser/ui/history/resources/history_empty.imageset/Contents.json
@@ -0,0 +1,25 @@
+{
+  "images" : [
+    {
+      "filename" : "history_empty.pdf",
+      "idiom" : "universal"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "filename" : "history_empty_dark.pdf",
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "preserves-vector-representation" : true
+  }
+}
diff --git a/ios/chrome/browser/ui/history/resources/history_empty.imageset/history_empty.pdf b/ios/chrome/browser/ui/history/resources/history_empty.imageset/history_empty.pdf
new file mode 100644
index 0000000..8987747
--- /dev/null
+++ b/ios/chrome/browser/ui/history/resources/history_empty.imageset/history_empty.pdf
Binary files differ
diff --git a/ios/chrome/browser/ui/history/resources/history_empty.imageset/history_empty_dark.pdf b/ios/chrome/browser/ui/history/resources/history_empty.imageset/history_empty_dark.pdf
new file mode 100644
index 0000000..7aa7f2a
--- /dev/null
+++ b/ios/chrome/browser/ui/history/resources/history_empty.imageset/history_empty_dark.pdf
Binary files differ
diff --git a/ios/chrome/browser/ui/history/resources/legacy_empty_history.imageset/Contents.json b/ios/chrome/browser/ui/history/resources/legacy_empty_history.imageset/Contents.json
new file mode 100644
index 0000000..e9b2039
--- /dev/null
+++ b/ios/chrome/browser/ui/history/resources/legacy_empty_history.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+    "images": [
+        {
+            "idiom": "universal",
+            "scale": "2x",
+            "filename": "legacy_empty_history@2x.png"
+        },
+        {
+            "idiom": "universal",
+            "scale": "3x",
+            "filename": "legacy_empty_history@3x.png"
+        }
+    ],
+    "info": {
+        "version": 1,
+        "author": "xcode"
+    }
+}
diff --git a/ios/chrome/browser/ui/history/resources/empty_history.imageset/empty_history@2x.png b/ios/chrome/browser/ui/history/resources/legacy_empty_history.imageset/legacy_empty_history@2x.png
similarity index 100%
rename from ios/chrome/browser/ui/history/resources/empty_history.imageset/empty_history@2x.png
rename to ios/chrome/browser/ui/history/resources/legacy_empty_history.imageset/legacy_empty_history@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/history/resources/empty_history.imageset/empty_history@3x.png b/ios/chrome/browser/ui/history/resources/legacy_empty_history.imageset/legacy_empty_history@3x.png
similarity index 100%
rename from ios/chrome/browser/ui/history/resources/empty_history.imageset/empty_history@3x.png
rename to ios/chrome/browser/ui/history/resources/legacy_empty_history.imageset/legacy_empty_history@3x.png
Binary files differ
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index aa8c671..81103ec 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -213,6 +213,7 @@
     "//ios/chrome/browser/reading_list:unit_tests",
     "//ios/chrome/browser/safe_browsing:unit_tests",
     "//ios/chrome/browser/safe_mode:unit_tests",
+    "//ios/chrome/browser/screenshot:unit_tests",
     "//ios/chrome/browser/search_engines:unit_tests",
     "//ios/chrome/browser/send_tab_to_self:unit_tests",
     "//ios/chrome/browser/sessions:unit_tests",
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm
index f52a311..50e263fc 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm
@@ -120,29 +120,35 @@
 - (void)cancelAddAccountWithAnimation:(BOOL)animated
                            completion:(void (^)(void))completion {
   [self dismissAndRunCompletionCallbackWithError:[self canceledError]
-                                        animated:animated];
+                                        animated:animated
+                                      completion:completion];
 }
 
 - (void)addAccountViewControllerDidTapSignIn {
   ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
       ->AddIdentity(_fakeIdentity);
-  [self dismissAndRunCompletionCallbackWithError:nil animated:YES];
+  [self dismissAndRunCompletionCallbackWithError:nil
+                                        animated:YES
+                                      completion:nil];
 }
 
 - (void)addAccountViewControllerDidTapCancel {
   [self dismissAndRunCompletionCallbackWithError:[self canceledError]
-                                        animated:YES];
+                                        animated:YES
+                                      completion:nil];
 }
 
 - (void)addAccountViewControllerDidThrowUnhandledError {
   [self dismissAndRunCompletionCallbackWithError:[self unhandledError]
-                                        animated:YES];
+                                        animated:YES
+                                      completion:nil];
 }
 
 #pragma mark Helper
 
 - (void)dismissAndRunCompletionCallbackWithError:(NSError*)error
-                                        animated:(BOOL)animated {
+                                        animated:(BOOL)animated
+                                      completion:(void (^)(void))completion {
   if (!_viewController) {
     [self runCompletionCallbackWithError:error];
     return;
@@ -151,6 +157,9 @@
       dismissViewControllerAnimated:animated
                          completion:^{
                            [self runCompletionCallbackWithError:error];
+                           if (completion) {
+                             completion();
+                           }
                          }];
 }
 
diff --git a/media/base/android/android_cdm_factory.cc b/media/base/android/android_cdm_factory.cc
index faa670f..1c7ef30 100644
--- a/media/base/android/android_cdm_factory.cc
+++ b/media/base/android/android_cdm_factory.cc
@@ -82,9 +82,10 @@
   auto* raw_factory = factory.get();
 
   creation_id_++;
-  pending_creations_.emplace(
+  auto result = pending_creations_.emplace(
       creation_id_,
       PendingCreation(std::move(factory), std::move(bound_cdm_created_cb)));
+  CHECK(result.second);
 
   raw_factory->Create(key_system, cdm_config, session_message_cb,
                       session_closed_cb, session_keys_change_cb,
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index ec65dea1..1e4954d 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -393,6 +393,7 @@
       "android/codec_wrapper_unittest.cc",
       "android/fake_codec_allocator.cc",
       "android/fake_codec_allocator.h",
+      "android/frame_info_helper_unittest.cc",
       "android/maybe_render_early_manager_unittest.cc",
       "android/media_codec_video_decoder_unittest.cc",
       "android/mock_android_video_surface_chooser.cc",
diff --git a/media/gpu/android/codec_output_buffer_renderer.h b/media/gpu/android/codec_output_buffer_renderer.h
index 69e6ea73..9984ba6c 100644
--- a/media/gpu/android/codec_output_buffer_renderer.h
+++ b/media/gpu/android/codec_output_buffer_renderer.h
@@ -78,6 +78,7 @@
   }
 
  private:
+  friend class FrameInfoHelperTest;
   // The lifecycle phases of an buffer.
   // The only possible transitions are from left to right. Both
   // kInFrontBuffer and kInvalidated are terminal.
@@ -85,6 +86,8 @@
 
   void EnsureBoundIfNeeded(BindingsMode mode);
 
+  void set_phase_for_testing(Phase phase) { phase_ = phase; }
+
   // The phase of the image buffer's lifecycle.
   Phase phase_ = Phase::kInCodec;
 
diff --git a/media/gpu/android/frame_info_helper.cc b/media/gpu/android/frame_info_helper.cc
index efe1873..fa336422 100644
--- a/media/gpu/android/frame_info_helper.cc
+++ b/media/gpu/android/frame_info_helper.cc
@@ -30,6 +30,8 @@
       stub_->AddDestructionObserver(this);
   }
 
+  FrameInfoHelperImpl() = default;
+
   ~FrameInfoHelperImpl() override {
     if (stub_)
       stub_->RemoveDestructionObserver(this);
@@ -77,7 +79,7 @@
       }
     }
 
-    std::move(cb).Run(std::move(buffer_renderer), frame_info_, success);
+    std::move(cb).Run(std::move(buffer_renderer), info, success);
   }
 
   void OnWillDestroyStub(bool have_context) override {
@@ -117,4 +119,8 @@
                                                   std::move(get_stub_cb));
 }
 
+std::unique_ptr<FrameInfoHelper> FrameInfoHelper::CreateForTesting() {
+  return std::make_unique<FrameInfoHelperImpl>();
+}
+
 }  // namespace media
diff --git a/media/gpu/android/frame_info_helper.h b/media/gpu/android/frame_info_helper.h
index 5fc4ffc..60d9ace 100644
--- a/media/gpu/android/frame_info_helper.h
+++ b/media/gpu/android/frame_info_helper.h
@@ -33,6 +33,8 @@
       scoped_refptr<base::SequencedTaskRunner> gpu_task_runner,
       SharedImageVideoProvider::GetStubCB get_stub_cb);
 
+  static std::unique_ptr<FrameInfoHelper> CreateForTesting();
+
   virtual ~FrameInfoHelper() = default;
 
   // Call |cb| with the FrameInfo.  Will render |buffer_renderer| to the front
diff --git a/media/gpu/android/frame_info_helper_unittest.cc b/media/gpu/android/frame_info_helper_unittest.cc
new file mode 100644
index 0000000..053d198
--- /dev/null
+++ b/media/gpu/android/frame_info_helper_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/gpu/android/frame_info_helper.h"
+
+#include "base/test/bind_test_util.h"
+#include "base/test/task_environment.h"
+#include "gpu/command_buffer/service/mock_texture_owner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+using testing::SetArgPointee;
+
+namespace media {
+namespace {
+constexpr gfx::Size kTestVisibleSize(100, 100);
+constexpr gfx::Size kTestVisibleSize2(110, 110);
+constexpr gfx::Size kTestCodedSize(128, 128);
+}  // namespace
+
+class FrameInfoHelperTest : public testing::Test {
+ public:
+  FrameInfoHelperTest() : helper_(FrameInfoHelper::CreateForTesting()) {}
+
+ protected:
+  void GetFrameInfo(
+      std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer) {
+    const auto* buffer_renderer_raw = buffer_renderer.get();
+    bool called = false;
+    auto callback = base::BindLambdaForTesting(
+        [&](std::unique_ptr<CodecOutputBufferRenderer> buffer_renderer,
+            FrameInfoHelper::FrameInfo info, bool success) {
+          ASSERT_EQ(buffer_renderer_raw, buffer_renderer.get());
+          called = true;
+          last_get_frame_info_succeeded_ = success;
+          last_frame_info_ = info;
+        });
+    helper_->GetFrameInfo(std::move(buffer_renderer), callback);
+    ASSERT_TRUE(called);
+  }
+
+  std::unique_ptr<CodecOutputBufferRenderer> CreateBufferRenderer(
+      gfx::Size size,
+      scoped_refptr<gpu::TextureOwner> texture_owner) {
+    auto codec_buffer_wait_coordinator =
+        texture_owner
+            ? base::MakeRefCounted<CodecBufferWaitCoordinator>(texture_owner)
+            : nullptr;
+    auto buffer = CodecOutputBuffer::CreateForTesting(0, size);
+    auto buffer_renderer = std::make_unique<CodecOutputBufferRenderer>(
+        std::move(buffer), codec_buffer_wait_coordinator);
+
+    // We don't have codec, so releasing test buffer is not possible. Mark it as
+    // rendered for test purpose.
+    buffer_renderer->set_phase_for_testing(
+        CodecOutputBufferRenderer::Phase::kInFrontBuffer);
+    return buffer_renderer;
+  }
+
+  void FailNextRender(CodecOutputBufferRenderer* buffer_renderer) {
+    buffer_renderer->set_phase_for_testing(
+        CodecOutputBufferRenderer::Phase::kInvalidated);
+  }
+
+  base::test::SingleThreadTaskEnvironment task_environment_;
+
+  std::unique_ptr<FrameInfoHelper> helper_;
+  bool last_get_frame_info_succeeded_ = false;
+  FrameInfoHelper::FrameInfo last_frame_info_;
+};
+
+TEST_F(FrameInfoHelperTest, NoBufferRenderer) {
+  // If there is no buffer renderer we shouldn't crash and report that request
+  // failed.
+  GetFrameInfo(nullptr);
+  EXPECT_FALSE(last_get_frame_info_succeeded_);
+}
+
+TEST_F(FrameInfoHelperTest, TextureOwner) {
+  auto texture_owner = base::MakeRefCounted<NiceMock<gpu::MockTextureOwner>>(
+      0, nullptr, nullptr, true);
+
+  // Return CodedSize when GetCodedSizeAndVisibleRect is called.
+  ON_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _))
+      .WillByDefault(SetArgPointee<1>(kTestCodedSize));
+
+  // Fail rendering buffer.
+  auto buffer1 = CreateBufferRenderer(kTestVisibleSize, texture_owner);
+  FailNextRender(buffer1.get());
+  // GetFrameInfo should fallback to visible size in this case, but mark request
+  // as failed.
+  EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0);
+  GetFrameInfo(std::move(buffer1));
+  EXPECT_FALSE(last_get_frame_info_succeeded_);
+  EXPECT_EQ(last_frame_info_.coded_size, kTestVisibleSize);
+  Mock::VerifyAndClearExpectations(texture_owner.get());
+
+  // This time rendering should succeed. We expect GetCodedSizeAndVisibleRect to
+  // be called and result should be kTestCodedSize instead of kTestVisibleSize.
+  EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(1);
+  GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, texture_owner));
+  EXPECT_TRUE(last_get_frame_info_succeeded_);
+  EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
+  Mock::VerifyAndClearExpectations(texture_owner.get());
+
+  // Verify that we don't render frame on subsequent calls with the same visible
+  // size. GetCodedSizeAndVisibleRect should not be called.
+  EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(0);
+  GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, texture_owner));
+  EXPECT_TRUE(last_get_frame_info_succeeded_);
+  EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
+  Mock::VerifyAndClearExpectations(texture_owner.get());
+
+  // Verify that we render if the visible size changed.
+  EXPECT_CALL(*texture_owner, GetCodedSizeAndVisibleRect(_, _, _)).Times(1);
+  GetFrameInfo(CreateBufferRenderer(kTestVisibleSize2, texture_owner));
+  EXPECT_TRUE(last_get_frame_info_succeeded_);
+  EXPECT_EQ(last_frame_info_.coded_size, kTestCodedSize);
+}
+
+TEST_F(FrameInfoHelperTest, Overlay) {
+  // In overlay case we always use visible size.
+  GetFrameInfo(CreateBufferRenderer(kTestVisibleSize, nullptr));
+  EXPECT_TRUE(last_get_frame_info_succeeded_);
+  EXPECT_EQ(last_frame_info_.coded_size, kTestVisibleSize);
+}
+
+}  // namespace media
diff --git a/media/gpu/android/video_frame_factory_impl.cc b/media/gpu/android/video_frame_factory_impl.cc
index 094d45a..1c264f9 100644
--- a/media/gpu/android/video_frame_factory_impl.cc
+++ b/media/gpu/android/video_frame_factory_impl.cc
@@ -113,6 +113,10 @@
   // changing the TextureOwner.  This is temporary.  See ImageSpec.
   image_spec_.generation_id++;
 
+  // Reset cached visible size as we might switched between overlay and texture
+  // owner mode.
+  visible_size_ = gfx::Size();
+
   if (!surface_bundle) {
     // Clear everything, just so we're not holding a reference.
     codec_buffer_wait_coordinator_ = nullptr;
diff --git a/net/base/backoff_entry_serializer.cc b/net/base/backoff_entry_serializer.cc
index c4aef82..8a282c2 100644
--- a/net/base/backoff_entry_serializer.cc
+++ b/net/base/backoff_entry_serializer.cc
@@ -88,6 +88,8 @@
   // against the clock being wound forward).
   if (backoff_duration > original_backoff_duration)
     backoff_duration = original_backoff_duration;
+  if (backoff_duration.is_min() || backoff_duration.is_max())
+    return nullptr;
   entry->SetCustomReleaseTime(
       entry->BackoffDurationToReleaseTime(backoff_duration));
 
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index c0048f7..e63d066 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -53667,7 +53667,6 @@
     { "name": "xliang.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xmine128.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xn--ehqw04eq6e.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "yhenke.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "youpickfarms.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "your-waterserver.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "youthrules.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -110576,7 +110575,6 @@
     { "name": "damacosmeticos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dancesafe.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dannys.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "davidskinnerantiques.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dealershipdrop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "delta-wings.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "deltaworkssecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -113233,6 +113231,602 @@
     { "name": "zephera.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zinglix.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zoflora.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "24ohrana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2sendai.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "4-0-4.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "99999999977.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aakf.org.pk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aaronburrows.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abdulkarimm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abdullaeff.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abu-auftrag.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "acadiate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "achkandiro.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "action-biosphere.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "active-baby.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adamabernathy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "administratorhandal.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adultlance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agata-privathospital.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agendas.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agrus-wow.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ahmud.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aicupom.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "akbam.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alcoholia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alexalist.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alimeta.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allfashionews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "allfit.com.tr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alnamic.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alvirzy.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "an0ns.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anderstornkvist.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "andressaflores.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "angelishansen.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "antykilion.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "arbeitskraft.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ardyaloon.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "asianbusinesscards.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "astralyx.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "atlanticcitycasino.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "atlanticcitycasinonews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "atrands.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autobazarcentrum.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autobraga.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aventurasnorowa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "balearicholidu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bambusushibar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "batterijeshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bekmekci.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "benleb.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestcreditcards.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestcreditcards.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestcreditcards.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestcreditcards.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bestcreditcards.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bierbaumer.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "biocbd.hr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoin-casino.monster", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincasino.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincasino.casino", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincasino.exposed", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincasino.icu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincasino.link", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincasino.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincasino.monster", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincasino.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincasino.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoincodereview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinera-review.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinfaucet.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoingambling.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoingames.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinnews.company", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinnews.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinnews.guru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinnews.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinprice.buzz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinprice.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinprice.international", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinprice.monster", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinprice.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinprice.pizza", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinprice.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinprice.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcoinslots.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bitcointrader-review.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bivi.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blackforlife.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bloggingsaif.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bmzm.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bopyx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "boringnews.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bracebridgechiro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bredabeds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bubu1.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "buyitnowfast.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cafemandala.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "camerashot.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "capsulecorp.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carberra.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carberra.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casadegomes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casino.fail", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casino.tires", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casino.viajes", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casinos.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cbdlession.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ccamatilfiji.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "certificateoflogistics.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chanakyanewz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chekhov.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chiamami.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chihirev.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chooseyourdesinty.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chrawrizard.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ciblogin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ciltskillnet.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ciphermail.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "circuses.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clearvisiontea.com.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cloudindia.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cloudmarathi.work", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubgalileo.com.ec", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coachingmillenium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "comsoli.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "contato.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "corriere.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "costantinogaming.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cparta.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crash.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cswapps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cultbeauty.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cultbeauty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cwallpapersheb.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cyberschmiede.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cyberschmiede.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cyberschmiede.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "czqu.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "daily-city.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dajjal.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "daveroverts.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davincigourmet.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "deanpearce.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "deluxeblogtips.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "demostweb.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "develoupe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "diegoisla.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dispur.nic.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dlmixcloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dobavki.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dot9dev.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dournois.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "downbook.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drdavidricketts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "droneways.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "duansunshinesdiamond.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dvwa.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "e-estonia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ecamisetas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eclipse4academia-startups.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "egypttimetravel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "egypttravelz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enky.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eperformax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eritropoyetina.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "escolaisttucano.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "esexchange.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "estonia.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ethereumnews.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ethereumnews.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ethereumnews.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ethereumnews.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ethereumnews.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "etimmer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "etororeview.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "etororeview.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "etororeview.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "etororeviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "europrimereviews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eurotech-cnc.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eurovision-romania.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eyelash-mc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "facebar.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "faieurope.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fatsnack.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fcarrascosa.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "festival365.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "festivalesargentina.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "figbert.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "financebottom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fizzcoronationstreetdied.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fleetster.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fleetster.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "flippery-wynajem.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "forexcomreview.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "forexinthai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "forexmarketsm.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fortistci.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freebitcoinfaucet.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freepatternsarea.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "frisaga.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "frisaga.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "frisaga.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "frisaga.travel", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "friv-2018.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fundaciongoldeoro.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fxbrokerreview.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fxbrokerreviews.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fxnews.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fxnotch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gabe.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "galileoart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "game-graph.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "garfieldairlines.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gasmar.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gauravtiwari.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "geddert.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "geneeskrachtig.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "genkihub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "genkiwork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "geobennett.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gerenciaconsultor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gibranhernandez.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "glamourtime.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "godating.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "golfmagic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "good-wishes-4-u.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "goodsite.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gottika.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gpbdev.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gplclubbd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gpspolis.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "graph.games", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "greenzved.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gretathemes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "grland.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gslabnet.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "halodebki.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "health4food.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "healthbank.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hectorfiorini.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "helix.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "helpcentral.ng", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "herkel.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hexg.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "highdaseo.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hinksonlabs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "histogames.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "holyscriptur.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "homeairguides.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hot100.ug", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hotdresses.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hotelsonline.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "houhuayuan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hsreformas.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hymnsandverses.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hyodyntamaton.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "icze4r.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "icze4r.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "icze4r.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "icze4r.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ideice.gob.do", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iftikharalam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iitneetprep.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ikasgela.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "impresapulizie.milano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inakasoftware.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inceneritore.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "infomexico.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "infoserp.net.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ingenious-development.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "innovativeactors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "insotech.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "interactivebrokersreview.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "intergermania.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "investinestonia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ioghawaii.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "irr52.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "irr59.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "islamerkantho.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iswag.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "itsca.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "izolyatsia.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "izone.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jacopomolina.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jfy.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joannajankowska.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jonnygreenwood.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jrock.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jy11.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k2analytics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kakazai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kappawingman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "karlov.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "khalidalnajjar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kienviethung.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kingtech8.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kiseimarriage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kiwi-pics.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "klinto.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kokica.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kokotaru.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lafyne.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lagunaklub.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lasvegascasinonews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "legal.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "legna.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "leleimports.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "levis.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "levisenlaw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lifeskills-education.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lindazi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "linkinsta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "livinkitchen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "magic-carpetcleaning.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "magsty.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maisecom.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mamaisonsherby.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "markdown.help", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "marliesslomp.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "martinsciekurs.lv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maskssouthafrica.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maximbaz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mazury-invest.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medcenter.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medcentr.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medcourse.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medservis.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "metabox.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mightful-noobs.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mikemcgeephotography.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "milkaholic.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "miragenews.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mobilhaber.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "modanese.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mof.gov.ws", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "molenaar-ricardo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moneyformybeer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moremindsbetter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "motivationshastra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mpcmsa.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mr-a.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mrluggagex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mstdn.fm", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mumbaigaming.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "muziektermen.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mybeancloud.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myclimate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mycontactopticien.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mydslwebstats.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myempire.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mygizmolife.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mynutrientcloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mysticmedia.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nairobisweet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "naklejki-plombowe.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nar-lekar.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "navnet.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nawaqees.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "neocharge.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "newsarticle.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nhakhoaflora.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nhanlucnhatban.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nicheosala.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nk-vision.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nkontur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "norbertorabinovichblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "notimesupport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nunogand.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oandareview.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "obscur.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "odiris.lk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oloadvid.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "one-clue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "orgtech.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ourharvest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "overcasthq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oxlab.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oxudummedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "paperworkspace.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parijattechnologies.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "paulchua.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "performanceetcoaching.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "petemerges.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "petops.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "physia.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "piknichok.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "piotrlewandowski.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pixstash.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "plashenkov.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "podarky.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pokemongosearch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pokerblog.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "polarhome.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "porsiaedenora.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "posadalasalbarcas.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "positive.photography", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "powerzonewrestling.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pozitiffchik.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "predalco.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "primeops.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "privatedns.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "productleaders.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pubertytalk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "puebladesoto.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pupon.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qeshmminer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qr.sb", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rahedm.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rammsteinaustralia.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ras34.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rbscrochet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "recoveryteam.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "recursosmi.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reley.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "retardedstudios.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ribdigital.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ringlightstudios.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ripplenews.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rjicpas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rodrydesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "roofdoctorutah.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "roolnews.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rosdpk.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royalcitystudios.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royaltyexchange.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rydeify.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "samurai-implant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanin.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sankyo-sys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sapienza-eclipse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sapienzaconsulting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "scindustries.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "scour.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "scoutingwijchen-bouwproject.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "searchexperts.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sei-yu.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sendaimori.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "senseful-online.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "servonline.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seteampty.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shanxia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sharm.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sheraatours.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shippexx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sikkind.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "silvius.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sincelockdown.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "slated.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "slotsmegacasino.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smanson.duckdns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smartcashumbrella.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smartech.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "snowboard-break.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "solarlider.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sonnenbergharrison.law", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "southessexstatus.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "spacelandpark.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stad.gent", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stanzolo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "startnowmakingmoneyonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "startup-lab.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "steamcleaning.expert", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "steamid.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stellar.guru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stoffhandwerk.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "suike.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "superiorseating.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "swabhoomi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sy95.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sysclouds.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tailor.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "talentx.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tarrasque.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tasteville.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tastyworksreview.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "taxdispute.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tdlconexion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techwise.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teknoekip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teknolama.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teknorix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "temnhan24h.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "texican.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thai-kacha.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thedonaldarchive.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thegoddy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thehomebakery.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thejourneydesignstudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thesimons.family", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thetechsite.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thewealthblog.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tichdiem80.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tiempolibre.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "timmermansadministratie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tnutoys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tobias4.ddns.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tomslawadvice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "topten.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "torsten-werner.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "totalinfo.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tpk.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trade99review.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tradewithestonia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tragaver.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "travelix.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "treatmentindiana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.best", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.global", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.world", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tronnews.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tryingtotakeoversweden.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ttwt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "twigandolive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ucero.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ultimadivisao.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uniekglas.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uniqueuniques.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "unrestricted.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "upstairs.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "urlendecoder.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "usaattorneyblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "usnews-new.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vacpas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vanguardreviews.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vasconcellos.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vegascasino.news", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "verzekerjebeter.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vicenterodriguez81.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "videovt.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vidnoe50.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "visordown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vivachile.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vivantstays.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vos.directory", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "votrespace.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wafflemakers.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "warezbook.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wavee-plus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wealthmu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wealthsuccess.edu.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "weathermelon.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webanet.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webmandat.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webullreview.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "westlondoncarpetcleaners.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "will-lash.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "willalex.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "williamsalexander.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wings.com.pk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wo25.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "world-citizen-report.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "worthlydeals.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wowkia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wpautolistings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wpdgimart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wpfy.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wphaxor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wpslimseo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wpspeedmetrix.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xaudiobooks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xmos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--2i0bo6pvvy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--2i0bo6pvvy.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--2i0bo6pvvy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--2i0bo6pvvy.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--or3bkpg7h2qs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xtechkr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yanagibashi.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yatsat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yourdomain.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yuanandyuan.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zappy.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zero-graph.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zerocms.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zerodhareview.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ziggletech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zoomative.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zpider.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     // END OF 1-YEAR BULK HSTS ENTRIES
 
     // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
diff --git a/net/log/README.md b/net/log/README.md
new file mode 100644
index 0000000..57dd6ae7
--- /dev/null
+++ b/net/log/README.md
@@ -0,0 +1,6 @@
+# Net Log
+
+Mechanism for tracing network events and writing them to a file.
+
+See [net/docs/net-log.md](../docs/net-log.md).
+
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index 8c1b9b04f..f6ef538 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -457,6 +457,7 @@
     ReadAndSendRequestBodyData();
   } else {
     CHECK(spdy_session_->GreasedFramesEnabled());
+    MaybePostRequestCallback(OK);
   }
 }
 
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 085940e..07fe57c 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -1174,6 +1174,77 @@
   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
 }
 
+// Regression test for https://crbug.com/1082683.
+// SendRequest() callback should be called as soon as sending is done,
+// even when sending greased frame type is allowed.
+TEST_F(SpdyHttpStreamTest, DownloadWithGreasedFrames) {
+  const uint8_t type = 0x0b;
+  const uint8_t flags = 0xcc;
+  const std::string payload("foo");
+  session_deps_.greased_http2_frame =
+      base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
+          {type, flags, payload});
+
+  spdy::SpdyHeaderBlock request_headers;
+  request_headers[spdy::kHttp2MethodHeader] = "GET";
+  spdy_util_.AddUrlToHeaderBlock(kDefaultUrl, &request_headers);
+  spdy::SpdySerializedFrame req = spdy_util_.ConstructSpdyHeaders(
+      1, std::move(request_headers), LOWEST, /* fin = */ false);
+
+  const char kRawFrameData[] = {
+      0x00, 0x00, 0x03,        // length
+      0x0b,                    // type
+      0xcc,                    // flags
+      0x00, 0x00, 0x00, 0x01,  // stream ID
+      'f',  'o',  'o'          // payload
+  };
+  spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
+                                   base::size(kRawFrameData),
+                                   /* owns_buffer = */ false);
+
+  spdy::SpdySerializedFrame empty_body(
+      spdy_util_.ConstructSpdyDataFrame(1, "", true));
+
+  MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
+                        CreateMockWrite(empty_body, 2)};
+
+  // This test only concerns the request,
+  // no need to construct a meaningful response.
+  MockRead reads[] = {
+      MockRead(ASYNC, ERR_IO_PENDING, 3),  // Pause reads.
+      MockRead(ASYNC, 0, 4)                // Close connection.
+  };
+
+  InitSession(reads, writes);
+
+  HttpRequestInfo request;
+  request.method = "GET";
+  request.url = url_;
+  request.traffic_annotation =
+      MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+  TestCompletionCallback callback;
+  HttpResponseInfo response;
+  HttpRequestHeaders headers;
+  NetLogWithSource net_log;
+  auto http_stream = std::make_unique<SpdyHttpStream>(
+      session_, kNoPushedStreamFound, net_log.source());
+
+  int rv = http_stream->InitializeStream(&request, true, DEFAULT_PRIORITY,
+                                         net_log, CompletionOnceCallback());
+  EXPECT_THAT(rv, IsOk());
+
+  rv = http_stream->SendRequest(headers, &response, callback.callback());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  // The request callback should be called even though response has not been
+  // received yet.
+  rv = callback.WaitForResult();
+  EXPECT_THAT(rv, IsOk());
+
+  sequenced_data_->Resume();
+  base::RunLoop().RunUntilIdle();
+}
+
 // TODO(willchan): Write a longer test for SpdyStream that exercises all
 // methods.
 
diff --git a/pdf/DEPS b/pdf/DEPS
index 064897d4..253bb53 100644
--- a/pdf/DEPS
+++ b/pdf/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+chrome/common/content_restriction.h",
   "+net",
   "+ppapi",
   "+printing/units.h",
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index a2f5e89..1c126a5 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -23,7 +23,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/common/content_restriction.h"
 #include "net/base/escape.h"
 #include "net/base/filename_util.h"
 #include "pdf/accessibility.h"
@@ -1406,7 +1405,7 @@
     // would generate an incomplete document.  Need to do this each time we
     // call DidStartLoading since that resets the content restrictions.
     pp::PDF::SetContentRestriction(
-        this, CONTENT_RESTRICTION_SAVE | CONTENT_RESTRICTION_PRINT);
+        this, PP_CONTENT_RESTRICTION_SAVE | PP_CONTENT_RESTRICTION_PRINT);
   }
 
   return CreateURLLoaderInternal();
@@ -1471,13 +1470,13 @@
   }
 
   int content_restrictions =
-      CONTENT_RESTRICTION_CUT | CONTENT_RESTRICTION_PASTE;
+      PP_CONTENT_RESTRICTION_CUT | PP_CONTENT_RESTRICTION_PASTE;
   if (!engine_->HasPermission(PDFEngine::PERMISSION_COPY))
-    content_restrictions |= CONTENT_RESTRICTION_COPY;
+    content_restrictions |= PP_CONTENT_RESTRICTION_COPY;
 
   if (!engine_->HasPermission(PDFEngine::PERMISSION_PRINT_LOW_QUALITY) &&
       !engine_->HasPermission(PDFEngine::PERMISSION_PRINT_HIGH_QUALITY)) {
-    content_restrictions |= CONTENT_RESTRICTION_PRINT;
+    content_restrictions |= PP_CONTENT_RESTRICTION_PRINT;
   }
 
   pp::PDF::SetContentRestriction(this, content_restrictions);
diff --git a/ppapi/c/private/ppb_pdf.h b/ppapi/c/private/ppb_pdf.h
index 26703721..4ddb3ca 100644
--- a/ppapi/c/private/ppb_pdf.h
+++ b/ppapi/c/private/ppb_pdf.h
@@ -22,6 +22,14 @@
   PP_PDFFEATURE_PRINTING = 1
 } PP_PDFFeature;
 
+typedef enum {
+  PP_CONTENT_RESTRICTION_COPY = 1 << 0,
+  PP_CONTENT_RESTRICTION_CUT = 1 << 1,
+  PP_CONTENT_RESTRICTION_PASTE = 1 << 2,
+  PP_CONTENT_RESTRICTION_PRINT = 1 << 3,
+  PP_CONTENT_RESTRICTION_SAVE = 1 << 4
+} PP_ContentRestriction;
+
 struct PP_PrivateFontFileDescription {
   const char* face;
   uint32_t weight;
@@ -381,7 +389,7 @@
   void (*DidStopLoading)(PP_Instance instance);
 
   // Sets content restriction for a full-page plugin (i.e. can't copy/print).
-  // The value is a bitfield of ContentRestriction enums.
+  // The value is a bitfield of PP_ContentRestriction enums.
   void (*SetContentRestriction)(PP_Instance instance, int restrictions);
 
   // Notifies the browser that the given action has been performed.
diff --git a/printing/BUILD.gn b/printing/BUILD.gn
index 6995990f..9512116 100644
--- a/printing/BUILD.gn
+++ b/printing/BUILD.gn
@@ -166,7 +166,7 @@
       ]
     }
 
-    libs = [
+    frameworks = [
       "AppKit.framework",
       "QuartzCore.framework",
       "ApplicationServices.framework",
diff --git a/printing/backend/cups_jobs.cc b/printing/backend/cups_jobs.cc
index 15919648..c09871e1 100644
--- a/printing/backend/cups_jobs.cc
+++ b/printing/backend/cups_jobs.cc
@@ -262,7 +262,10 @@
   } else if (name == kJobStateReasons) {
     ParseCollection(attr, &(job->state_reasons));
   } else if (name == kJobStateMessage) {
-    job->state_message = ippGetString(attr, 0, nullptr);
+    const char* message_string = ippGetString(attr, 0, nullptr);
+    if (message_string) {
+      job->state_message = message_string;
+    }
   } else if (name == kTimeAtProcessing) {
     job->processing_started = ippGetInteger(attr, 0);
   }
@@ -306,7 +309,10 @@
     base::StringPiece name = ippGetName(attr);
     if (name == base::StringPiece(kPrinterMakeAndModel)) {
       DCHECK_EQ(IPP_TAG_TEXT, ippGetValueTag(attr));
-      printer_info->make_and_model = ippGetString(attr, 0, nullptr);
+      const char* make_and_model_string = ippGetString(attr, 0, nullptr);
+      if (make_and_model_string) {
+        printer_info->make_and_model = make_and_model_string;
+      }
     } else if (name == base::StringPiece(kIppVersionsSupported)) {
       std::vector<std::string> ipp_versions;
       ParseCollection(attr, &ipp_versions);
diff --git a/remoting/host/disconnect_window_mac.h b/remoting/host/disconnect_window_mac.h
index da6589d..5b7a9ce 100644
--- a/remoting/host/disconnect_window_mac.h
+++ b/remoting/host/disconnect_window_mac.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef REMOTING_HOST_DISCONNECT_WINDOW_MAC_H_
+#define REMOTING_HOST_DISCONNECT_WINDOW_MAC_H_
+
 #import <Cocoa/Cocoa.h>
 
 #include <string>
@@ -14,11 +17,11 @@
 // quickly disconnect a session.
 @interface DisconnectWindowController : NSWindowController {
  @private
-  base::Closure _disconnect_callback;
+  base::OnceClosure _disconnect_callback;
   base::string16 _username;
 }
 
-- (id)initWithCallback:(const base::Closure&)disconnect_callback
+- (id)initWithCallback:(base::OnceClosure)disconnect_callback
               username:(const std::string&)username
                 window:(NSWindow*)window;
 - (void)initializeWindow;
@@ -35,3 +38,5 @@
 // it can be instantiated via a xib.
 @interface DisconnectView : NSView
 @end
+
+#endif  // REMOTING_HOST_DISCONNECT_WINDOW_MAC_H_
diff --git a/remoting/host/disconnect_window_mac.mm b/remoting/host/disconnect_window_mac.mm
index 6ba79e1..0e1a088d 100644
--- a/remoting/host/disconnect_window_mac.mm
+++ b/remoting/host/disconnect_window_mac.mm
@@ -81,9 +81,9 @@
   DCHECK(window_controller_ == nil);
 
   // Create the window.
-  base::Closure disconnect_callback =
-      base::Bind(&ClientSessionControl::DisconnectSession,
-                 client_session_control, protocol::OK);
+  base::OnceClosure disconnect_callback =
+      base::BindOnce(&ClientSessionControl::DisconnectSession,
+                     client_session_control, protocol::OK);
   std::string client_jid = client_session_control->client_jid();
   std::string username = client_jid.substr(0, client_jid.find('/'));
 
@@ -93,10 +93,10 @@
                                            styleMask:NSBorderlessWindowMask
                                              backing:NSBackingStoreBuffered
                                                defer:NO] autorelease];
-  window_controller_ =
-      [[DisconnectWindowController alloc] initWithCallback:disconnect_callback
-                                                  username:username
-                                                    window:window];
+  window_controller_ = [[DisconnectWindowController alloc]
+      initWithCallback:std::move(disconnect_callback)
+              username:username
+                window:window];
   [window_controller_ initializeWindow];
   [window_controller_ showWindow:nil];
 }
@@ -112,12 +112,12 @@
 @synthesize connectedToField = _connectedToField;
 @synthesize disconnectButton = _disconnectButton;
 
-- (id)initWithCallback:(const base::Closure&)disconnect_callback
+- (id)initWithCallback:(base::OnceClosure)disconnect_callback
               username:(const std::string&)username
                 window:(NSWindow*)window {
   self = [super initWithWindow:(NSWindow*)window];
   if (self) {
-    _disconnect_callback = disconnect_callback;
+    _disconnect_callback = std::move(disconnect_callback);
     _username = base::UTF8ToUTF16(username);
   }
   return self;
@@ -128,8 +128,8 @@
 }
 
 - (IBAction)stopSharing:(id)sender {
-  if (!_disconnect_callback.is_null()) {
-    _disconnect_callback.Run();
+  if (_disconnect_callback) {
+    std::move(_disconnect_callback).Run();
   }
 }
 
diff --git a/remoting/protocol/audio_pump.cc b/remoting/protocol/audio_pump.cc
index 2db03e3..112e128 100644
--- a/remoting/protocol/audio_pump.cc
+++ b/remoting/protocol/audio_pump.cc
@@ -148,7 +148,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   audio_source_->Start(
-      base::Bind(&Core::EncodeAudioPacket, base::Unretained(this)));
+      base::BindRepeating(&Core::EncodeAudioPacket, base::Unretained(this)));
 }
 
 void AudioPump::Core::Pause(bool pause) {
diff --git a/remoting/protocol/authenticator_test_base.cc b/remoting/protocol/authenticator_test_base.cc
index 6c533094..80846440 100644
--- a/remoting/protocol/authenticator_test_base.cc
+++ b/remoting/protocol/authenticator_test_base.cc
@@ -125,13 +125,13 @@
 
   client_auth_->SecureAndAuthenticate(
       std::move(client_fake_socket_),
-      base::Bind(&AuthenticatorTestBase::OnClientConnected,
-                 base::Unretained(this)));
+      base::BindOnce(&AuthenticatorTestBase::OnClientConnected,
+                     base::Unretained(this)));
 
   host_auth_->SecureAndAuthenticate(
       std::move(host_fake_socket_),
-      base::Bind(&AuthenticatorTestBase::OnHostConnected,
-                 base::Unretained(this)));
+      base::BindOnce(&AuthenticatorTestBase::OnHostConnected,
+                     base::Unretained(this)));
 
   // Expect two callbacks to be called - the client callback and the host
   // callback.
diff --git a/remoting/protocol/capture_scheduler_unittest.cc b/remoting/protocol/capture_scheduler_unittest.cc
index 32e1a1b5..e41f0de1 100644
--- a/remoting/protocol/capture_scheduler_unittest.cc
+++ b/remoting/protocol/capture_scheduler_unittest.cc
@@ -28,8 +28,8 @@
   CaptureSchedulerTest() : capture_called_(false) {}
 
   void InitScheduler() {
-    scheduler_.reset(new CaptureScheduler(
-        base::Bind(&CaptureSchedulerTest::DoCapture, base::Unretained(this))));
+    scheduler_.reset(new CaptureScheduler(base::BindRepeating(
+        &CaptureSchedulerTest::DoCapture, base::Unretained(this))));
     scheduler_->set_minimum_interval(
         base::TimeDelta::FromMilliseconds(kMinumumFrameIntervalMs));
     scheduler_->SetTickClockForTest(&tick_clock_);
diff --git a/remoting/protocol/channel_dispatcher_base.cc b/remoting/protocol/channel_dispatcher_base.cc
index fd8f21e8..a6d0909 100644
--- a/remoting/protocol/channel_dispatcher_base.cc
+++ b/remoting/protocol/channel_dispatcher_base.cc
@@ -27,8 +27,9 @@
   channel_factory_ = channel_factory;
   event_handler_ = event_handler;
 
-  channel_factory_->CreateChannel(channel_name_, base::Bind(
-      &ChannelDispatcherBase::OnChannelReady, base::Unretained(this)));
+  channel_factory_->CreateChannel(
+      channel_name_, base::BindOnce(&ChannelDispatcherBase::OnChannelReady,
+                                    base::Unretained(this)));
 }
 
 void ChannelDispatcherBase::Init(std::unique_ptr<MessagePipe> message_pipe,
diff --git a/remoting/protocol/channel_multiplexer.cc b/remoting/protocol/channel_multiplexer.cc
index 88098be..61ffcc91 100644
--- a/remoting/protocol/channel_multiplexer.cc
+++ b/remoting/protocol/channel_multiplexer.cc
@@ -339,8 +339,8 @@
     if (pending_channels_.size() == 1U) {
       base_channel_factory_->CreateChannel(
           base_channel_name_,
-          base::Bind(&ChannelMultiplexer::OnBaseChannelReady,
-                     base::Unretained(this)));
+          base::BindOnce(&ChannelMultiplexer::OnBaseChannelReady,
+                         base::Unretained(this)));
     }
   }
 }
@@ -362,13 +362,14 @@
 
   if (base_channel_.get()) {
     // Initialize reader and writer.
-    reader_.StartReading(base_channel_.get(),
-                         base::Bind(&ChannelMultiplexer::OnIncomingPacket,
-                                    base::Unretained(this)),
-                         base::Bind(&ChannelMultiplexer::OnBaseChannelError,
-                                    base::Unretained(this)));
-    writer_.Start(base::Bind(&P2PStreamSocket::Write,
-                             base::Unretained(base_channel_.get())),
+    reader_.StartReading(
+        base_channel_.get(),
+        base::BindRepeating(&ChannelMultiplexer::OnIncomingPacket,
+                            base::Unretained(this)),
+        base::BindOnce(&ChannelMultiplexer::OnBaseChannelError,
+                       base::Unretained(this)));
+    writer_.Start(base::BindRepeating(&P2PStreamSocket::Write,
+                                      base::Unretained(base_channel_.get())),
                   base::BindOnce(&ChannelMultiplexer::OnBaseChannelError,
                                  base::Unretained(this)));
   }
diff --git a/remoting/protocol/channel_multiplexer_unittest.cc b/remoting/protocol/channel_multiplexer_unittest.cc
index 22bbfde..7d8ee4b 100644
--- a/remoting/protocol/channel_multiplexer_unittest.cc
+++ b/remoting/protocol/channel_multiplexer_unittest.cc
@@ -91,12 +91,12 @@
                      std::unique_ptr<P2PStreamSocket>* host_socket,
                      std::unique_ptr<P2PStreamSocket>* client_socket) {
     int counter = 2;
-    host_mux_->CreateChannel(name, base::Bind(
-        &ChannelMultiplexerTest::OnChannelConnected, base::Unretained(this),
-        host_socket, &counter));
-    client_mux_->CreateChannel(name, base::Bind(
-        &ChannelMultiplexerTest::OnChannelConnected, base::Unretained(this),
-        client_socket, &counter));
+    host_mux_->CreateChannel(
+        name, base::BindOnce(&ChannelMultiplexerTest::OnChannelConnected,
+                             base::Unretained(this), host_socket, &counter));
+    client_mux_->CreateChannel(
+        name, base::BindOnce(&ChannelMultiplexerTest::OnChannelConnected,
+                             base::Unretained(this), client_socket, &counter));
 
     base::RunLoop().Run();
 
@@ -323,10 +323,12 @@
   MockConnectCallback cb1;
   MockConnectCallback cb2;
 
-  host_mux_->CreateChannel(kTestChannelName, base::Bind(
-      &MockConnectCallback::OnConnected, base::Unretained(&cb1)));
-  host_mux_->CreateChannel(kTestChannelName2, base::Bind(
-      &MockConnectCallback::OnConnected, base::Unretained(&cb2)));
+  host_mux_->CreateChannel(kTestChannelName,
+                           base::BindOnce(&MockConnectCallback::OnConnected,
+                                          base::Unretained(&cb1)));
+  host_mux_->CreateChannel(kTestChannelName2,
+                           base::BindOnce(&MockConnectCallback::OnConnected,
+                                          base::Unretained(&cb2)));
 
   EXPECT_CALL(cb1, OnConnectedPtr(nullptr))
       .Times(AtMost(1))
diff --git a/remoting/protocol/channel_socket_adapter_unittest.cc b/remoting/protocol/channel_socket_adapter_unittest.cc
index 769cb61..00a3d65 100644
--- a/remoting/protocol/channel_socket_adapter_unittest.cc
+++ b/remoting/protocol/channel_socket_adapter_unittest.cc
@@ -37,10 +37,10 @@
 class TransportChannelSocketAdapterTest : public testing::Test {
  public:
   TransportChannelSocketAdapterTest()
-      : callback_(base::Bind(&TransportChannelSocketAdapterTest::Callback,
-                             base::Unretained(this))),
-        callback_result_(0) {
-  }
+      : callback_(
+            base::BindRepeating(&TransportChannelSocketAdapterTest::Callback,
+                                base::Unretained(this))),
+        callback_result_(0) {}
 
  protected:
   void SetUp() override {
diff --git a/remoting/protocol/client_video_dispatcher_unittest.cc b/remoting/protocol/client_video_dispatcher_unittest.cc
index 95ae9a5..349358e 100644
--- a/remoting/protocol/client_video_dispatcher_unittest.cc
+++ b/remoting/protocol/client_video_dispatcher_unittest.cc
@@ -71,22 +71,23 @@
 ClientVideoDispatcherTest::ClientVideoDispatcherTest()
     : channel_factory_adapter_(
           &client_channel_factory_,
-          base::Bind(&ClientVideoDispatcherTest::OnChannelError,
-                     base::Unretained(this))),
+          base::BindRepeating(&ClientVideoDispatcherTest::OnChannelError,
+                              base::Unretained(this))),
       dispatcher_(this, &client_stub_) {
   dispatcher_.Init(&channel_factory_adapter_, this);
   base::RunLoop().RunUntilIdle();
   DCHECK(initialized_);
   host_socket_.PairWith(
       client_channel_factory_.GetFakeChannel(kVideoChannelName));
-  reader_.StartReading(&host_socket_,
-                       base::Bind(&ClientVideoDispatcherTest::OnMessageReceived,
-                                  base::Unretained(this)),
-                       base::Bind(&ClientVideoDispatcherTest::OnReadError,
-                                  base::Unretained(this)));
-  writer_.Start(
-      base::Bind(&P2PStreamSocket::Write, base::Unretained(&host_socket_)),
-      BufferedSocketWriter::WriteFailedCallback());
+  reader_.StartReading(
+      &host_socket_,
+      base::BindRepeating(&ClientVideoDispatcherTest::OnMessageReceived,
+                          base::Unretained(this)),
+      base::BindOnce(&ClientVideoDispatcherTest::OnReadError,
+                     base::Unretained(this)));
+  writer_.Start(base::BindRepeating(&P2PStreamSocket::Write,
+                                    base::Unretained(&host_socket_)),
+                BufferedSocketWriter::WriteFailedCallback());
 }
 
 void ClientVideoDispatcherTest::ProcessVideoPacket(
diff --git a/remoting/protocol/connection_unittest.cc b/remoting/protocol/connection_unittest.cc
index 6dc2d85..7916df9 100644
--- a/remoting/protocol/connection_unittest.cc
+++ b/remoting/protocol/connection_unittest.cc
@@ -143,8 +143,8 @@
   bool Start(const PacketCapturedCallback& callback) override {
     callback_ = callback;
     timer_.Start(FROM_HERE, kAudioPacketDuration,
-                 base::Bind(&TestAudioSource::GenerateAudioSamples,
-                            base::Unretained(this)));
+                 base::BindRepeating(&TestAudioSource::GenerateAudioSamples,
+                                     base::Unretained(this)));
     return true;
   }
 
@@ -392,10 +392,12 @@
     // VideoStub otherwise.
     if (is_using_webrtc()) {
       client_video_renderer_.GetFrameConsumer()->set_on_frame_callback(
-          base::Bind(&base::RunLoop::Quit, base::Unretained(&run_loop)));
+          base::BindRepeating(&base::RunLoop::Quit,
+                              base::Unretained(&run_loop)));
     } else {
       client_video_renderer_.GetVideoStub()->set_on_frame_callback(
-          base::Bind(&base::RunLoop::Quit, base::Unretained(&run_loop)));
+          base::BindRepeating(&base::RunLoop::Quit,
+                              base::Unretained(&run_loop)));
     }
 
     run_loop.Run();
@@ -427,7 +429,7 @@
 
     base::RunLoop run_loop;
     client_video_renderer_.GetFrameStatsConsumer()->set_on_stats_callback(
-        base::Bind(&base::RunLoop::Quit, base::Unretained(&run_loop)));
+        base::BindRepeating(&base::RunLoop::Quit, base::Unretained(&run_loop)));
     run_loop.Run();
     client_video_renderer_.GetFrameStatsConsumer()->set_on_stats_callback({});
 
diff --git a/remoting/protocol/data_channel_manager_unittest.cc b/remoting/protocol/data_channel_manager_unittest.cc
index 0fc90e4..a83c136 100644
--- a/remoting/protocol/data_channel_manager_unittest.cc
+++ b/remoting/protocol/data_channel_manager_unittest.cc
@@ -101,20 +101,24 @@
 void TestDataChannelManagerFullMatch(bool asynchronous) {
   base::test::SingleThreadTaskEnvironment task_environment;
   DataChannelManager manager;
-  manager.RegisterCreateHandlerCallback("FullMatch", base::Bind(
-      [](const std::string& expected_data,
-         const std::string& name,
-         std::unique_ptr<MessagePipe> pipe) -> void {
-        new FakeNamedMessagePipeHandler(name, std::move(pipe), expected_data);
-      },
-      "FullMatchContent"));
-  manager.RegisterCreateHandlerCallback("AnotherFullMatch", base::Bind(
-      [](const std::string& expected_data,
-         const std::string& name,
-         std::unique_ptr<MessagePipe> pipe) -> void {
-        new FakeNamedMessagePipeHandler(name, std::move(pipe), expected_data);
-      },
-      "AnotherFullMatchContent"));
+  manager.RegisterCreateHandlerCallback(
+      "FullMatch",
+      base::BindRepeating(
+          [](const std::string& expected_data, const std::string& name,
+             std::unique_ptr<MessagePipe> pipe) -> void {
+            new FakeNamedMessagePipeHandler(name, std::move(pipe),
+                                            expected_data);
+          },
+          "FullMatchContent"));
+  manager.RegisterCreateHandlerCallback(
+      "AnotherFullMatch",
+      base::BindRepeating(
+          [](const std::string& expected_data, const std::string& name,
+             std::unique_ptr<MessagePipe> pipe) -> void {
+            new FakeNamedMessagePipeHandler(name, std::move(pipe),
+                                            expected_data);
+          },
+          "AnotherFullMatchContent"));
 
   FakeMessagePipe pipe1(asynchronous);
   FakeMessagePipe pipe2(asynchronous);
@@ -193,20 +197,24 @@
 void TestDataChannelManagerMultipleRegistrations(bool asynchronous) {
   base::test::SingleThreadTaskEnvironment task_environment;
   DataChannelManager manager;
-  manager.RegisterCreateHandlerCallback("FullMatch", base::Bind(
-      [](const std::string& expected_data,
-         const std::string& name,
-         std::unique_ptr<MessagePipe> pipe) -> void {
-        new FakeNamedMessagePipeHandler(name, std::move(pipe), expected_data);
-      },
-      "FullMatchContent"));
-  manager.RegisterCreateHandlerCallback("Prefix-", base::Bind(
-      [](const std::string& expected_data,
-         const std::string& name,
-         std::unique_ptr<MessagePipe> pipe) -> void {
-        new FakeNamedMessagePipeHandler(name, std::move(pipe), expected_data);
-      },
-      "PrefixMatchContent"));
+  manager.RegisterCreateHandlerCallback(
+      "FullMatch",
+      base::BindRepeating(
+          [](const std::string& expected_data, const std::string& name,
+             std::unique_ptr<MessagePipe> pipe) -> void {
+            new FakeNamedMessagePipeHandler(name, std::move(pipe),
+                                            expected_data);
+          },
+          "FullMatchContent"));
+  manager.RegisterCreateHandlerCallback(
+      "Prefix-",
+      base::BindRepeating(
+          [](const std::string& expected_data, const std::string& name,
+             std::unique_ptr<MessagePipe> pipe) -> void {
+            new FakeNamedMessagePipeHandler(name, std::move(pipe),
+                                            expected_data);
+          },
+          "PrefixMatchContent"));
 
   FakeMessagePipe pipe1(asynchronous);
   FakeMessagePipe pipe2(asynchronous);
diff --git a/remoting/protocol/fake_session.cc b/remoting/protocol/fake_session.cc
index 972f095..4266e15 100644
--- a/remoting/protocol/fake_session.cc
+++ b/remoting/protocol/fake_session.cc
@@ -37,14 +37,15 @@
   authenticator_.reset(new FakeAuthenticator(FakeAuthenticator::ACCEPT));
   authenticator_->set_auth_key(kTestAuthKey);
   transport_->Start(authenticator_.get(),
-                    base::Bind(&FakeSession::SendTransportInfo,
-                               weak_factory_.GetWeakPtr()));
+                    base::BindRepeating(&FakeSession::SendTransportInfo,
+                                        weak_factory_.GetWeakPtr()));
 
   // Initialize transport and authenticator on the host.
   peer->authenticator_.reset(new FakeAuthenticator(FakeAuthenticator::ACCEPT));
   peer->authenticator_->set_auth_key(kTestAuthKey);
-  peer->transport_->Start(peer->authenticator_.get(),
-                          base::Bind(&FakeSession::SendTransportInfo, peer_));
+  peer->transport_->Start(
+      peer->authenticator_.get(),
+      base::BindRepeating(&FakeSession::SendTransportInfo, peer_));
 
   peer->event_handler_->OnSessionStateChange(AUTHENTICATED);
   event_handler_->OnSessionStateChange(AUTHENTICATED);
diff --git a/remoting/protocol/ice_connection_to_host.cc b/remoting/protocol/ice_connection_to_host.cc
index 53076f3..b258d46b 100644
--- a/remoting/protocol/ice_connection_to_host.cc
+++ b/remoting/protocol/ice_connection_to_host.cc
@@ -127,8 +127,8 @@
           video_renderer_->GetVideoStub(),
           base::TimeDelta::FromSeconds(
               MonitoredVideoStub::kConnectivityCheckDelaySeconds),
-          base::Bind(&IceConnectionToHost::OnVideoChannelStatus,
-                     base::Unretained(this))));
+          base::BindRepeating(&IceConnectionToHost::OnVideoChannelStatus,
+                              base::Unretained(this))));
       video_dispatcher_.reset(
           new ClientVideoDispatcher(monitored_video_stub_.get(), client_stub_));
       video_dispatcher_->Init(transport_->GetChannelFactory(), this);
diff --git a/remoting/protocol/ice_transport.cc b/remoting/protocol/ice_transport.cc
index a4e658c2..282c514 100644
--- a/remoting/protocol/ice_transport.cc
+++ b/remoting/protocol/ice_transport.cc
@@ -46,7 +46,8 @@
       pseudotcp_channel_factory_.get(), authenticator));
   message_channel_factory_.reset(new StreamMessageChannelFactoryAdapter(
       secure_channel_factory_.get(),
-      base::Bind(&IceTransport::OnChannelError, weak_factory_.GetWeakPtr())));
+      base::BindRepeating(&IceTransport::OnChannelError,
+                          weak_factory_.GetWeakPtr())));
 }
 
 bool IceTransport::ProcessTransportInfo(jingle_xmpp::XmlElement* transport_info_xml) {
@@ -91,7 +92,8 @@
         new ChannelMultiplexer(secure_channel_factory_.get(), kMuxChannelName));
     mux_channel_factory_.reset(new StreamMessageChannelFactoryAdapter(
         channel_multiplexer_.get(),
-        base::Bind(&IceTransport::OnChannelError, weak_factory_.GetWeakPtr())));
+        base::BindRepeating(&IceTransport::OnChannelError,
+                            weak_factory_.GetWeakPtr())));
   }
   return mux_channel_factory_.get();
 }
diff --git a/remoting/protocol/ice_transport_unittest.cc b/remoting/protocol/ice_transport_unittest.cc
index aeeb6de..8c179e3 100644
--- a/remoting/protocol/ice_transport_unittest.cc
+++ b/remoting/protocol/ice_transport_unittest.cc
@@ -133,20 +133,20 @@
           new FakeAuthenticator(FakeAuthenticator::ACCEPT));
     }
 
-    host_event_handler_.set_error_callback(base::Bind(
+    host_event_handler_.set_error_callback(base::BindRepeating(
         &IceTransportTest::OnTransportError, base::Unretained(this)));
-    client_event_handler_.set_error_callback(base::Bind(
+    client_event_handler_.set_error_callback(base::BindRepeating(
         &IceTransportTest::OnTransportError, base::Unretained(this)));
 
     // Start both transports.
     host_transport_->Start(
         host_authenticator_.get(),
-        base::Bind(&IceTransportTest::ProcessTransportInfo,
-                   base::Unretained(this), &client_transport_));
+        base::BindRepeating(&IceTransportTest::ProcessTransportInfo,
+                            base::Unretained(this), &client_transport_));
     client_transport_->Start(
         client_authenticator_.get(),
-        base::Bind(&IceTransportTest::ProcessTransportInfo,
-                   base::Unretained(this), &host_transport_));
+        base::BindRepeating(&IceTransportTest::ProcessTransportInfo,
+                            base::Unretained(this), &host_transport_));
   }
 
   void WaitUntilConnected() {
@@ -210,11 +210,11 @@
   InitializeConnection();
 
   client_transport_->GetChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnClientChannelCreated,
+                                   base::Unretained(this)));
   host_transport_->GetChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnHostChannelCreated,
+                                   base::Unretained(this)));
 
   WaitUntilConnected();
 
@@ -228,11 +228,11 @@
   InitializeConnection();
 
   client_transport_->GetMultiplexedChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnClientChannelCreated,
+                                   base::Unretained(this)));
   host_transport_->GetMultiplexedChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnHostChannelCreated,
+                                   base::Unretained(this)));
 
   WaitUntilConnected();
 
@@ -250,11 +250,11 @@
   InitializeConnection();
 
   client_transport_->GetChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnClientChannelCreated,
+                                   base::Unretained(this)));
   host_transport_->GetChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnHostChannelCreated,
+                                   base::Unretained(this)));
 
   run_loop_.reset(new base::RunLoop());
 
@@ -283,11 +283,11 @@
   InitializeConnection();
 
   client_transport_->GetChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnClientChannelCreated,
+                                   base::Unretained(this)));
   host_transport_->GetChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnHostChannelCreated,
+                                   base::Unretained(this)));
 
   // The RunLoop should quit in OnTransportError().
   run_loop_.reset(new base::RunLoop());
@@ -308,8 +308,8 @@
   InitializeConnection();
 
   client_transport_->GetChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnClientChannelCreated,
+                                   base::Unretained(this)));
   client_transport_->GetChannelFactory()->CancelChannelCreation(
       kChannelName);
 
@@ -324,11 +324,11 @@
   InitializeConnection();
 
   client_transport_->GetChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnClientChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnClientChannelCreated,
+                                   base::Unretained(this)));
   host_transport_->GetChannelFactory()->CreateChannel(
-      kChannelName, base::Bind(&IceTransportTest::OnHostChannelCreated,
-                               base::Unretained(this)));
+      kChannelName, base::BindOnce(&IceTransportTest::OnHostChannelCreated,
+                                   base::Unretained(this)));
 
   WaitUntilConnected();
 
diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc
index 370c313..2c770226 100644
--- a/remoting/protocol/jingle_session.cc
+++ b/remoting/protocol/jingle_session.cc
@@ -750,8 +750,8 @@
 
 void JingleSession::OnAuthenticated() {
   transport_->Start(authenticator_.get(),
-                    base::Bind(&JingleSession::SendTransportInfo,
-                               weak_factory_.GetWeakPtr()));
+                    base::BindRepeating(&JingleSession::SendTransportInfo,
+                                        weak_factory_.GetWeakPtr()));
 
   base::WeakPtr<JingleSession> self = weak_factory_.GetWeakPtr();
   std::vector<PendingMessage> messages_to_process;
diff --git a/remoting/protocol/jingle_session_manager.cc b/remoting/protocol/jingle_session_manager.cc
index e6a670ce..a743f87 100644
--- a/remoting/protocol/jingle_session_manager.cc
+++ b/remoting/protocol/jingle_session_manager.cc
@@ -136,8 +136,9 @@
 
   it->second->OnIncomingMessage(
       stanza->Attr(jingle_xmpp::QN_ID), std::move(message),
-      base::Bind(&JingleSessionManager::SendReply, base::Unretained(this),
-                 base::Passed(std::move(stanza_copy))));
+      base::BindRepeating(&JingleSessionManager::SendReply,
+                          base::Unretained(this),
+                          base::Passed(std::move(stanza_copy))));
   return true;
 }
 
diff --git a/remoting/protocol/jingle_session_unittest.cc b/remoting/protocol/jingle_session_unittest.cc
index 0bf8217b..8449b823 100644
--- a/remoting/protocol/jingle_session_unittest.cc
+++ b/remoting/protocol/jingle_session_unittest.cc
@@ -198,8 +198,8 @@
 
     host_server_.reset(new JingleSessionManager(host_signal_strategy_.get()));
     host_server_->AcceptIncoming(
-        base::Bind(&MockSessionManagerListener::OnIncomingSession,
-                   base::Unretained(&host_server_listener_)));
+        base::BindRepeating(&MockSessionManagerListener::OnIncomingSession,
+                            base::Unretained(&host_server_listener_)));
 
     std::unique_ptr<AuthenticatorFactory> factory(
         new FakeHostAuthenticatorFactory(messages_till_start, auth_config));
@@ -426,7 +426,7 @@
   host_transport_.send_transport_info_callback().Run(CreateTransportInfo("2"));
 
   // Destroy the session as soon as the first message is received.
-  client_transport_.set_on_message_callback(base::Bind(
+  client_transport_.set_on_message_callback(base::BindRepeating(
       &JingleSessionTest::DeleteClientSession, base::Unretained(this)));
 
   base::RunLoop().RunUntilIdle();
@@ -580,7 +580,7 @@
   EXPECT_TRUE(client_transport_.received_messages().empty());
 
   // Destroy the session as soon as the first message is received.
-  client_transport_.set_on_message_callback(base::Bind(
+  client_transport_.set_on_message_callback(base::BindRepeating(
       &JingleSessionTest::DeleteClientSession, base::Unretained(this)));
 
   // Resume authentication.
diff --git a/remoting/protocol/message_reader.cc b/remoting/protocol/message_reader.cc
index cd08d89..f73a3cc 100644
--- a/remoting/protocol/message_reader.cc
+++ b/remoting/protocol/message_reader.cc
@@ -32,16 +32,16 @@
 void MessageReader::StartReading(
     P2PStreamSocket* socket,
     const MessageReceivedCallback& message_received_callback,
-    const ReadFailedCallback& read_failed_callback) {
+    ReadFailedCallback read_failed_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!socket_);
   DCHECK(socket);
-  DCHECK(!message_received_callback.is_null());
-  DCHECK(!read_failed_callback.is_null());
+  DCHECK(message_received_callback);
+  DCHECK(read_failed_callback);
 
   socket_ = socket;
   message_received_callback_ = message_received_callback;
-  read_failed_callback_ = read_failed_callback;
+  read_failed_callback_ = std::move(read_failed_callback);
   DoRead();
 }
 
@@ -49,14 +49,14 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Don't try to read again if there is another read pending or we
   // have messages that we haven't finished processing yet.
-  bool read_succeeded = true;
-  while (read_succeeded && !closed_ && !read_pending_) {
+  while (!closed_ && !read_pending_) {
     read_buffer_ = base::MakeRefCounted<net::IOBuffer>(kReadBufferSize);
     int result = socket_->Read(
         read_buffer_.get(), kReadBufferSize,
         base::BindOnce(&MessageReader::OnRead, weak_factory_.GetWeakPtr()));
 
-    HandleReadResult(result, &read_succeeded);
+    if (!HandleReadResult(result))
+      break;
   }
 }
 
@@ -66,33 +66,31 @@
   read_pending_ = false;
 
   if (!closed_) {
-    bool read_succeeded;
-    HandleReadResult(result, &read_succeeded);
-    if (read_succeeded)
-      DoRead();
+    HandleReadResult(result);
+    DoRead();
   }
 }
 
-void MessageReader::HandleReadResult(int result, bool* read_succeeded) {
+bool MessageReader::HandleReadResult(int result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (closed_)
-    return;
-
-  *read_succeeded = true;
+  DCHECK(!closed_);
 
   if (result > 0) {
     OnDataReceived(read_buffer_.get(), result);
-    *read_succeeded = true;
-  } else if (result == net::ERR_IO_PENDING) {
-    read_pending_ = true;
-  } else {
-    // Stop reading after any error.
-    closed_ = true;
-    *read_succeeded = false;
-
-    LOG(ERROR) << "Read() returned error " << result;
-    read_failed_callback_.Run(result);
+    return true;
   }
+
+  if (result == net::ERR_IO_PENDING) {
+    read_pending_ = true;
+    return true;
+  }
+
+  // Stop reading after any error.
+  closed_ = true;
+  LOG(ERROR) << "Read() returned error " << result;
+  std::move(read_failed_callback_).Run(result);
+  // |this| may be deleted.
+  return false;
 }
 
 void MessageReader::OnDataReceived(net::IOBuffer* data, int data_size) {
@@ -113,7 +111,7 @@
 }
 
 void MessageReader::RunCallback(std::unique_ptr<CompoundBuffer> message) {
-  if (!message_received_callback_.is_null()) {
+  if (message_received_callback_) {
     message_received_callback_.Run(std::move(message));
   }
 }
diff --git a/remoting/protocol/message_reader.h b/remoting/protocol/message_reader.h
index b20421eb..6a62b99 100644
--- a/remoting/protocol/message_reader.h
+++ b/remoting/protocol/message_reader.h
@@ -38,7 +38,7 @@
  public:
   typedef base::RepeatingCallback<void(std::unique_ptr<CompoundBuffer> message)>
       MessageReceivedCallback;
-  typedef base::RepeatingCallback<void(int)> ReadFailedCallback;
+  typedef base::OnceCallback<void(int)> ReadFailedCallback;
 
   MessageReader();
   virtual ~MessageReader();
@@ -46,14 +46,17 @@
   // Starts reading from |socket|.
   void StartReading(P2PStreamSocket* socket,
                     const MessageReceivedCallback& message_received_callback,
-                    const ReadFailedCallback& read_failed_callback);
+                    ReadFailedCallback read_failed_callback);
 
  private:
   void DoRead();
   void OnRead(int result);
-  void HandleReadResult(int result, bool* read_succeeded);
+  // Returns true on success, or runs |read_failed_callback_| and returns false
+  // on failure. When false is returned, |this| may be deleted.
+  bool HandleReadResult(int result);
   void OnDataReceived(net::IOBuffer* data, int data_size);
   void RunCallback(std::unique_ptr<CompoundBuffer> message);
+  bool DidReadFail();
 
   ReadFailedCallback read_failed_callback_;
 
diff --git a/remoting/protocol/message_reader_unittest.cc b/remoting/protocol/message_reader_unittest.cc
index 90fd7559d..9e0b5ea 100644
--- a/remoting/protocol/message_reader_unittest.cc
+++ b/remoting/protocol/message_reader_unittest.cc
@@ -50,10 +50,11 @@
   }
 
   void InitReader() {
-    reader_->StartReading(
-        &socket_,
-        base::Bind(&MessageReaderTest::OnMessage, base::Unretained(this)),
-        base::Bind(&MessageReaderTest::OnReadError, base::Unretained(this)));
+    reader_->StartReading(&socket_,
+                          base::BindRepeating(&MessageReaderTest::OnMessage,
+                                              base::Unretained(this)),
+                          base::BindOnce(&MessageReaderTest::OnReadError,
+                                         base::Unretained(this)));
   }
 
   void AddMessage(const std::string& message) {
diff --git a/remoting/protocol/monitored_video_stub_unittest.cc b/remoting/protocol/monitored_video_stub_unittest.cc
index 14efa87..abb10f9 100644
--- a/remoting/protocol/monitored_video_stub_unittest.cc
+++ b/remoting/protocol/monitored_video_stub_unittest.cc
@@ -35,9 +35,8 @@
     monitor_.reset(new MonitoredVideoStub(
         &video_stub_,
         base::TimeDelta::FromMilliseconds(kTestOverrideDelayMilliseconds),
-        base::Bind(
-            &MonitoredVideoStubTest::OnVideoChannelStatus,
-            base::Unretained(this))));
+        base::BindRepeating(&MonitoredVideoStubTest::OnVideoChannelStatus,
+                            base::Unretained(this))));
     EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _)).Times(AnyNumber());
   }
 
diff --git a/remoting/protocol/negotiating_authenticator_unittest.cc b/remoting/protocol/negotiating_authenticator_unittest.cc
index b33a8dd..223ddba 100644
--- a/remoting/protocol/negotiating_authenticator_unittest.cc
+++ b/remoting/protocol/negotiating_authenticator_unittest.cc
@@ -75,8 +75,8 @@
     client_auth_config.pairing_secret = client_paired_secret;
     bool pairing_expected = pairing_registry_.get() != nullptr;
     client_auth_config.fetch_secret_callback =
-        base::Bind(&NegotiatingAuthenticatorTest::FetchSecret,
-                   client_interactive_pin, pairing_expected);
+        base::BindRepeating(&NegotiatingAuthenticatorTest::FetchSecret,
+                            client_interactive_pin, pairing_expected);
     client_as_negotiating_authenticator_ = new NegotiatingClientAuthenticator(
         kClientJid, kHostJid, client_auth_config);
     client_.reset(client_as_negotiating_authenticator_);
diff --git a/remoting/protocol/negotiating_client_authenticator.cc b/remoting/protocol/negotiating_client_authenticator.cc
index 8f413bb7..5a4b2329 100644
--- a/remoting/protocol/negotiating_client_authenticator.cc
+++ b/remoting/protocol/negotiating_client_authenticator.cc
@@ -135,15 +135,15 @@
 
     case Method::THIRD_PARTY_SPAKE2_P224:
       current_authenticator_.reset(new ThirdPartyClientAuthenticator(
-          base::Bind(&V2Authenticator::CreateForClient),
+          base::BindRepeating(&V2Authenticator::CreateForClient),
           config_.fetch_third_party_token_callback));
       std::move(resume_callback).Run();
       break;
 
     case Method::THIRD_PARTY_SPAKE2_CURVE25519:
       current_authenticator_.reset(new ThirdPartyClientAuthenticator(
-          base::Bind(&Spake2Authenticator::CreateForClient, local_id_,
-                     remote_id_),
+          base::BindRepeating(&Spake2Authenticator::CreateForClient, local_id_,
+                              remote_id_),
           config_.fetch_third_party_token_callback));
       std::move(resume_callback).Run();
       break;
@@ -151,7 +151,7 @@
     case Method::PAIRED_SPAKE2_P224: {
       PairingClientAuthenticator* pairing_authenticator =
           new PairingClientAuthenticator(
-              config_, base::Bind(&V2Authenticator::CreateForClient));
+              config_, base::BindRepeating(&V2Authenticator::CreateForClient));
       current_authenticator_ = base::WrapUnique(pairing_authenticator);
       pairing_authenticator->Start(preferred_initial_state,
                                    std::move(resume_callback));
@@ -161,7 +161,8 @@
     case Method::PAIRED_SPAKE2_CURVE25519: {
       PairingClientAuthenticator* pairing_authenticator =
           new PairingClientAuthenticator(
-              config_, base::Bind(&Spake2Authenticator::CreateForClient,
+              config_,
+              base::BindRepeating(&Spake2Authenticator::CreateForClient,
                                   local_id_, remote_id_));
       current_authenticator_ = base::WrapUnique(pairing_authenticator);
       pairing_authenticator->Start(preferred_initial_state,
@@ -174,7 +175,7 @@
     case Method::SHARED_SECRET_SPAKE2_CURVE25519:
       config_.fetch_secret_callback.Run(
           false,
-          base::Bind(
+          base::BindRepeating(
               &NegotiatingClientAuthenticator::CreateSharedSecretAuthenticator,
               weak_factory_.GetWeakPtr(), preferred_initial_state,
               base::Passed(std::move(resume_callback))));
@@ -188,7 +189,7 @@
           methods_.end()) {
     PairingClientAuthenticator* pairing_authenticator =
         new PairingClientAuthenticator(
-            config_, base::Bind(&V2Authenticator::CreateForClient));
+            config_, base::BindRepeating(&V2Authenticator::CreateForClient));
     current_authenticator_ = base::WrapUnique(pairing_authenticator);
     pairing_authenticator->StartPaired(MESSAGE_READY);
     current_method_ = Method::PAIRED_SPAKE2_P224;
diff --git a/remoting/protocol/negotiating_host_authenticator.cc b/remoting/protocol/negotiating_host_authenticator.cc
index 571d7bca..60904674 100644
--- a/remoting/protocol/negotiating_host_authenticator.cc
+++ b/remoting/protocol/negotiating_host_authenticator.cc
@@ -185,8 +185,8 @@
 
     case Method::THIRD_PARTY_SPAKE2_P224:
       current_authenticator_.reset(new ThirdPartyHostAuthenticator(
-          base::Bind(&V2Authenticator::CreateForHost, local_cert_,
-                     local_key_pair_),
+          base::BindRepeating(&V2Authenticator::CreateForHost, local_cert_,
+                              local_key_pair_),
           token_validator_factory_->CreateTokenValidator(local_id_,
                                                          remote_id_)));
       std::move(resume_callback).Run();
@@ -194,8 +194,8 @@
 
     case Method::THIRD_PARTY_SPAKE2_CURVE25519:
       current_authenticator_.reset(new ThirdPartyHostAuthenticator(
-          base::Bind(&Spake2Authenticator::CreateForHost, local_id_, remote_id_,
-                     local_cert_, local_key_pair_),
+          base::BindRepeating(&Spake2Authenticator::CreateForHost, local_id_,
+                              remote_id_, local_cert_, local_key_pair_),
           token_validator_factory_->CreateTokenValidator(local_id_,
                                                          remote_id_)));
       std::move(resume_callback).Run();
@@ -204,8 +204,9 @@
     case Method::PAIRED_SPAKE2_P224: {
       PairingHostAuthenticator* pairing_authenticator =
           new PairingHostAuthenticator(
-              pairing_registry_, base::Bind(&V2Authenticator::CreateForHost,
-                                            local_cert_, local_key_pair_),
+              pairing_registry_,
+              base::BindRepeating(&V2Authenticator::CreateForHost, local_cert_,
+                                  local_key_pair_),
               shared_secret_hash_);
       current_authenticator_.reset(pairing_authenticator);
       pairing_authenticator->Initialize(client_id_, preferred_initial_state,
@@ -217,8 +218,9 @@
       PairingHostAuthenticator* pairing_authenticator =
           new PairingHostAuthenticator(
               pairing_registry_,
-              base::Bind(&Spake2Authenticator::CreateForHost, local_id_,
-                         remote_id_, local_cert_, local_key_pair_),
+              base::BindRepeating(&Spake2Authenticator::CreateForHost,
+                                  local_id_, remote_id_, local_cert_,
+                                  local_key_pair_),
               shared_secret_hash_);
       current_authenticator_.reset(pairing_authenticator);
       pairing_authenticator->Initialize(client_id_, preferred_initial_state,
diff --git a/remoting/protocol/pairing_client_authenticator.cc b/remoting/protocol/pairing_client_authenticator.cc
index c8c6ffc..bd6874e 100644
--- a/remoting/protocol/pairing_client_authenticator.cc
+++ b/remoting/protocol/pairing_client_authenticator.cc
@@ -58,9 +58,9 @@
   DCHECK(!waiting_for_pin_);
   waiting_for_pin_ = true;
   client_auth_config_.fetch_secret_callback.Run(
-      true, base::Bind(&PairingClientAuthenticator::OnPinFetched,
-                       weak_factory_.GetWeakPtr(), initial_state,
-                       base::Passed(std::move(resume_callback))));
+      true, base::BindRepeating(&PairingClientAuthenticator::OnPinFetched,
+                                weak_factory_.GetWeakPtr(), initial_state,
+                                base::Passed(std::move(resume_callback))));
 }
 
 void PairingClientAuthenticator::OnPinFetched(State initial_state,
diff --git a/remoting/protocol/performance_tracker.cc b/remoting/protocol/performance_tracker.cc
index 3f69140..927f3d2 100644
--- a/remoting/protocol/performance_tracker.cc
+++ b/remoting/protocol/performance_tracker.cc
@@ -88,9 +88,12 @@
       video_decode_ms_(kLatencySampleSize),
       video_paint_ms_(kLatencySampleSize),
       round_trip_ms_(kLatencySampleSize) {
-  uma_custom_counts_updater_ = base::Bind(&UpdateUmaCustomHistogramStub);
-  uma_custom_times_updater_ = base::Bind(&UpdateUmaCustomHistogramStub);
-  uma_enum_histogram_updater_ = base::Bind(&UpdateUmaEnumHistogramStub);
+  uma_custom_counts_updater_ =
+      base::BindRepeating(&UpdateUmaCustomHistogramStub);
+  uma_custom_times_updater_ =
+      base::BindRepeating(&UpdateUmaCustomHistogramStub);
+  uma_enum_histogram_updater_ =
+      base::BindRepeating(&UpdateUmaEnumHistogramStub);
 }
 
 PerformanceTracker::~PerformanceTracker() = default;
@@ -112,8 +115,8 @@
   if (!is_paused_ && !upload_uma_stats_timer_.IsRunning()) {
     upload_uma_stats_timer_.Start(
         FROM_HERE, base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds),
-        base::Bind(&PerformanceTracker::UploadRateStatsToUma,
-                   base::Unretained(this)));
+        base::BindRepeating(&PerformanceTracker::UploadRateStatsToUma,
+                            base::Unretained(this)));
   }
 
   // Record this received packet, even if it is empty.
diff --git a/remoting/protocol/port_allocator.cc b/remoting/protocol/port_allocator.cc
index b6bdfe2..ac87026f 100644
--- a/remoting/protocol/port_allocator.cc
+++ b/remoting/protocol/port_allocator.cc
@@ -75,7 +75,7 @@
 PortAllocatorSession::~PortAllocatorSession() = default;
 
 void PortAllocatorSession::GetPortConfigurations() {
-  transport_context_->GetIceConfig(base::Bind(
+  transport_context_->GetIceConfig(base::BindOnce(
       &PortAllocatorSession::OnIceConfig, weak_factory_.GetWeakPtr()));
 }
 
diff --git a/remoting/protocol/pseudotcp_adapter.cc b/remoting/protocol/pseudotcp_adapter.cc
index bdb467f..0b26d15 100644
--- a/remoting/protocol/pseudotcp_adapter.cc
+++ b/remoting/protocol/pseudotcp_adapter.cc
@@ -347,9 +347,10 @@
   // send exactly as many bytes as we requested, or fail.
   int result;
   if (socket_) {
-    result = socket_->Send(
-        write_buffer.get(), len,
-        base::Bind(&PseudoTcpAdapter::Core::OnWritten, base::Unretained(this)));
+    result =
+        socket_->Send(write_buffer.get(), len,
+                      base::BindRepeating(&PseudoTcpAdapter::Core::OnWritten,
+                                          base::Unretained(this)));
   } else {
     result = net::ERR_CONNECTION_CLOSED;
   }
@@ -371,9 +372,9 @@
 
   int result = 1;
   while (socket_ && result > 0) {
-    result = socket_->Recv(
-        socket_read_buffer_.get(), kReadBufferSize,
-        base::Bind(&PseudoTcpAdapter::Core::OnRead, base::Unretained(this)));
+    result = socket_->Recv(socket_read_buffer_.get(), kReadBufferSize,
+                           base::BindRepeating(&PseudoTcpAdapter::Core::OnRead,
+                                               base::Unretained(this)));
     if (result != net::ERR_IO_PENDING)
       HandleReadResults(result);
   }
diff --git a/remoting/protocol/secure_channel_factory.cc b/remoting/protocol/secure_channel_factory.cc
index f52fa3bd..83318588 100644
--- a/remoting/protocol/secure_channel_factory.cc
+++ b/remoting/protocol/secure_channel_factory.cc
@@ -60,9 +60,9 @@
   channel_authenticators_[name] = channel_authenticator;
   channel_authenticator->SecureAndAuthenticate(
       std::move(socket),
-      base::Bind(&SecureChannelFactory::OnSecureChannelCreated,
-                 base::Unretained(this), name,
-                 base::Passed(std::move(callback))));
+      base::BindOnce(&SecureChannelFactory::OnSecureChannelCreated,
+                     base::Unretained(this), name,
+                     base::Passed(std::move(callback))));
 }
 
 void SecureChannelFactory::OnSecureChannelCreated(
diff --git a/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc b/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc
index 4bf7f4e..0833b9f 100644
--- a/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc
+++ b/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc
@@ -82,13 +82,14 @@
 
     client_auth_->SecureAndAuthenticate(
         std::move(client_fake_socket_),
-        base::Bind(&SslHmacChannelAuthenticatorTest::OnClientConnected,
-                   base::Unretained(this)));
+        base::BindOnce(&SslHmacChannelAuthenticatorTest::OnClientConnected,
+                       base::Unretained(this)));
 
     host_auth_->SecureAndAuthenticate(
         std::move(host_fake_socket_),
-        base::Bind(&SslHmacChannelAuthenticatorTest::OnHostConnected,
-                   base::Unretained(this), std::string("ref argument value")));
+        base::BindOnce(&SslHmacChannelAuthenticatorTest::OnHostConnected,
+                       base::Unretained(this),
+                       std::string("ref argument value")));
 
     // Expect two callbacks to be called - the client callback and the host
     // callback.
diff --git a/remoting/protocol/stream_message_pipe_adapter.cc b/remoting/protocol/stream_message_pipe_adapter.cc
index 33d7699..a8713de 100644
--- a/remoting/protocol/stream_message_pipe_adapter.cc
+++ b/remoting/protocol/stream_message_pipe_adapter.cc
@@ -34,17 +34,17 @@
   event_handler_ = event_handler;
 
   writer_ = std::make_unique<BufferedSocketWriter>();
-  writer_->Start(
-      base::Bind(&P2PStreamSocket::Write, base::Unretained(socket_.get())),
-      base::BindOnce(&StreamMessagePipeAdapter::CloseOnError,
-                     base::Unretained(this)));
+  writer_->Start(base::BindRepeating(&P2PStreamSocket::Write,
+                                     base::Unretained(socket_.get())),
+                 base::BindOnce(&StreamMessagePipeAdapter::CloseOnError,
+                                base::Unretained(this)));
 
   reader_ = std::make_unique<MessageReader>();
   reader_->StartReading(socket_.get(),
-                        base::Bind(&EventHandler::OnMessageReceived,
-                                   base::Unretained(event_handler_)),
-                        base::Bind(&StreamMessagePipeAdapter::CloseOnError,
-                                   base::Unretained(this)));
+                        base::BindRepeating(&EventHandler::OnMessageReceived,
+                                            base::Unretained(event_handler_)),
+                        base::BindOnce(&StreamMessagePipeAdapter::CloseOnError,
+                                       base::Unretained(this)));
 
   event_handler_->OnMessagePipeOpen();
 }
diff --git a/remoting/protocol/third_party_authenticator_unittest.cc b/remoting/protocol/third_party_authenticator_unittest.cc
index c63343d..78bd7c12 100644
--- a/remoting/protocol/third_party_authenticator_unittest.cc
+++ b/remoting/protocol/third_party_authenticator_unittest.cc
@@ -105,12 +105,13 @@
   void InitAuthenticators() {
     token_validator_ = new FakeTokenValidator();
     host_.reset(new ThirdPartyHostAuthenticator(
-        base::Bind(&V2Authenticator::CreateForHost, host_cert_, key_pair_),
+        base::BindRepeating(&V2Authenticator::CreateForHost, host_cert_,
+                            key_pair_),
         base::WrapUnique(token_validator_)));
     client_.reset(new ThirdPartyClientAuthenticator(
-        base::Bind(&V2Authenticator::CreateForClient),
-        base::Bind(&FakeTokenFetcher::FetchThirdPartyToken,
-                   base::Unretained(&token_fetcher_))));
+        base::BindRepeating(&V2Authenticator::CreateForClient),
+        base::BindRepeating(&FakeTokenFetcher::FetchThirdPartyToken,
+                            base::Unretained(&token_fetcher_))));
   }
 
   FakeTokenFetcher token_fetcher_;
diff --git a/remoting/protocol/third_party_client_authenticator.cc b/remoting/protocol/third_party_client_authenticator.cc
index 486bfd4..08e242f 100644
--- a/remoting/protocol/third_party_client_authenticator.cc
+++ b/remoting/protocol/third_party_client_authenticator.cc
@@ -46,9 +46,10 @@
 
   fetch_token_callback_.Run(
       token_url, token_scope,
-      base::Bind(&ThirdPartyClientAuthenticator::OnThirdPartyTokenFetched,
-                 weak_factory_.GetWeakPtr(),
-                 base::Passed(std::move(resume_callback))));
+      base::BindRepeating(
+          &ThirdPartyClientAuthenticator::OnThirdPartyTokenFetched,
+          weak_factory_.GetWeakPtr(),
+          base::Passed(std::move(resume_callback))));
 }
 
 void ThirdPartyClientAuthenticator::AddTokenElements(
diff --git a/remoting/protocol/video_frame_pump.cc b/remoting/protocol/video_frame_pump.cc
index 226f8f40..d138694 100644
--- a/remoting/protocol/video_frame_pump.cc
+++ b/remoting/protocol/video_frame_pump.cc
@@ -51,10 +51,10 @@
       keep_alive_timer_(
           FROM_HERE,
           base::TimeDelta::FromMilliseconds(kKeepAlivePacketIntervalMs),
-          base::Bind(&VideoFramePump::SendKeepAlivePacket,
-                     base::Unretained(this))),
-      capture_scheduler_(base::Bind(&VideoFramePump::CaptureNextFrame,
-                                    base::Unretained(this))) {
+          base::BindRepeating(&VideoFramePump::SendKeepAlivePacket,
+                              base::Unretained(this))),
+      capture_scheduler_(base::BindRepeating(&VideoFramePump::CaptureNextFrame,
+                                             base::Unretained(this))) {
   DCHECK(encoder_);
   DCHECK(video_stub_);
 
diff --git a/remoting/protocol/video_frame_pump_unittest.cc b/remoting/protocol/video_frame_pump_unittest.cc
index cb002d3..90ecfde 100644
--- a/remoting/protocol/video_frame_pump_unittest.cc
+++ b/remoting/protocol/video_frame_pump_unittest.cc
@@ -205,7 +205,7 @@
   base::RunLoop run_loop;
 
   // Set up the capturer to return null frames.
-  capturer->set_frame_generator(base::Bind(&CreateNullFrame));
+  capturer->set_frame_generator(base::BindRepeating(&CreateNullFrame));
 
   // Expect that the VideoEncoder::Encode() method is never called.
   EXPECT_CALL(*encoder, EncodePtr(_)).Times(0);
@@ -232,7 +232,7 @@
   base::RunLoop run_loop;
 
   // Set up the capturer to return unchanged frames.
-  capturer->set_frame_generator(base::Bind(&CreateUnchangedFrame));
+  capturer->set_frame_generator(base::BindRepeating(&CreateUnchangedFrame));
 
   // Expect that the VideoEncoder::Encode() method is called.
   EXPECT_CALL(*encoder, EncodePtr(_)).WillRepeatedly(Return(nullptr));
diff --git a/remoting/protocol/webrtc_audio_source_adapter.cc b/remoting/protocol/webrtc_audio_source_adapter.cc
index 72ed24f24..d80c9934 100644
--- a/remoting/protocol/webrtc_audio_source_adapter.cc
+++ b/remoting/protocol/webrtc_audio_source_adapter.cc
@@ -68,7 +68,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   audio_source_ = std::move(audio_source);
   audio_source_->Start(
-      base::Bind(&Core::OnAudioPacket, base::Unretained(this)));
+      base::BindRepeating(&Core::OnAudioPacket, base::Unretained(this)));
 }
 
 void WebrtcAudioSourceAdapter::Core::Pause(bool pause) {
diff --git a/remoting/protocol/webrtc_frame_scheduler_unittest.cc b/remoting/protocol/webrtc_frame_scheduler_unittest.cc
index 3af2de2..482ccd82 100644
--- a/remoting/protocol/webrtc_frame_scheduler_unittest.cc
+++ b/remoting/protocol/webrtc_frame_scheduler_unittest.cc
@@ -33,9 +33,10 @@
     video_encoder_factory_.reset(new WebrtcDummyVideoEncoderFactory());
     scheduler_.reset(new WebrtcFrameSchedulerSimple(SessionOptions()));
     scheduler_->SetTickClockForTest(task_runner_->GetMockTickClock());
-    scheduler_->Start(video_encoder_factory_.get(),
-                      base::Bind(&WebrtcFrameSchedulerTest::CaptureCallback,
-                                 base::Unretained(this)));
+    scheduler_->Start(
+        video_encoder_factory_.get(),
+        base::BindRepeating(&WebrtcFrameSchedulerTest::CaptureCallback,
+                            base::Unretained(this)));
   }
   ~WebrtcFrameSchedulerTest() override = default;
 
diff --git a/remoting/protocol/webrtc_video_stream.cc b/remoting/protocol/webrtc_video_stream.cc
index 5d6c477c..fe03fda 100644
--- a/remoting/protocol/webrtc_video_stream.cc
+++ b/remoting/protocol/webrtc_video_stream.cc
@@ -138,8 +138,8 @@
   webrtc_transport_ = webrtc_transport;
 
   webrtc_transport_->video_encoder_factory()->RegisterEncoderSelectedCallback(
-      base::Bind(&WebrtcVideoStream::OnEncoderCreated,
-                 weak_factory_.GetWeakPtr()));
+      base::BindRepeating(&WebrtcVideoStream::OnEncoderCreated,
+                          weak_factory_.GetWeakPtr()));
 
   capturer_->Start(this);
 
@@ -159,9 +159,9 @@
   webrtc_transport_->OnVideoTransceiverCreated(transceiver);
 
   scheduler_.reset(new WebrtcFrameSchedulerSimple(session_options_));
-  scheduler_->Start(
-      webrtc_transport_->video_encoder_factory(),
-      base::Bind(&WebrtcVideoStream::CaptureNextFrame, base::Unretained(this)));
+  scheduler_->Start(webrtc_transport_->video_encoder_factory(),
+                    base::BindRepeating(&WebrtcVideoStream::CaptureNextFrame,
+                                        base::Unretained(this)));
 
   video_stats_dispatcher_.Init(webrtc_transport_->CreateOutgoingChannel(
                                    video_stats_dispatcher_.channel_name()),
diff --git a/services/tracing/BUILD.gn b/services/tracing/BUILD.gn
index bcb2fe7..e0d3e15 100644
--- a/services/tracing/BUILD.gn
+++ b/services/tracing/BUILD.gn
@@ -86,6 +86,7 @@
     "public/cpp/perfetto/producer_test_utils.h",
     "public/cpp/perfetto/task_runner_unittest.cc",
     "public/cpp/perfetto/trace_event_data_source_unittest.cc",
+    "public/cpp/perfetto/trace_packet_tokenizer_unittest.cc",
     "public/cpp/perfetto/traced_value_proto_writer_unittest.cc",
     "public/cpp/stack_sampling/reached_code_data_source_android_unittest.cc",
     "public/cpp/stack_sampling/tracing_sampler_profiler_unittest.cc",
diff --git a/services/tracing/perfetto/consumer_host.cc b/services/tracing/perfetto/consumer_host.cc
index 67a3d1b..09ce4b5 100644
--- a/services/tracing/perfetto/consumer_host.cc
+++ b/services/tracing/perfetto/consumer_host.cc
@@ -217,27 +217,35 @@
 
 void ConsumerHost::TracingSession::OnPerfettoEvents(
     const perfetto::ObservableEvents& events) {
-  if (!pending_enable_tracing_ack_pids_) {
+  if (!pending_enable_tracing_ack_pids_ ||
+      !events.instance_state_changes_size()) {
     return;
   }
 
   for (const auto& state_change : events.instance_state_changes()) {
-    if (state_change.state() !=
-        perfetto::ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED) {
-      continue;
-    }
+    DataSourceHandle handle(state_change.producer_name(),
+                            state_change.data_source_name());
+    data_source_states_[handle] =
+        state_change.state() ==
+        perfetto::ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED;
+  }
 
-    if (state_change.data_source_name() != mojom::kTraceEventDataSourceName) {
-      continue;
-    }
+  // Data sources are first reported as being stopped before starting, so once
+  // all the data sources we know about have started we can declare tracing
+  // begun.
+  bool all_data_sources_started = std::all_of(
+      data_source_states_.cbegin(), data_source_states_.cend(),
+      [](std::pair<DataSourceHandle, bool> state) { return state.second; });
+  if (!all_data_sources_started)
+    return;
 
+  for (const auto& it : data_source_states_) {
     // Attempt to parse the PID out of the producer name.
     base::ProcessId pid;
-    if (!PerfettoService::ParsePidFromProducerName(state_change.producer_name(),
+    if (!PerfettoService::ParsePidFromProducerName(it.first.producer_name(),
                                                    &pid)) {
       continue;
     }
-
     pending_enable_tracing_ack_pids_->erase(pid);
   }
   MaybeSendEnableTracingAck();
diff --git a/services/tracing/perfetto/consumer_host.h b/services/tracing/perfetto/consumer_host.h
index b8bc8e12..97c7e36 100644
--- a/services/tracing/perfetto/consumer_host.h
+++ b/services/tracing/perfetto/consumer_host.h
@@ -110,6 +110,13 @@
     base::Optional<std::set<base::ProcessId>> pending_enable_tracing_ack_pids_;
     base::OneShotTimer enable_tracing_ack_timer_;
 
+    struct DataSourceHandle : public std::pair<std::string, std::string> {
+      using std::pair<std::string, std::string>::pair;
+      const std::string& producer_name() const { return first; }
+      const std::string& data_source_name() const { return second; }
+    };
+    std::map<DataSourceHandle, bool /*started*/> data_source_states_;
+
     SEQUENCE_CHECKER(sequence_checker_);
     base::WeakPtrFactory<TracingSession> weak_factory_{this};
 
diff --git a/services/tracing/public/cpp/BUILD.gn b/services/tracing/public/cpp/BUILD.gn
index bed382e8..9a3c0f77 100644
--- a/services/tracing/public/cpp/BUILD.gn
+++ b/services/tracing/public/cpp/BUILD.gn
@@ -91,6 +91,8 @@
       "perfetto/task_runner.h",
       "perfetto/trace_event_data_source.cc",
       "perfetto/trace_event_data_source.h",
+      "perfetto/trace_packet_tokenizer.cc",
+      "perfetto/trace_packet_tokenizer.h",
       "perfetto/trace_time.cc",
       "perfetto/trace_time.h",
       "perfetto/traced_value_proto_writer.cc",
diff --git a/services/tracing/public/cpp/perfetto/trace_packet_tokenizer.cc b/services/tracing/public/cpp/perfetto/trace_packet_tokenizer.cc
new file mode 100644
index 0000000..25f1321
--- /dev/null
+++ b/services/tracing/public/cpp/perfetto/trace_packet_tokenizer.cc
@@ -0,0 +1,99 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/tracing/public/cpp/perfetto/trace_packet_tokenizer.h"
+
+#include "base/check.h"
+#include "base/check_op.h"
+#include "base/macros.h"
+#include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_packet.h"
+
+namespace tracing {
+namespace {
+
+static constexpr uint8_t kPacketTag =
+    protozero::proto_utils::MakeTagLengthDelimited(
+        perfetto::TracePacket::kPacketFieldNumber);
+
+}  // namespace
+
+TracePacketTokenizer::TracePacketTokenizer() = default;
+TracePacketTokenizer::~TracePacketTokenizer() = default;
+TracePacketTokenizer::Packet::Packet() = default;
+TracePacketTokenizer::Packet::~Packet() = default;
+
+std::vector<perfetto::TracePacket> TracePacketTokenizer::Parse(
+    const uint8_t* data,
+    size_t size) {
+  std::vector<perfetto::TracePacket> packets;
+  const uint8_t* data_end = data + size;
+  const uint8_t* packet_ptr = data;
+
+  // Only one fragmented packet can be finalized per call to Parse(), so clear
+  // any previous one.
+  assembled_packet_ = Packet();
+
+  while (packet_ptr < data_end) {
+    // First parse the packet header, i.e., the one byte field tag and the
+    // variable sized packet length field.
+    if (!next_packet_.parsed_size) {
+      // Parse the field tag.
+      auto prev_header_size = next_packet_.header->size();
+      size_t bytes_to_copy = kMaxHeaderSize - prev_header_size;
+      next_packet_.header->insert(
+          next_packet_.header->end(), packet_ptr,
+          std::min(packet_ptr + bytes_to_copy, data_end));
+      DCHECK(next_packet_.header->size() <= kMaxHeaderSize);
+      if (next_packet_.header->size() < kMinHeaderSize) {
+        // Not enough data -- try again later.
+        return packets;
+      }
+      DCHECK_EQ(kPacketTag, next_packet_.header[0]);
+
+      // Parse the size field.
+      const auto* size_begin = &next_packet_.header[1];
+      const auto* size_end = protozero::proto_utils::ParseVarInt(
+          size_begin, &*next_packet_.header->end(), &next_packet_.parsed_size);
+      size_t size_field_size = size_end - size_begin;
+      if (!size_field_size) {
+        // Size field overflows to next chunk. Try again later.
+        return packets;
+      }
+      // Find the start of the packet data after the size field.
+      packet_ptr += sizeof(kPacketTag) + size_field_size - prev_header_size;
+    }
+
+    // We've now parsed the the proto preamble and the size field for our
+    // packet. Let's see if the packet fits completely into this chunk.
+    DCHECK(next_packet_.parsed_size);
+    size_t remaining_size =
+        next_packet_.parsed_size - next_packet_.partial_data->size();
+    if (packet_ptr + remaining_size > data_end) {
+      // Save remaining bytes into overflow buffer and try again later.
+      next_packet_.partial_data->insert(next_packet_.partial_data->end(),
+                                        packet_ptr, data_end);
+      return packets;
+    }
+
+    // The packet is now complete. It can have a slice overflowing from the
+    // previous chunk(s) as well a a slice in the current chunk.
+    packets.emplace_back();
+    if (!next_packet_.partial_data->empty()) {
+      DCHECK(assembled_packet_.partial_data->empty());
+      assembled_packet_ = std::move(next_packet_);
+      packets.back().AddSlice(&assembled_packet_.partial_data[0],
+                              assembled_packet_.partial_data->size());
+    }
+    CHECK_LE(packet_ptr + remaining_size, data_end);
+    packets.back().AddSlice(packet_ptr, remaining_size);
+    packet_ptr += remaining_size;
+
+    // Start a new packet.
+    next_packet_ = Packet();
+  }
+  DCHECK_EQ(packet_ptr, data_end);
+  return packets;
+}
+
+}  // namespace tracing
diff --git a/services/tracing/public/cpp/perfetto/trace_packet_tokenizer.h b/services/tracing/public/cpp/perfetto/trace_packet_tokenizer.h
new file mode 100644
index 0000000..62f7f50
--- /dev/null
+++ b/services/tracing/public/cpp/perfetto/trace_packet_tokenizer.h
@@ -0,0 +1,78 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_TRACING_PUBLIC_CPP_PERFETTO_TRACE_PACKET_TOKENIZER_H_
+#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_TRACE_PACKET_TOKENIZER_H_
+
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/containers/stack_container.h"
+#include "third_party/perfetto/include/perfetto/protozero/proto_utils.h"
+
+namespace perfetto {
+class TracePacket;
+}  // namespace perfetto
+
+namespace tracing {
+
+// Converts between a raw stream of perfetto::TracePacket bytes and a tokenized
+// vector of delineated packets.
+//
+// The tracing service provides us with serialized proto bytes, while the
+// Perfetto consumer expects a vector of TracePackets (i.e., without the field
+// number and size header) without partial or truncated packets. To translate
+// between the two, we find the position of each TracePacket and construct a
+// vector pointing to the original data at the corresponding offsets.
+//
+// To make matters more complicated, mojo can split the data chunks
+// arbitrarily, including in the middle of trace packets. To work around
+// this, we tokenize as much data as we can and buffer any unprocessed bytes as
+// long as needed.
+class COMPONENT_EXPORT(TRACING_CPP) TracePacketTokenizer {
+ public:
+  TracePacketTokenizer();
+  ~TracePacketTokenizer();
+
+  // Given a chunk of trace data, tokenize as many trace packets as possible
+  // (could be zero) and return the result. Note that the tokenized packets have
+  // pointers to |data| as well as |this|, so they won't be valid after another
+  // call to Parse().
+  std::vector<perfetto::TracePacket> Parse(const uint8_t* data, size_t size);
+
+  // Returns |true| if there is more data left to be consumed in the tokenizer.
+  bool has_more() const {
+    return !next_packet_.header->empty() || next_packet_.parsed_size ||
+           !next_packet_.partial_data->empty();
+  }
+
+ private:
+  static constexpr size_t kMinHeaderSize = sizeof(uint8_t) + sizeof(uint8_t);
+  static constexpr size_t kMaxHeaderSize =
+      sizeof(uint8_t) + protozero::proto_utils::kMessageLengthFieldSize;
+
+  struct Packet {
+    Packet();
+    ~Packet();
+
+    // Most trace packets are very small, so avoid heap allocations in the
+    // common case where one packet straddles the boundary between chunks.
+    base::StackVector<uint8_t, 64> partial_data;
+
+    uint64_t parsed_size = 0;
+    base::StackVector<uint8_t, kMaxHeaderSize> header;
+  };
+
+  // Packet currently being parsed.
+  Packet next_packet_;
+
+  // Most recently completed packet which spanned multiple chunks. Kept as a
+  // member so that the memory remains valid while the caller is processing the
+  // results.
+  Packet assembled_packet_;
+};
+
+}  // namespace tracing
+
+#endif  // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_TRACE_PACKET_TOKENIZER_H_
diff --git a/services/tracing/public/cpp/perfetto/trace_packet_tokenizer_unittest.cc b/services/tracing/public/cpp/perfetto/trace_packet_tokenizer_unittest.cc
new file mode 100644
index 0000000..9afa3bd
--- /dev/null
+++ b/services/tracing/public/cpp/perfetto/trace_packet_tokenizer_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/tracing/public/cpp/perfetto/trace_packet_tokenizer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_packet.h"
+#include "third_party/perfetto/protos/perfetto/trace/trace.pb.h"
+#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pb.h"
+
+#include <list>
+
+namespace tracing {
+namespace {
+
+constexpr char kTestString[] = "This little packet went to the market";
+
+class TracePacketTokenizerTest : public testing::Test {
+ protected:
+  // Parse a trace chunk using an indirect memory allocation so ASAN can detect
+  // any out-of-bounds reads.
+  std::vector<perfetto::TracePacket> ParseChunk(const uint8_t* data,
+                                                size_t size) {
+    input_chunks_.emplace_back(data, data + size);
+    auto& it = input_chunks_.back();
+    return tokenizer_.Parse(it.data(), it.size());
+  }
+
+  void Reset() {
+    input_chunks_.clear();
+    tokenizer_ = TracePacketTokenizer();
+  }
+
+  TracePacketTokenizer& tokenizer() { return tokenizer_; }
+
+ private:
+  std::list<std::vector<uint8_t>> input_chunks_;
+  TracePacketTokenizer tokenizer_;
+};
+
+TEST_F(TracePacketTokenizerTest, Basic) {
+  perfetto::protos::Trace trace;
+  auto* packet = trace.add_packet();
+  packet->mutable_for_testing()->set_str(kTestString);
+  auto packet_data = trace.SerializeAsString();
+
+  auto packets = ParseChunk(
+      reinterpret_cast<const uint8_t*>(packet_data.data()), packet_data.size());
+  EXPECT_EQ(1u, packets.size());
+  perfetto::protos::TracePacket parsed_packet;
+  EXPECT_TRUE(
+      parsed_packet.ParseFromString(packets[0].GetRawBytesForTesting()));
+  EXPECT_EQ(kTestString, parsed_packet.for_testing().str());
+  EXPECT_FALSE(tokenizer().has_more());
+}
+
+TEST_F(TracePacketTokenizerTest, PartialParse) {
+  perfetto::protos::Trace trace;
+  auto* packet = trace.add_packet();
+  packet->mutable_for_testing()->set_str(kTestString);
+  auto packet_data = trace.SerializeAsString();
+
+  auto packets =
+      ParseChunk(reinterpret_cast<const uint8_t*>(packet_data.data()),
+                 packet_data.size() / 2);
+  EXPECT_TRUE(packets.empty());
+  EXPECT_TRUE(tokenizer().has_more());
+
+  packets = ParseChunk(reinterpret_cast<const uint8_t*>(packet_data.data() +
+                                                        packet_data.size() / 2),
+                       packet_data.size() / 2);
+  EXPECT_EQ(1u, packets.size());
+  perfetto::protos::TracePacket parsed_packet;
+  EXPECT_TRUE(
+      parsed_packet.ParseFromString(packets[0].GetRawBytesForTesting()));
+  EXPECT_EQ(kTestString, parsed_packet.for_testing().str());
+  EXPECT_FALSE(tokenizer().has_more());
+}
+
+TEST_F(TracePacketTokenizerTest, MultiplePackets) {
+  constexpr size_t kPacketCount = 32;
+  perfetto::protos::Trace trace;
+  for (size_t i = 0; i < kPacketCount; i++) {
+    auto* packet = trace.add_packet();
+    packet->set_timestamp(i);
+    packet->mutable_for_testing()->set_str(kTestString);
+  }
+  auto packet_data = trace.SerializeAsString();
+
+  auto packets = ParseChunk(
+      reinterpret_cast<const uint8_t*>(packet_data.data()), packet_data.size());
+  EXPECT_EQ(kPacketCount, packets.size());
+
+  for (size_t i = 0; i < kPacketCount; i++) {
+    perfetto::protos::TracePacket parsed_packet;
+    EXPECT_TRUE(
+        parsed_packet.ParseFromString(packets[i].GetRawBytesForTesting()));
+    EXPECT_EQ(i, parsed_packet.timestamp());
+    EXPECT_EQ(kTestString, parsed_packet.for_testing().str());
+  }
+  EXPECT_FALSE(tokenizer().has_more());
+}
+
+TEST_F(TracePacketTokenizerTest, Fragmentation) {
+  constexpr size_t kPacketCount = 17;
+  perfetto::protos::Trace trace;
+  for (size_t i = 0; i < kPacketCount; i++) {
+    auto* packet = trace.add_packet();
+    packet->set_timestamp(i + 1);
+    packet->mutable_for_testing()->set_str(kTestString);
+  }
+  auto packet_data = trace.SerializeAsString();
+
+  for (size_t chunk_size = 1; chunk_size < packet_data.size(); chunk_size++) {
+    size_t packet_count = 0;
+    for (size_t offset = 0; offset < packet_data.size(); offset += chunk_size) {
+      const auto* chunk_start =
+          reinterpret_cast<const uint8_t*>(packet_data.data()) + offset;
+      const auto* chunk_end =
+          std::min(chunk_start + chunk_size,
+                   reinterpret_cast<const uint8_t*>(&*packet_data.end()));
+      auto packets = ParseChunk(chunk_start, chunk_end - chunk_start);
+      if (packets.empty())
+        continue;
+      packet_count += packets.size();
+
+      for (auto& packet : packets) {
+        perfetto::protos::TracePacket parsed_packet;
+        EXPECT_TRUE(
+            parsed_packet.ParseFromString(packet.GetRawBytesForTesting()));
+        EXPECT_GT(parsed_packet.timestamp(), 0u);
+        EXPECT_EQ(kTestString, parsed_packet.for_testing().str());
+      }
+    }
+    EXPECT_EQ(kPacketCount, packet_count);
+    EXPECT_FALSE(tokenizer().has_more());
+    Reset();
+  }
+}
+
+}  // namespace
+}  // namespace tracing
diff --git a/storage/browser/quota/client_usage_tracker.cc b/storage/browser/quota/client_usage_tracker.cc
index 12ab0e6..4c07f72 100644
--- a/storage/browser/quota/client_usage_tracker.cc
+++ b/storage/browser/quota/client_usage_tracker.cc
@@ -29,14 +29,14 @@
 bool EraseOriginFromOriginSet(OriginSetByHost* origins_by_host,
                               const std::string& host,
                               const url::Origin& origin) {
-  auto found = origins_by_host->find(host);
-  if (found == origins_by_host->end())
+  auto it = origins_by_host->find(host);
+  if (it == origins_by_host->end())
     return false;
 
-  if (!found->second.erase(origin))
+  if (!it->second.erase(origin))
     return false;
 
-  if (found->second.empty())
+  if (it->second.empty())
     origins_by_host->erase(host);
   return true;
 }
@@ -223,17 +223,17 @@
   const std::string& host = origin.host();
   if (!enabled) {
     // Erase |origin| from cache and subtract its usage.
-    auto found_host = cached_usage_by_host_.find(host);
-    if (found_host != cached_usage_by_host_.end()) {
-      UsageMap& cached_usage_for_host = found_host->second;
+    auto host_it = cached_usage_by_host_.find(host);
+    if (host_it != cached_usage_by_host_.end()) {
+      UsageMap& cached_usage_for_host = host_it->second;
 
-      auto found = cached_usage_for_host.find(origin);
-      if (found != cached_usage_for_host.end()) {
-        int64_t usage = found->second;
+      auto origin_it = cached_usage_for_host.find(origin);
+      if (origin_it != cached_usage_for_host.end()) {
+        int64_t usage = origin_it->second;
         UpdateUsageCache(origin, -usage);
-        cached_usage_for_host.erase(found);
+        cached_usage_for_host.erase(origin_it);
         if (cached_usage_for_host.empty()) {
-          cached_usage_by_host_.erase(found_host);
+          cached_usage_by_host_.erase(host_it);
           cached_hosts_.erase(host);
         }
       }
@@ -414,12 +414,12 @@
 
 int64_t ClientUsageTracker::GetCachedHostUsage(const std::string& host) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto found = cached_usage_by_host_.find(host);
-  if (found == cached_usage_by_host_.end())
+  auto it = cached_usage_by_host_.find(host);
+  if (it == cached_usage_by_host_.end())
     return 0;
 
   int64_t usage = 0;
-  const UsageMap& usage_map = found->second;
+  const UsageMap& usage_map = it->second;
   for (const auto& origin_and_usage : usage_map)
     usage += origin_and_usage.second;
   return usage;
@@ -429,16 +429,16 @@
                                               int64_t* usage) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const std::string& host = origin.host();
-  auto found_host = cached_usage_by_host_.find(host);
-  if (found_host == cached_usage_by_host_.end())
+  auto host_it = cached_usage_by_host_.find(host);
+  if (host_it == cached_usage_by_host_.end())
     return false;
 
-  auto found = found_host->second.find(origin);
-  if (found == found_host->second.end())
+  auto origin_it = host_it->second.find(origin);
+  if (origin_it == host_it->second.end())
     return false;
 
   DCHECK(IsUsageCacheEnabledForOrigin(origin));
-  *usage = found->second;
+  *usage = origin_it->second;
   return true;
 }
 
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc
index 63b2e52..2ca38b8 100644
--- a/storage/browser/quota/quota_manager.cc
+++ b/storage/browser/quota/quota_manager.cc
@@ -1575,15 +1575,15 @@
 
     // Ignore stale database entries. If there is no map entry, the origin's
     // data has been deleted.
-    auto found = usage_map.find(info.origin);
-    if (found == usage_map.end() || found->second == 0)
+    auto it = usage_map.find(info.origin);
+    if (it == usage_map.end() || it->second == 0)
       continue;
 
     base::TimeDelta age = now - std::max(info.last_access_time,
                                          info.last_modified_time);
     UMA_HISTOGRAM_COUNTS_1000("Quota.AgeOfOriginInDays", age.InDays());
 
-    int64_t kilobytes = std::max(found->second / INT64_C(1024), INT64_C(1));
+    int64_t kilobytes = std::max(it->second / INT64_C(1024), INT64_C(1));
     base::Histogram::FactoryGet(
         "Quota.AgeOfDataInDays", 1, 1000, 50,
         base::HistogramBase::kUmaTargetedHistogramFlag)->
diff --git a/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc b/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc
index 8a0e289..2f1b729 100644
--- a/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc
+++ b/storage/browser/quota/quota_temporary_storage_evictor_unittest.cc
@@ -108,9 +108,9 @@
   // Simulates an access to |origin|.  It reorders the internal LRU list.
   // It internally uses AddOrigin().
   void AccessOrigin(const url::Origin& origin) {
-    const auto& found = origins_.find(origin);
-    EXPECT_TRUE(origins_.end() != found);
-    AddOrigin(origin, found->second);
+    const auto& it = origins_.find(origin);
+    EXPECT_TRUE(origins_.end() != it);
+    AddOrigin(origin, it->second);
   }
 
   // Simulates adding or overwriting the |origin| to the internal origin set
diff --git a/storage/browser/quota/usage_tracker.cc b/storage/browser/quota/usage_tracker.cc
index 3ad8717..a65d90a 100644
--- a/storage/browser/quota/usage_tracker.cc
+++ b/storage/browser/quota/usage_tracker.cc
@@ -318,15 +318,15 @@
 void UsageTracker::FinallySendHostUsageWithBreakdown(AccumulateInfo* info,
                                                      const std::string& host) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  auto host_it = host_usage_callbacks_.find(host);
-  if (host_it == host_usage_callbacks_.end())
+  auto it = host_usage_callbacks_.find(host);
+  if (it == host_usage_callbacks_.end())
     return;
 
   std::vector<UsageWithBreakdownCallback> pending_callbacks;
-  pending_callbacks.swap(host_it->second);
+  pending_callbacks.swap(it->second);
   DCHECK(pending_callbacks.size() > 0)
       << "host_usage_callbacks_ should only have non-empty callback lists";
-  host_usage_callbacks_.erase(host_it);
+  host_usage_callbacks_.erase(it);
 
   for (auto& callback : pending_callbacks) {
     std::move(callback).Run(info->usage, info->usage_breakdown->Clone());
diff --git a/storage/browser/quota/usage_tracker_unittest.cc b/storage/browser/quota/usage_tracker_unittest.cc
index 9210f45..a709019 100644
--- a/storage/browser/quota/usage_tracker_unittest.cc
+++ b/storage/browser/quota/usage_tracker_unittest.cc
@@ -96,10 +96,10 @@
   }
 
   int64_t GetUsage(const url::Origin& origin) {
-    auto found = origin_usage_map_.find(origin);
-    if (found == origin_usage_map_.end())
+    auto it = origin_usage_map_.find(origin);
+    if (it == origin_usage_map_.end())
       return 0;
-    return found->second;
+    return it->second;
   }
 
   void SetUsage(const url::Origin& origin, int64_t usage) {
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index f37dae3..6b5c628 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: 10cb35e459f5ecca5b2ff107635da0bfa41011b4
+Revision: 38db52adb2eabc0969195b33b30763e0a1285ef9
 Security Critical: yes
 
 Description:
diff --git a/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h b/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h
index 961cc98..ed0b4bfa 100644
--- a/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h
+++ b/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h
@@ -76,7 +76,7 @@
     bool disabled;
   };
 
-  // Access to SchedulingGuard is explicitly white-listed.
+  // Access to SchedulingGuard is explicitly permitted.
   friend class SchedulingHelper;
   friend class SpinLock;
 
diff --git a/third_party/abseil-cpp/absl/base/internal/raw_logging.cc b/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
index f27e2838..ae8754c 100644
--- a/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
+++ b/third_party/abseil-cpp/absl/base/internal/raw_logging.cc
@@ -69,7 +69,7 @@
 
 // TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
 // Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
-// whitelisted set of platforms for which we expect not to be able to raw log.
+// selected set of platforms for which we expect not to be able to raw log.
 
 ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
     absl::raw_logging_internal::LogPrefixHook>
diff --git a/third_party/abseil-cpp/absl/base/internal/spinlock.h b/third_party/abseil-cpp/absl/base/internal/spinlock.h
index 2222398..e6ac9e6 100644
--- a/third_party/abseil-cpp/absl/base/internal/spinlock.h
+++ b/third_party/abseil-cpp/absl/base/internal/spinlock.h
@@ -64,7 +64,14 @@
   constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
       : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
 
+  // For global SpinLock instances prefer trivial destructor when possible.
+  // Default but non-trivial destructor in some build configurations causes an
+  // extra static initializer.
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
   ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
+#else
+  ~SpinLock() = default;
+#endif
 
   // Acquire this SpinLock.
   inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
diff --git a/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h b/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h
index cdce9bf..82f2c87 100644
--- a/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h
+++ b/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h
@@ -15,8 +15,8 @@
 // UnscaledCycleClock
 //    An UnscaledCycleClock yields the value and frequency of a cycle counter
 //    that increments at a rate that is approximately constant.
-//    This class is for internal / whitelisted use only, you should consider
-//    using CycleClock instead.
+//    This class is for internal use only, you should consider using CycleClock
+//    instead.
 //
 // Notes:
 // The cycle counter frequency is not necessarily the core clock frequency.
@@ -109,7 +109,7 @@
   // value.
   static double Frequency();
 
-  // Whitelisted friends.
+  // Allowed users
   friend class base_internal::CycleClock;
   friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
   friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
diff --git a/third_party/abseil-cpp/absl/base/spinlock_test_common.cc b/third_party/abseil-cpp/absl/base/spinlock_test_common.cc
index b68c51a..b33c54ba 100644
--- a/third_party/abseil-cpp/absl/base/spinlock_test_common.cc
+++ b/third_party/abseil-cpp/absl/base/spinlock_test_common.cc
@@ -20,6 +20,7 @@
 #include <limits>
 #include <random>
 #include <thread>  // NOLINT(build/c++11)
+#include <type_traits>
 #include <vector>
 
 #include "gtest/gtest.h"
@@ -103,6 +104,10 @@
   }
 }
 
+#ifndef THREAD_SANITIZER
+static_assert(std::is_trivially_destructible<SpinLock>(), "");
+#endif
+
 TEST(SpinLock, StackNonCooperativeDisablesScheduling) {
   SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
   spinlock.Lock();
diff --git a/third_party/abseil-cpp/absl/base/thread_annotations.h b/third_party/abseil-cpp/absl/base/thread_annotations.h
index 7eb1d59..0c207e0 100644
--- a/third_party/abseil-cpp/absl/base/thread_annotations.h
+++ b/third_party/abseil-cpp/absl/base/thread_annotations.h
@@ -34,6 +34,7 @@
 #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
 #define ABSL_BASE_THREAD_ANNOTATIONS_H_
 
+#include "absl/base/attributes.h"
 #include "absl/base/config.h"
 
 #if defined(__clang__)
@@ -149,8 +150,12 @@
 // 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 ABSL_LOCK_RETURNED.
+#if ABSL_HAVE_ATTRIBUTE(lock_returned)
 #define ABSL_LOCK_RETURNED(x) \
   ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x))
+#else
+#define ABSL_LOCK_RETURNED(x)
+#endif
 
 // ABSL_LOCKABLE
 //
diff --git a/third_party/abseil-cpp/absl/container/fixed_array.h b/third_party/abseil-cpp/absl/container/fixed_array.h
index 60637d99..e74802a 100644
--- a/third_party/abseil-cpp/absl/container/fixed_array.h
+++ b/third_party/abseil-cpp/absl/container/fixed_array.h
@@ -505,8 +505,10 @@
     typename FixedArray<T, N, A>::size_type n) {
 #ifdef ADDRESS_SANITIZER
   if (!n) return;
-  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n);
-  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin());
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(),
+                                     data() + n);
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(),
+                                     RedzoneBegin());
 #endif                   // ADDRESS_SANITIZER
   static_cast<void>(n);  // Mark used when not in asan mode
 }
@@ -516,8 +518,10 @@
     typename FixedArray<T, N, A>::size_type n) {
 #ifdef ADDRESS_SANITIZER
   if (!n) return;
-  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd());
-  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data());
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n,
+                                     RedzoneEnd());
+  ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(),
+                                     data());
 #endif                   // ADDRESS_SANITIZER
   static_cast<void>(n);  // Mark used when not in asan mode
 }
diff --git a/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc b/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc
index 2d05a0b7..59576b8 100644
--- a/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc
+++ b/third_party/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc
@@ -337,11 +337,11 @@
 }  // namespace absl
 
 enum Hash : size_t {
-  kStd = 0x2,       // std::hash
+  kStd = 0x1,       // std::hash
 #ifdef _MSC_VER
   kExtension = kStd,  // In MSVC, std::hash == ::hash
 #else                 // _MSC_VER
-  kExtension = 0x4,  // ::hash (GCC extension)
+  kExtension = 0x2,  // ::hash (GCC extension)
 #endif                // _MSC_VER
 };
 
diff --git a/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc b/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc
index b960cc4..559af8d 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc
+++ b/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc
@@ -175,18 +175,6 @@
   return ret_code == 0 ? cpu : ret_code;
 }
 
-// We need to make sure VDSOSupport::Init() is called before
-// InitGoogle() does any setuid or chroot calls.  If VDSOSupport
-// is used in any global constructor, this will happen, since
-// VDSOSupport's constructor calls Init.  But if not, we need to
-// ensure it here, with a global constructor of our own.  This
-// is an allowed exception to the normal rule against non-trivial
-// global constructors.
-static class VDSOInitHelper {
- public:
-  VDSOInitHelper() { VDSOSupport::Init(); }
-} vdso_init_helper;
-
 }  // namespace debugging_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc b/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc
index ed77159e..b7f8663 100644
--- a/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc
+++ b/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc
@@ -83,6 +83,12 @@
 static char *argv0_value = nullptr;
 
 void InitializeSymbolizer(const char *argv0) {
+#ifdef ABSL_HAVE_VDSO_SUPPORT
+  // We need to make sure VDSOSupport::Init() is called before any setuid or
+  // chroot calls, so InitializeSymbolizer() should be called very early in the
+  // life of a program.
+  absl::debugging_internal::VDSOSupport::Init();
+#endif
   if (argv0_value != nullptr) {
     free(argv0_value);
     argv0_value = nullptr;
@@ -1376,7 +1382,7 @@
 
   if (!g_decorators_mu.TryLock()) {
     // Someone else is using decorators. Get out.
-    return false;
+    return -2;
   }
   int ret = ticket;
   if (g_num_decorators >= kMaxDecorators) {
diff --git a/third_party/abseil-cpp/absl/flags/BUILD.bazel b/third_party/abseil-cpp/absl/flags/BUILD.bazel
index 006911f..524e7027 100644
--- a/third_party/abseil-cpp/absl/flags/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/flags/BUILD.bazel
@@ -106,6 +106,9 @@
 
 cc_library(
     name = "commandlineflag_internal",
+    srcs = [
+        "internal/commandlineflag.cc",
+    ],
     hdrs = [
         "internal/commandlineflag.h",
     ],
diff --git a/third_party/abseil-cpp/absl/flags/BUILD.gn b/third_party/abseil-cpp/absl/flags/BUILD.gn
index 969d89e..a9fbbcb1 100644
--- a/third_party/abseil-cpp/absl/flags/BUILD.gn
+++ b/third_party/abseil-cpp/absl/flags/BUILD.gn
@@ -66,6 +66,7 @@
 absl_source_set("commandlineflag_internal") {
   testonly = true
   public = [ "internal/commandlineflag.h" ]
+  sources = [ "internal/commandlineflag.cc" ]
   deps = [
     "//third_party/abseil-cpp/absl/base:config",
     "//third_party/abseil-cpp/absl/base:fast_type_id",
diff --git a/third_party/abseil-cpp/absl/flags/CMakeLists.txt b/third_party/abseil-cpp/absl/flags/CMakeLists.txt
index ef75db8e..343774d 100644
--- a/third_party/abseil-cpp/absl/flags/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/flags/CMakeLists.txt
@@ -95,6 +95,8 @@
 absl_cc_library(
   NAME
     flags_commandlineflag_internal
+  SRCS
+    "internal/commandlineflag.cc"
   HDRS
     "internal/commandlineflag.h"
   COPTS
diff --git a/third_party/abseil-cpp/absl/flags/commandlineflag.cc b/third_party/abseil-cpp/absl/flags/commandlineflag.cc
index 217b2d87..9f3b4a5 100644
--- a/third_party/abseil-cpp/absl/flags/commandlineflag.cc
+++ b/third_party/abseil-cpp/absl/flags/commandlineflag.cc
@@ -30,9 +30,5 @@
                    flags_internal::kProgrammaticChange, *error);
 }
 
-namespace flags_internal {
-FlagStateInterface::~FlagStateInterface() {}
-}  // namespace flags_internal
 ABSL_NAMESPACE_END
 }  // namespace absl
-
diff --git a/third_party/abseil-cpp/absl/flags/commandlineflag.h b/third_party/abseil-cpp/absl/flags/commandlineflag.h
index 7e21d05..f2fa089 100644
--- a/third_party/abseil-cpp/absl/flags/commandlineflag.h
+++ b/third_party/abseil-cpp/absl/flags/commandlineflag.h
@@ -108,6 +108,10 @@
     U u;
 
     Read(&u.value);
+    // allow retired flags to be "read", so we can report invalid access.
+    if (IsRetired()) {
+      return absl::nullopt;
+    }
     return std::move(u.value);
   }
 
diff --git a/third_party/abseil-cpp/absl/flags/internal/commandlineflag.cc b/third_party/abseil-cpp/absl/flags/internal/commandlineflag.cc
new file mode 100644
index 0000000..4482955
--- /dev/null
+++ b/third_party/abseil-cpp/absl/flags/internal/commandlineflag.cc
@@ -0,0 +1,26 @@
+//
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/flags/internal/commandlineflag.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace flags_internal {
+
+FlagStateInterface::~FlagStateInterface() {}
+
+}  // namespace flags_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/third_party/abseil-cpp/absl/flags/internal/flag.h b/third_party/abseil-cpp/absl/flags/internal/flag.h
index 2cc44e0..89e43ad 100644
--- a/third_party/abseil-cpp/absl/flags/internal/flag.h
+++ b/third_party/abseil-cpp/absl/flags/internal/flag.h
@@ -482,7 +482,8 @@
   friend class FlagState;
 
   // Ensures that `data_guard_` is initialized and returns it.
-  absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED((absl::Mutex*)&data_guard_);
+  absl::Mutex* DataGuard() const
+      ABSL_LOCK_RETURNED(reinterpret_cast<absl::Mutex*>(data_guard_));
   // Returns heap allocated value of type T initialized with default value.
   std::unique_ptr<void, DynValueDeleter> MakeInitValue() const
       ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
diff --git a/third_party/abseil-cpp/absl/flags/internal/usage.cc b/third_party/abseil-cpp/absl/flags/internal/usage.cc
index 35b6427..0805df3 100644
--- a/third_party/abseil-cpp/absl/flags/internal/usage.cc
+++ b/third_party/abseil-cpp/absl/flags/internal/usage.cc
@@ -250,14 +250,14 @@
       matching_flags;
 
   flags_internal::ForEachFlag([&](absl::CommandLineFlag& flag) {
-    std::string flag_filename = flag.Filename();
-
     // Ignore retired flags.
     if (flag.IsRetired()) return;
 
     // If the flag has been stripped, pretend that it doesn't exist.
     if (flag.Help() == flags_internal::kStrippedFlagHelp) return;
 
+    std::string flag_filename = flag.Filename();
+
     // Make sure flag satisfies the filter
     if (!filter_cb || !filter_cb(flag_filename)) return;
 
diff --git a/third_party/abseil-cpp/absl/flags/parse.cc b/third_party/abseil-cpp/absl/flags/parse.cc
index e2c88ff8..4f4bb3d5 100644
--- a/third_party/abseil-cpp/absl/flags/parse.cc
+++ b/third_party/abseil-cpp/absl/flags/parse.cc
@@ -729,12 +729,13 @@
     }
 
     // 100. Set the located flag to a new new value, unless it is retired.
-    // Setting retired flag fails, but we ignoring it here.
-    if (flag->IsRetired()) continue;
-
+    // Setting retired flag fails, but we ignoring it here while also reporting
+    // access to retired flag.
     std::string error;
     if (!flags_internal::PrivateHandleAccessor::ParseFrom(
             *flag, value, SET_FLAGS_VALUE, kCommandLine, error)) {
+      if (flag->IsRetired()) continue;
+
       flags_internal::ReportUsageError(error, true);
       success = false;
     } else {
diff --git a/third_party/abseil-cpp/absl/flags/reflection.cc b/third_party/abseil-cpp/absl/flags/reflection.cc
index 5fc945f2..02b7c06 100644
--- a/third_party/abseil-cpp/absl/flags/reflection.cc
+++ b/third_party/abseil-cpp/absl/flags/reflection.cc
@@ -88,12 +88,6 @@
   if (i == flags_.end()) {
     return nullptr;
   }
-
-  if (i->second->IsRetired()) {
-    flags_internal::ReportUsageError(
-        absl::StrCat("Accessing retired flag '", name, "'"), false);
-  }
-
   return i->second;
 }
 
@@ -155,7 +149,7 @@
     } else {
       flags_internal::ReportUsageError(
           absl::StrCat(
-              "Something wrong with flag '", flag.Name(), "' in file '",
+              "Something is wrong with flag '", flag.Name(), "' in file '",
               flag.Filename(), "'. One possibility: file '", flag.Filename(),
               "' is being linked both statically and dynamically into this "
               "executable. e.g. some files listed as srcs to a test and also "
@@ -206,16 +200,34 @@
 
  private:
   absl::string_view Name() const override { return name_; }
-  std::string Filename() const override { return "RETIRED"; }
+  std::string Filename() const override {
+    OnAccess();
+    return "RETIRED";
+  }
   FlagFastTypeId TypeId() const override { return type_id_; }
-  std::string Help() const override { return ""; }
+  std::string Help() const override {
+    OnAccess();
+    return "";
+  }
   bool IsRetired() const override { return true; }
-  bool IsSpecifiedOnCommandLine() const override { return false; }
-  std::string DefaultValue() const override { return ""; }
-  std::string CurrentValue() const override { return ""; }
+  bool IsSpecifiedOnCommandLine() const override {
+    OnAccess();
+    return false;
+  }
+  std::string DefaultValue() const override {
+    OnAccess();
+    return "";
+  }
+  std::string CurrentValue() const override {
+    OnAccess();
+    return "";
+  }
 
   // Any input is valid
-  bool ValidateInputValue(absl::string_view) const override { return true; }
+  bool ValidateInputValue(absl::string_view) const override {
+    OnAccess();
+    return true;
+  }
 
   std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
     return nullptr;
@@ -223,12 +235,18 @@
 
   bool ParseFrom(absl::string_view, flags_internal::FlagSettingMode,
                  flags_internal::ValueSource, std::string&) override {
+    OnAccess();
     return false;
   }
 
-  void CheckDefaultValueParsingRoundtrip() const override {}
+  void CheckDefaultValueParsingRoundtrip() const override { OnAccess(); }
 
-  void Read(void*) const override {}
+  void Read(void*) const override { OnAccess(); }
+
+  void OnAccess() const {
+    flags_internal::ReportUsageError(
+        absl::StrCat("Accessing retired flag '", name_, "'"), false);
+  }
 
   // Data members
   const char* const name_;
diff --git a/third_party/abseil-cpp/absl/random/BUILD.bazel b/third_party/abseil-cpp/absl/random/BUILD.bazel
index 694331c2..81e150e6 100644
--- a/third_party/abseil-cpp/absl/random/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/random/BUILD.bazel
@@ -199,6 +199,7 @@
 cc_test(
     name = "distributions_test",
     size = "small",
+    timeout = "moderate",
     srcs = [
         "distributions_test.cc",
     ],
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.bazel b/third_party/abseil-cpp/absl/strings/BUILD.bazel
index 8220896..ef41263 100644
--- a/third_party/abseil-cpp/absl/strings/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/strings/BUILD.bazel
@@ -720,6 +720,7 @@
     visibility = ["//visibility:private"],
     deps = [
         ":str_format_internal",
+        ":strings",
         "//absl/base:raw_logging_internal",
         "//absl/types:optional",
         "@com_google_googletest//:gtest_main",
diff --git a/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/third_party/abseil-cpp/absl/strings/CMakeLists.txt
index c0ea0c8e..d723723 100644
--- a/third_party/abseil-cpp/absl/strings/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/strings/CMakeLists.txt
@@ -475,6 +475,7 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::strings
     absl::str_format_internal
     absl::raw_logging_internal
     absl::int128
diff --git a/third_party/abseil-cpp/absl/strings/cord.cc b/third_party/abseil-cpp/absl/strings/cord.cc
index 68f5398..70c399c18 100644
--- a/third_party/abseil-cpp/absl/strings/cord.cc
+++ b/third_party/abseil-cpp/absl/strings/cord.cc
@@ -493,10 +493,7 @@
 // --------------------------------------------------------------------
 // Cord::InlineRep functions
 
-// This will trigger LNK2005 in MSVC.
-#ifndef COMPILER_MSVC
-const unsigned char Cord::InlineRep::kMaxInline;
-#endif  // COMPILER_MSVC
+constexpr unsigned char Cord::InlineRep::kMaxInline;
 
 inline void Cord::InlineRep::set_data(const char* data, size_t n,
                                       bool nullify_tail) {
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
index 0e8535c..5ee5fbc 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
@@ -12,6 +12,7 @@
 #include "gtest/gtest.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/strings/internal/str_format/bind.h"
+#include "absl/strings/match.h"
 #include "absl/types/optional.h"
 
 namespace absl {
@@ -19,6 +20,13 @@
 namespace str_format_internal {
 namespace {
 
+struct NativePrintfTraits {
+  bool hex_float_has_glibc_rounding;
+  bool hex_float_prefers_denormal_repr;
+  bool hex_float_uses_minimal_precision_when_not_specified;
+  bool hex_float_optimizes_leading_digit_bit_count;
+};
+
 template <typename T, size_t N>
 size_t ArraySize(T (&)[N]) {
   return N;
@@ -118,6 +126,63 @@
   return result;
 }
 
+NativePrintfTraits VerifyNativeImplementationImpl() {
+  NativePrintfTraits result;
+
+  // >>> hex_float_has_glibc_rounding. To have glibc's rounding behavior we need
+  // to meet three requirements:
+  //
+  //   - The threshold for rounding up is 8 (for e.g. MSVC uses 9).
+  //   - If the digits lower than than the 8 are non-zero then we round up.
+  //   - If the digits lower than the 8 are all zero then we round toward even.
+  //
+  // The numbers below represent all the cases covering {below,at,above} the
+  // threshold (8) with both {zero,non-zero} lower bits and both {even,odd}
+  // preceding digits.
+  const double d0079 = 65657.0;  // 0x1.0079p+16
+  const double d0179 = 65913.0;  // 0x1.0179p+16
+  const double d0080 = 65664.0;  // 0x1.0080p+16
+  const double d0180 = 65920.0;  // 0x1.0180p+16
+  const double d0081 = 65665.0;  // 0x1.0081p+16
+  const double d0181 = 65921.0;  // 0x1.0181p+16
+  result.hex_float_has_glibc_rounding =
+      StartsWith(StrPrint("%.2a", d0079), "0x1.00") &&
+      StartsWith(StrPrint("%.2a", d0179), "0x1.01") &&
+      StartsWith(StrPrint("%.2a", d0080), "0x1.00") &&
+      StartsWith(StrPrint("%.2a", d0180), "0x1.02") &&
+      StartsWith(StrPrint("%.2a", d0081), "0x1.01") &&
+      StartsWith(StrPrint("%.2a", d0181), "0x1.02");
+
+  // >>> hex_float_prefers_denormal_repr. Formatting `denormal` on glibc yields
+  // "0x0.0000000000001p-1022", whereas on std libs that don't use denormal
+  // representation it would either be 0x1p-1074 or 0x1.0000000000000-1074.
+  const double denormal = std::numeric_limits<double>::denorm_min();
+  result.hex_float_prefers_denormal_repr =
+      StartsWith(StrPrint("%a", denormal), "0x0.0000000000001");
+
+  // >>> hex_float_uses_minimal_precision_when_not_specified. Some (non-glibc)
+  // libs will format the following as "0x1.0079000000000p+16".
+  result.hex_float_uses_minimal_precision_when_not_specified =
+      (StrPrint("%a", d0079) == "0x1.0079p+16");
+
+  // >>> hex_float_optimizes_leading_digit_bit_count. The number 1.5, when
+  // formatted by glibc should yield "0x1.8p+0" for `double` and "0xcp-3" for
+  // `long double`, i.e., number of bits in the leading digit is adapted to the
+  // number of bits in the mantissa.
+  const double d_15 = 1.5;
+  const long double ld_15 = 1.5;
+  result.hex_float_optimizes_leading_digit_bit_count =
+      StartsWith(StrPrint("%a", d_15), "0x1.8") &&
+      StartsWith(StrPrint("%La", ld_15), "0xc");
+
+  return result;
+}
+
+const NativePrintfTraits &VerifyNativeImplementation() {
+  static NativePrintfTraits native_traits = VerifyNativeImplementationImpl();
+  return native_traits;
+}
+
 class FormatConvertTest : public ::testing::Test { };
 
 template <typename T>
@@ -474,6 +539,68 @@
   }
 }
 
+template <typename Floating>
+void TestWithMultipleFormatsHelper(const std::vector<Floating> &floats) {
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+  // Reserve the space to ensure we don't allocate memory in the output itself.
+  std::string str_format_result;
+  str_format_result.reserve(1 << 20);
+  std::string string_printf_result;
+  string_printf_result.reserve(1 << 20);
+
+  const char *const kFormats[] = {
+      "%",  "%.3", "%8.5", "%500",   "%.5000", "%.60", "%.30",   "%03",
+      "%+", "% ",  "%-10", "%#15.3", "%#.0",   "%.0",  "%1$*2$", "%1$.*2$"};
+
+  for (const char *fmt : kFormats) {
+    for (char f : {'f', 'F',  //
+                   'g', 'G',  //
+                   'a', 'A',  //
+                   'e', 'E'}) {
+      std::string fmt_str = std::string(fmt) + f;
+
+      if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F' &&
+          f != 'a' && f != 'A') {
+        // This particular test takes way too long with snprintf.
+        // Disable for the case we are not implementing natively.
+        continue;
+      }
+
+      if ((f == 'a' || f == 'A') &&
+          !native_traits.hex_float_has_glibc_rounding) {
+        continue;
+      }
+
+      for (Floating d : floats) {
+        if (!native_traits.hex_float_prefers_denormal_repr &&
+            (f == 'a' || f == 'A') && std::fpclassify(d) == FP_SUBNORMAL) {
+          continue;
+        }
+        int i = -10;
+        FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
+        UntypedFormatSpecImpl format(fmt_str);
+
+        string_printf_result.clear();
+        StrAppend(&string_printf_result, fmt_str.c_str(), d, i);
+        str_format_result.clear();
+
+        {
+          AppendPack(&str_format_result, format, absl::MakeSpan(args));
+        }
+
+        if (string_printf_result != str_format_result) {
+          // We use ASSERT_EQ here because failures are usually correlated and a
+          // bug would print way too many failed expectations causing the test
+          // to time out.
+          ASSERT_EQ(string_printf_result, str_format_result)
+              << fmt_str << " " << StrPrint("%.18g", d) << " "
+              << StrPrint("%a", d) << " " << StrPrint("%.50f", d);
+        }
+      }
+    }
+  }
+}
+
 TEST_F(FormatConvertTest, Float) {
 #ifdef _MSC_VER
   // MSVC has a different rounding policy than us so we can't test our
@@ -481,9 +608,62 @@
   return;
 #endif  // _MSC_VER
 
-  const char *const kFormats[] = {
-      "%",  "%.3", "%8.5", "%500",   "%.5000", "%.60", "%.30",   "%03",
-      "%+", "% ",  "%-10", "%#15.3", "%#.0",   "%.0",  "%1$*2$", "%1$.*2$"};
+  std::vector<float> floats = {0.0f,
+                               -0.0f,
+                               .9999999f,
+                               9999999.f,
+                               std::numeric_limits<float>::max(),
+                               -std::numeric_limits<float>::max(),
+                               std::numeric_limits<float>::min(),
+                               -std::numeric_limits<float>::min(),
+                               std::numeric_limits<float>::lowest(),
+                               -std::numeric_limits<float>::lowest(),
+                               std::numeric_limits<float>::epsilon(),
+                               std::numeric_limits<float>::epsilon() + 1.0f,
+                               std::numeric_limits<float>::infinity(),
+                               -std::numeric_limits<float>::infinity()};
+
+  // Some regression tests.
+  floats.push_back(0.999999989f);
+
+  if (std::numeric_limits<float>::has_denorm != std::denorm_absent) {
+    floats.push_back(std::numeric_limits<float>::denorm_min());
+    floats.push_back(-std::numeric_limits<float>::denorm_min());
+  }
+
+  for (float base :
+       {1.f, 12.f, 123.f, 1234.f, 12345.f, 123456.f, 1234567.f, 12345678.f,
+        123456789.f, 1234567890.f, 12345678901.f, 12345678.f, 12345678.f}) {
+    for (int exp = -123; exp <= 123; ++exp) {
+      for (int sign : {1, -1}) {
+        floats.push_back(sign * std::ldexp(base, exp));
+      }
+    }
+  }
+
+  for (int exp = -300; exp <= 300; ++exp) {
+    const float all_ones_mantissa = 0xffffff;
+    floats.push_back(std::ldexp(all_ones_mantissa, exp));
+  }
+
+  // Remove duplicates to speed up the logic below.
+  std::sort(floats.begin(), floats.end());
+  floats.erase(std::unique(floats.begin(), floats.end()), floats.end());
+
+#ifndef __APPLE__
+  // Apple formats NaN differently (+nan) vs. (nan)
+  floats.push_back(std::nan(""));
+#endif
+
+  TestWithMultipleFormatsHelper(floats);
+}
+
+TEST_F(FormatConvertTest, Double) {
+#ifdef _MSC_VER
+  // MSVC has a different rounding policy than us so we can't test our
+  // implementation against the native one there.
+  return;
+#endif  // _MSC_VER
 
   std::vector<double> doubles = {0.0,
                                  -0.0,
@@ -554,52 +734,10 @@
   doubles.push_back(std::nan(""));
 #endif
 
-  // Reserve the space to ensure we don't allocate memory in the output itself.
-  std::string str_format_result;
-  str_format_result.reserve(1 << 20);
-  std::string string_printf_result;
-  string_printf_result.reserve(1 << 20);
-
-  for (const char *fmt : kFormats) {
-    for (char f : {'f', 'F',  //
-                   'g', 'G',  //
-                   'a', 'A',  //
-                   'e', 'E'}) {
-      std::string fmt_str = std::string(fmt) + f;
-
-      if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F') {
-        // This particular test takes way too long with snprintf.
-        // Disable for the case we are not implementing natively.
-        continue;
-      }
-
-      for (double d : doubles) {
-        int i = -10;
-        FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)};
-        UntypedFormatSpecImpl format(fmt_str);
-
-        string_printf_result.clear();
-        StrAppend(&string_printf_result, fmt_str.c_str(), d, i);
-        str_format_result.clear();
-
-        {
-          AppendPack(&str_format_result, format, absl::MakeSpan(args));
-        }
-
-        if (string_printf_result != str_format_result) {
-          // We use ASSERT_EQ here because failures are usually correlated and a
-          // bug would print way too many failed expectations causing the test
-          // to time out.
-          ASSERT_EQ(string_printf_result, str_format_result)
-              << fmt_str << " " << StrPrint("%.18g", d) << " "
-              << StrPrint("%a", d) << " " << StrPrint("%.1080f", d);
-        }
-      }
-    }
-  }
+  TestWithMultipleFormatsHelper(doubles);
 }
 
-TEST_F(FormatConvertTest, FloatRound) {
+TEST_F(FormatConvertTest, DoubleRound) {
   std::string s;
   const auto format = [&](const char *fmt, double d) -> std::string & {
     s.clear();
@@ -704,6 +842,193 @@
             "1837869002408041296803276054561138153076171875");
 }
 
+TEST_F(FormatConvertTest, DoubleRoundA) {
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+  std::string s;
+  const auto format = [&](const char *fmt, double d) -> std::string & {
+    s.clear();
+    FormatArgImpl args[1] = {FormatArgImpl(d)};
+    AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+    if (native_traits.hex_float_has_glibc_rounding) {
+      EXPECT_EQ(StrPrint(fmt, d), s);
+    }
+    return s;
+  };
+
+  // 0x1.00018000p+100
+  const double on_boundary_odd = 1267679614447900152596896153600.0;
+  EXPECT_EQ(format("%.0a", on_boundary_odd), "0x1p+100");
+  EXPECT_EQ(format("%.1a", on_boundary_odd), "0x1.0p+100");
+  EXPECT_EQ(format("%.2a", on_boundary_odd), "0x1.00p+100");
+  EXPECT_EQ(format("%.3a", on_boundary_odd), "0x1.000p+100");
+  EXPECT_EQ(format("%.4a", on_boundary_odd), "0x1.0002p+100");  // round
+  EXPECT_EQ(format("%.5a", on_boundary_odd), "0x1.00018p+100");
+  EXPECT_EQ(format("%.6a", on_boundary_odd), "0x1.000180p+100");
+
+  // 0x1.00028000p-2
+  const double on_boundary_even = 0.250009536743164062500;
+  EXPECT_EQ(format("%.0a", on_boundary_even), "0x1p-2");
+  EXPECT_EQ(format("%.1a", on_boundary_even), "0x1.0p-2");
+  EXPECT_EQ(format("%.2a", on_boundary_even), "0x1.00p-2");
+  EXPECT_EQ(format("%.3a", on_boundary_even), "0x1.000p-2");
+  EXPECT_EQ(format("%.4a", on_boundary_even), "0x1.0002p-2");  // no round
+  EXPECT_EQ(format("%.5a", on_boundary_even), "0x1.00028p-2");
+  EXPECT_EQ(format("%.6a", on_boundary_even), "0x1.000280p-2");
+
+  // 0x1.00018001p+1
+  const double slightly_over = 2.00004577683284878730773925781250;
+  EXPECT_EQ(format("%.0a", slightly_over), "0x1p+1");
+  EXPECT_EQ(format("%.1a", slightly_over), "0x1.0p+1");
+  EXPECT_EQ(format("%.2a", slightly_over), "0x1.00p+1");
+  EXPECT_EQ(format("%.3a", slightly_over), "0x1.000p+1");
+  EXPECT_EQ(format("%.4a", slightly_over), "0x1.0002p+1");
+  EXPECT_EQ(format("%.5a", slightly_over), "0x1.00018p+1");
+  EXPECT_EQ(format("%.6a", slightly_over), "0x1.000180p+1");
+
+  // 0x1.00017fffp+0
+  const double slightly_under = 1.000022887950763106346130371093750;
+  EXPECT_EQ(format("%.0a", slightly_under), "0x1p+0");
+  EXPECT_EQ(format("%.1a", slightly_under), "0x1.0p+0");
+  EXPECT_EQ(format("%.2a", slightly_under), "0x1.00p+0");
+  EXPECT_EQ(format("%.3a", slightly_under), "0x1.000p+0");
+  EXPECT_EQ(format("%.4a", slightly_under), "0x1.0001p+0");
+  EXPECT_EQ(format("%.5a", slightly_under), "0x1.00018p+0");
+  EXPECT_EQ(format("%.6a", slightly_under), "0x1.000180p+0");
+  EXPECT_EQ(format("%.7a", slightly_under), "0x1.0001800p+0");
+
+  // 0x1.1b3829ac28058p+3
+  const double hex_value = 8.85060580848964661981881363317370414733886718750;
+  EXPECT_EQ(format("%.0a", hex_value), "0x1p+3");
+  EXPECT_EQ(format("%.1a", hex_value), "0x1.2p+3");
+  EXPECT_EQ(format("%.2a", hex_value), "0x1.1bp+3");
+  EXPECT_EQ(format("%.3a", hex_value), "0x1.1b4p+3");
+  EXPECT_EQ(format("%.4a", hex_value), "0x1.1b38p+3");
+  EXPECT_EQ(format("%.5a", hex_value), "0x1.1b383p+3");
+  EXPECT_EQ(format("%.6a", hex_value), "0x1.1b382ap+3");
+  EXPECT_EQ(format("%.7a", hex_value), "0x1.1b3829bp+3");
+  EXPECT_EQ(format("%.8a", hex_value), "0x1.1b3829acp+3");
+  EXPECT_EQ(format("%.9a", hex_value), "0x1.1b3829ac3p+3");
+  EXPECT_EQ(format("%.10a", hex_value), "0x1.1b3829ac28p+3");
+  EXPECT_EQ(format("%.11a", hex_value), "0x1.1b3829ac280p+3");
+  EXPECT_EQ(format("%.12a", hex_value), "0x1.1b3829ac2806p+3");
+  EXPECT_EQ(format("%.13a", hex_value), "0x1.1b3829ac28058p+3");
+  EXPECT_EQ(format("%.14a", hex_value), "0x1.1b3829ac280580p+3");
+  EXPECT_EQ(format("%.15a", hex_value), "0x1.1b3829ac2805800p+3");
+  EXPECT_EQ(format("%.16a", hex_value), "0x1.1b3829ac28058000p+3");
+  EXPECT_EQ(format("%.17a", hex_value), "0x1.1b3829ac280580000p+3");
+  EXPECT_EQ(format("%.18a", hex_value), "0x1.1b3829ac2805800000p+3");
+  EXPECT_EQ(format("%.19a", hex_value), "0x1.1b3829ac28058000000p+3");
+  EXPECT_EQ(format("%.20a", hex_value), "0x1.1b3829ac280580000000p+3");
+  EXPECT_EQ(format("%.21a", hex_value), "0x1.1b3829ac2805800000000p+3");
+
+  // 0x1.0818283848586p+3
+  const double hex_value2 = 8.2529488658208371987257123691961169242858886718750;
+  EXPECT_EQ(format("%.0a", hex_value2), "0x1p+3");
+  EXPECT_EQ(format("%.1a", hex_value2), "0x1.1p+3");
+  EXPECT_EQ(format("%.2a", hex_value2), "0x1.08p+3");
+  EXPECT_EQ(format("%.3a", hex_value2), "0x1.082p+3");
+  EXPECT_EQ(format("%.4a", hex_value2), "0x1.0818p+3");
+  EXPECT_EQ(format("%.5a", hex_value2), "0x1.08183p+3");
+  EXPECT_EQ(format("%.6a", hex_value2), "0x1.081828p+3");
+  EXPECT_EQ(format("%.7a", hex_value2), "0x1.0818284p+3");
+  EXPECT_EQ(format("%.8a", hex_value2), "0x1.08182838p+3");
+  EXPECT_EQ(format("%.9a", hex_value2), "0x1.081828385p+3");
+  EXPECT_EQ(format("%.10a", hex_value2), "0x1.0818283848p+3");
+  EXPECT_EQ(format("%.11a", hex_value2), "0x1.08182838486p+3");
+  EXPECT_EQ(format("%.12a", hex_value2), "0x1.081828384858p+3");
+  EXPECT_EQ(format("%.13a", hex_value2), "0x1.0818283848586p+3");
+  EXPECT_EQ(format("%.14a", hex_value2), "0x1.08182838485860p+3");
+  EXPECT_EQ(format("%.15a", hex_value2), "0x1.081828384858600p+3");
+  EXPECT_EQ(format("%.16a", hex_value2), "0x1.0818283848586000p+3");
+  EXPECT_EQ(format("%.17a", hex_value2), "0x1.08182838485860000p+3");
+  EXPECT_EQ(format("%.18a", hex_value2), "0x1.081828384858600000p+3");
+  EXPECT_EQ(format("%.19a", hex_value2), "0x1.0818283848586000000p+3");
+  EXPECT_EQ(format("%.20a", hex_value2), "0x1.08182838485860000000p+3");
+  EXPECT_EQ(format("%.21a", hex_value2), "0x1.081828384858600000000p+3");
+}
+
+TEST_F(FormatConvertTest, LongDoubleRoundA) {
+  if (std::numeric_limits<long double>::digits % 4 != 0) {
+    // This test doesn't really make sense to run on platforms where a long
+    // double has a different mantissa size (mod 4) than Prod, since then the
+    // leading digit will be formatted differently.
+    return;
+  }
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+  std::string s;
+  const auto format = [&](const char *fmt, long double d) -> std::string & {
+    s.clear();
+    FormatArgImpl args[1] = {FormatArgImpl(d)};
+    AppendPack(&s, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+    if (native_traits.hex_float_has_glibc_rounding &&
+        native_traits.hex_float_optimizes_leading_digit_bit_count) {
+      EXPECT_EQ(StrPrint(fmt, d), s);
+    }
+    return s;
+  };
+
+  // 0x8.8p+4
+  const long double on_boundary_even = 136.0;
+  EXPECT_EQ(format("%.0La", on_boundary_even), "0x8p+4");
+  EXPECT_EQ(format("%.1La", on_boundary_even), "0x8.8p+4");
+  EXPECT_EQ(format("%.2La", on_boundary_even), "0x8.80p+4");
+  EXPECT_EQ(format("%.3La", on_boundary_even), "0x8.800p+4");
+  EXPECT_EQ(format("%.4La", on_boundary_even), "0x8.8000p+4");
+  EXPECT_EQ(format("%.5La", on_boundary_even), "0x8.80000p+4");
+  EXPECT_EQ(format("%.6La", on_boundary_even), "0x8.800000p+4");
+
+  // 0x9.8p+4
+  const long double on_boundary_odd = 152.0;
+  EXPECT_EQ(format("%.0La", on_boundary_odd), "0xap+4");
+  EXPECT_EQ(format("%.1La", on_boundary_odd), "0x9.8p+4");
+  EXPECT_EQ(format("%.2La", on_boundary_odd), "0x9.80p+4");
+  EXPECT_EQ(format("%.3La", on_boundary_odd), "0x9.800p+4");
+  EXPECT_EQ(format("%.4La", on_boundary_odd), "0x9.8000p+4");
+  EXPECT_EQ(format("%.5La", on_boundary_odd), "0x9.80000p+4");
+  EXPECT_EQ(format("%.6La", on_boundary_odd), "0x9.800000p+4");
+
+  // 0x8.80001p+24
+  const long double slightly_over = 142606352.0;
+  EXPECT_EQ(format("%.0La", slightly_over), "0x9p+24");
+  EXPECT_EQ(format("%.1La", slightly_over), "0x8.8p+24");
+  EXPECT_EQ(format("%.2La", slightly_over), "0x8.80p+24");
+  EXPECT_EQ(format("%.3La", slightly_over), "0x8.800p+24");
+  EXPECT_EQ(format("%.4La", slightly_over), "0x8.8000p+24");
+  EXPECT_EQ(format("%.5La", slightly_over), "0x8.80001p+24");
+  EXPECT_EQ(format("%.6La", slightly_over), "0x8.800010p+24");
+
+  // 0x8.7ffffp+24
+  const long double slightly_under = 142606320.0;
+  EXPECT_EQ(format("%.0La", slightly_under), "0x8p+24");
+  EXPECT_EQ(format("%.1La", slightly_under), "0x8.8p+24");
+  EXPECT_EQ(format("%.2La", slightly_under), "0x8.80p+24");
+  EXPECT_EQ(format("%.3La", slightly_under), "0x8.800p+24");
+  EXPECT_EQ(format("%.4La", slightly_under), "0x8.8000p+24");
+  EXPECT_EQ(format("%.5La", slightly_under), "0x8.7ffffp+24");
+  EXPECT_EQ(format("%.6La", slightly_under), "0x8.7ffff0p+24");
+  EXPECT_EQ(format("%.7La", slightly_under), "0x8.7ffff00p+24");
+
+  // 0xc.0828384858688000p+128
+  const long double eights = 4094231060438608800781871108094404067328.0;
+  EXPECT_EQ(format("%.0La", eights), "0xcp+128");
+  EXPECT_EQ(format("%.1La", eights), "0xc.1p+128");
+  EXPECT_EQ(format("%.2La", eights), "0xc.08p+128");
+  EXPECT_EQ(format("%.3La", eights), "0xc.083p+128");
+  EXPECT_EQ(format("%.4La", eights), "0xc.0828p+128");
+  EXPECT_EQ(format("%.5La", eights), "0xc.08284p+128");
+  EXPECT_EQ(format("%.6La", eights), "0xc.082838p+128");
+  EXPECT_EQ(format("%.7La", eights), "0xc.0828385p+128");
+  EXPECT_EQ(format("%.8La", eights), "0xc.08283848p+128");
+  EXPECT_EQ(format("%.9La", eights), "0xc.082838486p+128");
+  EXPECT_EQ(format("%.10La", eights), "0xc.0828384858p+128");
+  EXPECT_EQ(format("%.11La", eights), "0xc.08283848587p+128");
+  EXPECT_EQ(format("%.12La", eights), "0xc.082838485868p+128");
+  EXPECT_EQ(format("%.13La", eights), "0xc.0828384858688p+128");
+  EXPECT_EQ(format("%.14La", eights), "0xc.08283848586880p+128");
+  EXPECT_EQ(format("%.15La", eights), "0xc.082838485868800p+128");
+  EXPECT_EQ(format("%.16La", eights), "0xc.0828384858688000p+128");
+}
+
 // We don't actually store the results. This is just to exercise the rest of the
 // machinery.
 struct NullSink {
@@ -735,6 +1060,7 @@
   // implementation against the native one there.
   return;
 #endif  // _MSC_VER
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
   const char *const kFormats[] = {"%",    "%.3", "%8.5", "%9",  "%.5000",
                                   "%.60", "%+",  "% ",   "%-10"};
 
@@ -777,12 +1103,20 @@
                    'e', 'E'}) {
       std::string fmt_str = std::string(fmt) + 'L' + f;
 
-      if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F') {
+      if (fmt == absl::string_view("%.5000") && f != 'f' && f != 'F' &&
+          f != 'a' && f != 'A') {
         // This particular test takes way too long with snprintf.
         // Disable for the case we are not implementing natively.
         continue;
       }
 
+      if (f == 'a' || f == 'A') {
+        if (!native_traits.hex_float_has_glibc_rounding ||
+            !native_traits.hex_float_optimizes_leading_digit_bit_count) {
+          continue;
+        }
+      }
+
       for (auto d : doubles) {
         FormatArgImpl arg(d);
         UntypedFormatSpecImpl format(fmt_str);
@@ -797,7 +1131,8 @@
   }
 }
 
-TEST_F(FormatConvertTest, IntAsFloat) {
+TEST_F(FormatConvertTest, IntAsDouble) {
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
   const int kMin = std::numeric_limits<int>::min();
   const int kMax = std::numeric_limits<int>::max();
   const int ia[] = {
@@ -813,14 +1148,16 @@
       const char *fmt;
     };
     const double dx = static_cast<double>(fx);
-    const Expectation kExpect[] = {
-      { __LINE__, StrPrint("%f", dx), "%f" },
-      { __LINE__, StrPrint("%12f", dx), "%12f" },
-      { __LINE__, StrPrint("%.12f", dx), "%.12f" },
-      { __LINE__, StrPrint("%12a", dx), "%12a" },
-      { __LINE__, StrPrint("%.12a", dx), "%.12a" },
+    std::vector<Expectation> expect = {
+        {__LINE__, StrPrint("%f", dx), "%f"},
+        {__LINE__, StrPrint("%12f", dx), "%12f"},
+        {__LINE__, StrPrint("%.12f", dx), "%.12f"},
+        {__LINE__, StrPrint("%.12a", dx), "%.12a"},
     };
-    for (const Expectation &e : kExpect) {
+    if (native_traits.hex_float_uses_minimal_precision_when_not_specified) {
+      expect.push_back({__LINE__, StrPrint("%12a", dx), "%12a"});
+    }
+    for (const Expectation &e : expect) {
       SCOPED_TRACE(e.line);
       SCOPED_TRACE(e.fmt);
       UntypedFormatSpecImpl format(e.fmt);
@@ -865,6 +1202,25 @@
   EXPECT_TRUE(FormatFails("%*d", ""));
 }
 
+// Sanity check to make sure that we are testing what we think we're testing on
+// e.g. the x86_64+glibc platform.
+TEST_F(FormatConvertTest, GlibcHasCorrectTraits) {
+#if !defined(__GLIBC__) || !defined(__x86_64__)
+  return;
+#endif
+  const NativePrintfTraits &native_traits = VerifyNativeImplementation();
+  // If one of the following tests break then it is either because the above PP
+  // macro guards failed to exclude a new platform (likely) or because something
+  // has changed in the implemention of glibc sprintf float formatting behavior.
+  // If the latter, then the code that computes these flags needs to be
+  // revisited and/or possibly the StrFormat implementation.
+  EXPECT_TRUE(native_traits.hex_float_has_glibc_rounding);
+  EXPECT_TRUE(native_traits.hex_float_prefers_denormal_repr);
+  EXPECT_TRUE(
+      native_traits.hex_float_uses_minimal_precision_when_not_specified);
+  EXPECT_TRUE(native_traits.hex_float_optimizes_leading_digit_bit_count);
+}
+
 }  // namespace
 }  // namespace str_format_internal
 ABSL_NAMESPACE_END
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
index 10e4695..cafa479 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
@@ -15,6 +15,7 @@
 #include "absl/functional/function_ref.h"
 #include "absl/meta/type_traits.h"
 #include "absl/numeric/int128.h"
+#include "absl/strings/numbers.h"
 #include "absl/types/optional.h"
 #include "absl/types/span.h"
 
@@ -453,26 +454,31 @@
   }
 }
 
-void FinalPrint(absl::string_view data, int trailing_zeros,
-                const FormatState &state) {
+void FinalPrint(const FormatState &state, absl::string_view data,
+                int padding_offset, int trailing_zeros,
+                absl::string_view data_postfix) {
   if (state.conv.width() < 0) {
     // No width specified. Fast-path.
     if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
     state.sink->Append(data);
     state.sink->Append(trailing_zeros, '0');
+    state.sink->Append(data_postfix);
     return;
   }
 
-  auto padding =
-      ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) + data.size() +
-                              static_cast<size_t>(trailing_zeros),
-                          state);
+  auto padding = ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) +
+                                         data.size() + data_postfix.size() +
+                                         static_cast<size_t>(trailing_zeros),
+                                     state);
 
   state.sink->Append(padding.left_spaces, ' ');
   if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+  // Padding in general needs to be inserted somewhere in the middle of `data`.
+  state.sink->Append(data.substr(0, padding_offset));
   state.sink->Append(padding.zeros, '0');
-  state.sink->Append(data);
+  state.sink->Append(data.substr(padding_offset));
   state.sink->Append(trailing_zeros, '0');
+  state.sink->Append(data_postfix);
   state.sink->Append(padding.right_spaces, ' ');
 }
 
@@ -525,10 +531,11 @@
   // In `alt` mode (flag #) we keep the `.` even if there are no fractional
   // digits. In non-alt mode, we strip it.
   if (!state.ShouldPrintDot()) --size;
-  FinalPrint(absl::string_view(integral_digits_start, size),
+  FinalPrint(state, absl::string_view(integral_digits_start, size),
+             /*padding_offset=*/0,
              static_cast<int>(state.precision - (fractional_digits_end -
                                                  fractional_digits_start)),
-             state);
+             /*data_postfix=*/"");
 }
 
 // Slow %f formatter for when the shifted value does not fit in a uint128, and
@@ -655,6 +662,257 @@
   return FormatFFast(mantissa, exp, state);
 }
 
+// Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to
+// bits 4-7.
+template <typename Int>
+uint8_t GetNibble(Int n, int nibble_index) {
+  constexpr Int mask_low_nibble = Int{0xf};
+  int shift = nibble_index * 4;
+  n &= mask_low_nibble << shift;
+  return static_cast<uint8_t>((n >> shift) & 0xf);
+}
+
+// Add one to the given nibble, applying carry to higher nibbles. Returns true
+// if overflow, false otherwise.
+template <typename Int>
+bool IncrementNibble(int nibble_index, Int *n) {
+  constexpr int kShift = sizeof(Int) * 8 - 1;
+  constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+  Int before = *n >> kShift;
+  // Here we essentially want to take the number 1 and move it into the requsted
+  // nibble, then add it to *n to effectively increment the nibble. However,
+  // ASan will complain if we try to shift the 1 beyond the limits of the Int,
+  // i.e., if the nibble_index is out of range. So therefore we check for this
+  // and if we are out of range we just add 0 which leaves *n unchanged, which
+  // seems like the reasonable thing to do in that case.
+  *n +=
+      ((nibble_index * 4 >= sizeof(Int) * 8) ? 0
+                                             : (Int{1} << (nibble_index * 4)));
+  Int after = *n >> kShift;
+  return (before && !after) || (nibble_index >= kNumNibbles);
+}
+
+// Return a mask with 1's in the given nibble and all lower nibbles.
+template <typename Int>
+Int MaskUpToNibbleInclusive(int nibble_index) {
+  constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+  static const Int ones = ~Int{0};
+  return ones >> std::max(0, 4 * (kNumNibbles - nibble_index - 1));
+}
+
+// Return a mask with 1's below the given nibble.
+template <typename Int>
+Int MaskUpToNibbleExclusive(int nibble_index) {
+  return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1);
+}
+
+template <typename Int>
+Int MoveToNibble(uint8_t nibble, int nibble_index) {
+  return Int{nibble} << (4 * nibble_index);
+}
+
+// Given mantissa size, find optimal # of mantissa bits to put in initial digit.
+//
+// In the hex representation we keep a single hex digit to the left of the dot.
+// However, the question as to how many bits of the mantissa should be put into
+// that hex digit in theory is arbitrary, but in practice it is optimal to
+// choose based on the size of the mantissa. E.g., for a `double`, there are 53
+// mantissa bits, so that means that we should put 1 bit to the left of the dot,
+// thereby leaving 52 bits to the right, which is evenly divisible by four and
+// thus all fractional digits represent actual precision. For a `long double`,
+// on the other hand, there are 64 bits of mantissa, thus we can use all four
+// bits for the initial hex digit and still have a number left over (60) that is
+// a multiple of four. Once again, the goal is to have all fractional digits
+// represent real precision.
+template <typename Float>
+constexpr int HexFloatLeadingDigitSizeInBits() {
+  return std::numeric_limits<Float>::digits % 4 > 0
+             ? std::numeric_limits<Float>::digits % 4
+             : 4;
+}
+
+// This function captures the rounding behavior of glibc for hex float
+// representations. E.g. when rounding 0x1.ab800000 to a precision of .2
+// ("%.2a") glibc will round up because it rounds toward the even number (since
+// 0xb is an odd number, it will round up to 0xc). However, when rounding at a
+// point that is not followed by 800000..., it disregards the parity and rounds
+// up if > 8 and rounds down if < 8.
+template <typename Int>
+bool HexFloatNeedsRoundUp(Int mantissa, int final_nibble_displayed,
+                          uint8_t leading) {
+  // If the last nibble (hex digit) to be displayed is the lowest on in the
+  // mantissa then that means that we don't have any further nibbles to inform
+  // rounding, so don't round.
+  if (final_nibble_displayed <= 0) {
+    return false;
+  }
+  int rounding_nibble_idx = final_nibble_displayed - 1;
+  constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+  assert(final_nibble_displayed <= kTotalNibbles);
+  Int mantissa_up_to_rounding_nibble_inclusive =
+      mantissa & MaskUpToNibbleInclusive<Int>(rounding_nibble_idx);
+  Int eight = MoveToNibble<Int>(8, rounding_nibble_idx);
+  if (mantissa_up_to_rounding_nibble_inclusive != eight) {
+    return mantissa_up_to_rounding_nibble_inclusive > eight;
+  }
+  // Nibble in question == 8.
+  uint8_t round_if_odd = (final_nibble_displayed == kTotalNibbles)
+                             ? leading
+                             : GetNibble(mantissa, final_nibble_displayed);
+  return round_if_odd % 2 == 1;
+}
+
+// Stores values associated with a Float type needed by the FormatA
+// implementation in order to avoid templatizing that function by the Float
+// type.
+struct HexFloatTypeParams {
+  template <typename Float>
+  explicit HexFloatTypeParams(Float)
+      : min_exponent(std::numeric_limits<Float>::min_exponent - 1),
+        leading_digit_size_bits(HexFloatLeadingDigitSizeInBits<Float>()) {
+    assert(leading_digit_size_bits >= 1 && leading_digit_size_bits <= 4);
+  }
+
+  int min_exponent;
+  int leading_digit_size_bits;
+};
+
+// Hex Float Rounding. First check if we need to round; if so, then we do that
+// by manipulating (incrementing) the mantissa, that way we can later print the
+// mantissa digits by iterating through them in the same way regardless of
+// whether a rounding happened.
+template <typename Int>
+void FormatARound(bool precision_specified, const FormatState &state,
+                  uint8_t *leading, Int *mantissa, int *exp) {
+  constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+  // Index of the last nibble that we could display given precision.
+  int final_nibble_displayed =
+      precision_specified ? std::max(0, (kTotalNibbles - state.precision)) : 0;
+  if (HexFloatNeedsRoundUp(*mantissa, final_nibble_displayed, *leading)) {
+    // Need to round up.
+    bool overflow = IncrementNibble(final_nibble_displayed, mantissa);
+    *leading += (overflow ? 1 : 0);
+    if (ABSL_PREDICT_FALSE(*leading > 15)) {
+      // We have overflowed the leading digit. This would mean that we would
+      // need two hex digits to the left of the dot, which is not allowed. So
+      // adjust the mantissa and exponent so that the result is always 1.0eXXX.
+      *leading = 1;
+      *mantissa = 0;
+      *exp += 4;
+    }
+  }
+  // Now that we have handled a possible round-up we can go ahead and zero out
+  // all the nibbles of the mantissa that we won't need.
+  if (precision_specified) {
+    *mantissa &= ~MaskUpToNibbleExclusive<Int>(final_nibble_displayed);
+  }
+}
+
+template <typename Int>
+void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading,
+                      Int *mantissa, int *exp) {
+  constexpr int kIntBits = sizeof(Int) * 8;
+  static const Int kHighIntBit = Int{1} << (kIntBits - 1);
+  const int kLeadDigitBitsCount = float_traits.leading_digit_size_bits;
+  // Normalize mantissa so that highest bit set is in MSB position, unless we
+  // get interrupted by the exponent threshold.
+  while (*mantissa && !(*mantissa & kHighIntBit)) {
+    if (ABSL_PREDICT_FALSE(*exp - 1 < float_traits.min_exponent)) {
+      *mantissa >>= (float_traits.min_exponent - *exp);
+      *exp = float_traits.min_exponent;
+      return;
+    }
+    *mantissa <<= 1;
+    --*exp;
+  }
+  // Extract bits for leading digit then shift them away leaving the
+  // fractional part.
+  *leading =
+      static_cast<uint8_t>(*mantissa >> (kIntBits - kLeadDigitBitsCount));
+  *exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp;
+  *mantissa <<= kLeadDigitBitsCount;
+}
+
+template <typename Int>
+void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp,
+             bool uppercase, const FormatState &state) {
+  // Int properties.
+  constexpr int kIntBits = sizeof(Int) * 8;
+  constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+  // Did the user specify a precision explicitly?
+  const bool precision_specified = state.conv.precision() >= 0;
+
+  // ========== Normalize/Denormalize ==========
+  exp += kIntBits;  // make all digits fractional digits.
+  // This holds the (up to four) bits of leading digit, i.e., the '1' in the
+  // number 0x1.e6fp+2. It's always > 0 unless number is zero or denormal.
+  uint8_t leading = 0;
+  FormatANormalize(float_traits, &leading, &mantissa, &exp);
+
+  // =============== Rounding ==================
+  // Check if we need to round; if so, then we do that by manipulating
+  // (incrementing) the mantissa before beginning to print characters.
+  FormatARound(precision_specified, state, &leading, &mantissa, &exp);
+
+  // ============= Format Result ===============
+  // This buffer holds the "0x1.ab1de3" portion of "0x1.ab1de3pe+2". Compute the
+  // size with long double which is the largest of the floats.
+  constexpr size_t kBufSizeForHexFloatRepr =
+      2                                               // 0x
+      + std::numeric_limits<long double>::digits / 4  // number of hex digits
+      + 1                                             // round up
+      + 1;                                            // "." (dot)
+  char digits_buffer[kBufSizeForHexFloatRepr];
+  char *digits_iter = digits_buffer;
+  const char *const digits =
+      static_cast<const char *>("0123456789ABCDEF0123456789abcdef") +
+      (uppercase ? 0 : 16);
+
+  // =============== Hex Prefix ================
+  *digits_iter++ = '0';
+  *digits_iter++ = uppercase ? 'X' : 'x';
+
+  // ========== Non-Fractional Digit ===========
+  *digits_iter++ = digits[leading];
+
+  // ================== Dot ====================
+  // There are three reasons we might need a dot. Keep in mind that, at this
+  // point, the mantissa holds only the fractional part.
+  if ((precision_specified && state.precision > 0) ||
+      (!precision_specified && mantissa > 0) || state.conv.has_alt_flag()) {
+    *digits_iter++ = '.';
+  }
+
+  // ============ Fractional Digits ============
+  int digits_emitted = 0;
+  while (mantissa > 0) {
+    *digits_iter++ = digits[GetNibble(mantissa, kTotalNibbles - 1)];
+    mantissa <<= 4;
+    ++digits_emitted;
+  }
+  int trailing_zeros =
+      precision_specified ? state.precision - digits_emitted : 0;
+  assert(trailing_zeros >= 0);
+  auto digits_result = string_view(digits_buffer, digits_iter - digits_buffer);
+
+  // =============== Exponent ==================
+  constexpr size_t kBufSizeForExpDecRepr =
+      numbers_internal::kFastToBufferSize  // requred for FastIntToBuffer
+      + 1                                  // 'p' or 'P'
+      + 1;                                 // '+' or '-'
+  char exp_buffer[kBufSizeForExpDecRepr];
+  exp_buffer[0] = uppercase ? 'P' : 'p';
+  exp_buffer[1] = exp >= 0 ? '+' : '-';
+  numbers_internal::FastIntToBuffer(exp < 0 ? -exp : exp, exp_buffer + 2);
+
+  // ============ Assemble Result ==============
+  FinalPrint(state,           //
+             digits_result,   // 0xN.NNN...
+             2,               // offset in `data` to start padding if needed.
+             trailing_zeros,  // num remaining mantissa padding zeros
+             exp_buffer);     // exponent
+}
+
 char *CopyStringTo(absl::string_view v, char *out) {
   std::memcpy(out, v.data(), v.size());
   return out + v.size();
@@ -1103,7 +1361,10 @@
     }
   } else if (c == FormatConversionCharInternal::a ||
              c == FormatConversionCharInternal::A) {
-    return FallbackToSnprintf(v, conv, sink);
+    bool uppercase = (c == FormatConversionCharInternal::A);
+    FormatA(HexFloatTypeParams(Float{}), decomposed.mantissa,
+            decomposed.exponent, uppercase, {sign_char, precision, conv, sink});
+    return true;
   } else {
     return false;
   }
@@ -1131,7 +1392,7 @@
 
 bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
                       FormatSinkImpl *sink) {
-  return FloatToSink(v, conv, sink);
+  return FloatToSink(static_cast<double>(v), conv, sink);
 }
 
 bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
diff --git a/third_party/abseil-cpp/absl/strings/numbers_test.cc b/third_party/abseil-cpp/absl/strings/numbers_test.cc
index 7db85e7..c2f03b63 100644
--- a/third_party/abseil-cpp/absl/strings/numbers_test.cc
+++ b/third_party/abseil-cpp/absl/strings/numbers_test.cc
@@ -359,6 +359,12 @@
   VerifySimpleAtoiGood<std::string::size_type>(42, 42);
 }
 
+TEST(NumbersTest, Atod) {
+  double d;
+  EXPECT_TRUE(absl::SimpleAtod("nan", &d));
+  EXPECT_TRUE(std::isnan(d));
+}
+
 TEST(NumbersTest, Atoenum) {
   enum E01 {
     E01_zero = 0,
diff --git a/third_party/abseil-cpp/absl/strings/str_cat.cc b/third_party/abseil-cpp/absl/strings/str_cat.cc
index d9afe2f..dd5d25b 100644
--- a/third_party/abseil-cpp/absl/strings/str_cat.cc
+++ b/third_party/abseil-cpp/absl/strings/str_cat.cc
@@ -141,12 +141,12 @@
 std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
   std::string result;
   size_t total_size = 0;
-  for (const absl::string_view piece : pieces) total_size += piece.size();
+  for (const absl::string_view& piece : pieces) total_size += piece.size();
   strings_internal::STLStringResizeUninitialized(&result, total_size);
 
   char* const begin = &result[0];
   char* out = begin;
-  for (const absl::string_view piece : pieces) {
+  for (const absl::string_view& piece : pieces) {
     const size_t this_size = piece.size();
     if (this_size != 0) {
       memcpy(out, piece.data(), this_size);
@@ -170,7 +170,7 @@
                   std::initializer_list<absl::string_view> pieces) {
   size_t old_size = dest->size();
   size_t total_size = old_size;
-  for (const absl::string_view piece : pieces) {
+  for (const absl::string_view& piece : pieces) {
     ASSERT_NO_OVERLAP(*dest, piece);
     total_size += piece.size();
   }
@@ -178,7 +178,7 @@
 
   char* const begin = &(*dest)[0];
   char* out = begin + old_size;
-  for (const absl::string_view piece : pieces) {
+  for (const absl::string_view& piece : pieces) {
     const size_t this_size = piece.size();
     if (this_size != 0) {
       memcpy(out, piece.data(), this_size);
diff --git a/third_party/abseil-cpp/absl/strings/string_view.h b/third_party/abseil-cpp/absl/strings/string_view.h
index 7fb03330..8a9db8c3 100644
--- a/third_party/abseil-cpp/absl/strings/string_view.h
+++ b/third_party/abseil-cpp/absl/strings/string_view.h
@@ -586,7 +586,7 @@
 }
 
 // IO Insertion Operator
-ABSL_DLL std::ostream& operator<<(std::ostream& o, string_view piece);
+std::ostream& operator<<(std::ostream& o, string_view piece);
 
 ABSL_NAMESPACE_END
 }  // namespace absl
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h b/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h
index 8ab4391..2228b6e 100644
--- a/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h
+++ b/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h
@@ -78,7 +78,7 @@
   // !t.has_timeout() => Wait(t) will return true.
   static inline bool Wait(KernelTimeout t);
 
-  // White-listed callers.
+  // Permitted callers.
   friend class PerThreadSemTest;
   friend class absl::Mutex;
   friend absl::base_internal::ThreadIdentity* CreateThreadIdentity();
diff --git a/third_party/abseil-cpp/absl/time/time_test.cc b/third_party/abseil-cpp/absl/time/time_test.cc
index 6f89672..b28a99f 100644
--- a/third_party/abseil-cpp/absl/time/time_test.cc
+++ b/third_party/abseil-cpp/absl/time/time_test.cc
@@ -58,8 +58,7 @@
 // timespec ts1, ts2;
 // EXPECT_THAT(ts1, TimespecMatcher(ts2));
 MATCHER_P(TimespecMatcher, ts, "") {
-  if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec)
-    return true;
+  if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec) return true;
   *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} ";
   *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}";
   return false;
@@ -69,8 +68,7 @@
 // timeval tv1, tv2;
 // EXPECT_THAT(tv1, TimevalMatcher(tv2));
 MATCHER_P(TimevalMatcher, tv, "") {
-  if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec)
-    return true;
+  if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec) return true;
   *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} ";
   *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}";
   return false;
@@ -103,7 +101,7 @@
   EXPECT_EQ(a, b);
   EXPECT_EQ(a, c);
   EXPECT_EQ(b, c);
-  b = c;       // Assignment
+  b = c;  // Assignment
   EXPECT_EQ(a, b);
   EXPECT_EQ(a, c);
   EXPECT_EQ(b, c);
@@ -228,6 +226,9 @@
   constexpr absl::Time t = absl::UnixEpoch();  // Any finite time.
   static_assert(t < ifuture, "");
   static_assert(t > ipast, "");
+
+  EXPECT_EQ(ifuture, t + absl::InfiniteDuration());
+  EXPECT_EQ(ipast, t - absl::InfiniteDuration());
 }
 
 TEST(Time, FloorConversion) {
@@ -358,19 +359,21 @@
   const int64_t min_plus_1 = std::numeric_limits<int64_t>::min() + 1;
   EXPECT_EQ(min_plus_1, absl::ToUnixSeconds(absl::FromUnixSeconds(min_plus_1)));
   EXPECT_EQ(std::numeric_limits<int64_t>::min(),
-            absl::ToUnixSeconds(
-                absl::FromUnixSeconds(min_plus_1) - absl::Nanoseconds(1) / 2));
+            absl::ToUnixSeconds(absl::FromUnixSeconds(min_plus_1) -
+                                absl::Nanoseconds(1) / 2));
 
   // Tests flooring near positive infinity.
   EXPECT_EQ(std::numeric_limits<int64_t>::max(),
-            absl::ToUnixSeconds(absl::FromUnixSeconds(
-                std::numeric_limits<int64_t>::max()) + absl::Nanoseconds(1) / 2));
+            absl::ToUnixSeconds(
+                absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()) +
+                absl::Nanoseconds(1) / 2));
   EXPECT_EQ(std::numeric_limits<int64_t>::max(),
             absl::ToUnixSeconds(
                 absl::FromUnixSeconds(std::numeric_limits<int64_t>::max())));
   EXPECT_EQ(std::numeric_limits<int64_t>::max() - 1,
-            absl::ToUnixSeconds(absl::FromUnixSeconds(
-                std::numeric_limits<int64_t>::max()) - absl::Nanoseconds(1) / 2));
+            absl::ToUnixSeconds(
+                absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()) -
+                absl::Nanoseconds(1) / 2));
 }
 
 TEST(Time, RoundtripConversion) {
@@ -1045,15 +1048,15 @@
 
   // Checks how TimeZone::At() saturates on infinities.
   auto ci = utc.At(absl::InfiniteFuture());
-  EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::max(), 12, 31, 23,
-                            59, 59, 0, false);
+  EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59,
+                    0, false);
   EXPECT_EQ(absl::InfiniteDuration(), ci.subsecond);
   EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(ci.cs));
   EXPECT_EQ(365, absl::GetYearDay(ci.cs));
   EXPECT_STREQ("-00", ci.zone_abbr);  // artifact of TimeZone::At()
   ci = utc.At(absl::InfinitePast());
-  EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
-                            0, 0, false);
+  EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0, 0, 0,
+                    false);
   EXPECT_EQ(-absl::InfiniteDuration(), ci.subsecond);
   EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(ci.cs));
   EXPECT_EQ(1, absl::GetYearDay(ci.cs));
@@ -1171,14 +1174,13 @@
   const int kMin = std::numeric_limits<int>::min();
   absl::Time t;
 
-  t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::max(),
-                         kMax, kMax, kMax, kMax, kMax, utc);
+  t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::max(), kMax,
+                         kMax, kMax, kMax, kMax, utc);
   EXPECT_EQ("infinite-future",
             absl::FormatTime(ymdhms, t, utc));  // no overflow
-  t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::min(),
-                         kMin, kMin, kMin, kMin, kMin, utc);
-  EXPECT_EQ("infinite-past",
-            absl::FormatTime(ymdhms, t, utc));  // no overflow
+  t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::min(), kMin,
+                         kMin, kMin, kMin, kMin, utc);
+  EXPECT_EQ("infinite-past", absl::FormatTime(ymdhms, t, utc));  // no overflow
 
   // Check normalization.
   EXPECT_TRUE(absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, utc).normalized);
diff --git a/third_party/abseil-cpp/absl/types/BUILD.bazel b/third_party/abseil-cpp/absl/types/BUILD.bazel
index de71c73..102affa 100644
--- a/third_party/abseil-cpp/absl/types/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/types/BUILD.bazel
@@ -12,7 +12,6 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-#
 
 load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
 load(
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom
index 6a01d28..1409f76a 100644
--- a/third_party/blink/public/mojom/frame/frame.mojom
+++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -578,6 +578,26 @@
   GetSavableResourceLinks() => (GetSavableResourceLinksReply? reply);
 };
 
+// Also implemented in Blink, this interface defines frame-specific methods
+// that will be invoked from the browser process but processed at a higher
+// priority than methods invoked on the LocalFrame interface.
+//
+// Note this interface does not use legacy IPC channels and as such there are
+// no ordering guarantees for messages sent on this interface. This interface is
+// for experimental purposes.
+interface HighPriorityLocalFrame {
+
+  // Instructs the frame to invoke the beforeunload event handler.
+  //
+  // The closure callback is invoked to acknowledge the browser that
+  // the beforeunload event is handled. |proceed| matches the return value
+  // of the frame's beforeunload handler: true if the user decided to proceed
+  // with leaving the page.
+  DispatchBeforeUnload(bool is_reload)
+      => (bool proceed, mojo_base.mojom.TimeTicks before_unload_start_time,
+          mojo_base.mojom.TimeTicks before_unload_end_time);
+};
+
 // Implemented in Browser, this interface defines frame-specific methods that
 // will be invoked from the render process (e.g. blink::RemoteFrame).
 //
diff --git a/third_party/blink/public/platform/task_type.h b/third_party/blink/public/platform/task_type.h
index 3093d1e..35d9d12 100644
--- a/third_party/blink/public/platform/task_type.h
+++ b/third_party/blink/public/platform/task_type.h
@@ -237,6 +237,9 @@
   // Tasks used for find-in-page.
   kInternalFindInPage = 70,
 
+  // Tasks that come in on the HighPriorityLocalFrame interface.
+  kInternalHighPriorityLocalFrame = 71,
+
   ///////////////////////////////////////
   // The following task types are only for thread-local queues.
   ///////////////////////////////////////
@@ -261,7 +264,7 @@
   kWorkerThreadTaskQueueV8 = 47,
   kWorkerThreadTaskQueueCompositor = 48,
 
-  kCount = 71,
+  kCount = 72,
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/animation_input_helpers.cc b/third_party/blink/renderer/core/animation/animation_input_helpers.cc
index 5e3181f..64edd97 100644
--- a/third_party/blink/renderer/core/animation/animation_input_helpers.cc
+++ b/third_party/blink/renderer/core/animation/animation_input_helpers.cc
@@ -248,7 +248,7 @@
   // Fallback to an insecure parsing mode if we weren't provided with a
   // document.
   SecureContextMode secure_context_mode =
-      document ? document->GetSecureContextMode()
+      document ? document->GetExecutionContext()->GetSecureContextMode()
                : SecureContextMode::kInsecureContext;
   const CSSValue* value = CSSParser::ParseSingleValue(
       CSSPropertyID::kTransitionTimingFunction, string,
diff --git a/third_party/blink/renderer/core/animation/animation_sim_test.cc b/third_party/blink/renderer/core/animation/animation_sim_test.cc
index 1e633ee1..fd09fdd 100644
--- a/third_party/blink/renderer/core/animation/animation_sim_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_sim_test.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
 #include "third_party/blink/renderer/core/css/css_test_helpers.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
@@ -59,8 +60,7 @@
 
   // target.animate({'--x': '100%'}, 1000);
   auto* keyframe = MakeGarbageCollected<StringKeyframe>();
-  keyframe->SetCSSPropertyValue("--x", "100%",
-                                GetDocument().GetSecureContextMode(),
+  keyframe->SetCSSPropertyValue("--x", "100%", Window().GetSecureContextMode(),
                                 GetDocument().ElementSheet().Contents());
   StringKeyframeVector keyframes;
   keyframes.push_back(keyframe);
@@ -83,8 +83,7 @@
 
   // target.animate({'--x': '100%'}, 1000);
   keyframe = MakeGarbageCollected<StringKeyframe>();
-  keyframe->SetCSSPropertyValue("--x", "100%",
-                                GetDocument().GetSecureContextMode(),
+  keyframe->SetCSSPropertyValue("--x", "100%", Window().GetSecureContextMode(),
                                 GetDocument().ElementSheet().Contents());
   keyframes.clear();
   keyframes.push_back(std::move(keyframe));
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index c76b836b..d2898e8d 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -254,9 +254,10 @@
                                           const String& value,
                                           double offset = 0) {
     auto* keyframe = MakeGarbageCollected<StringKeyframe>();
-    keyframe->SetCSSPropertyValue(AtomicString(property_name), value,
-                                  GetDocument().GetSecureContextMode(),
-                                  GetDocument().ElementSheet().Contents());
+    keyframe->SetCSSPropertyValue(
+        AtomicString(property_name), value,
+        GetDocument().GetExecutionContext()->GetSecureContextMode(),
+        GetDocument().ElementSheet().Contents());
     keyframe->SetComposite(EffectModel::kCompositeReplace);
     keyframe->SetOffset(offset);
     keyframe->SetEasing(LinearTimingFunction::Shared());
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_interpolation_type.cc
index 64f4ad9..f1caa26 100644
--- a/third_party/blink/renderer/core/animation/css_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_interpolation_type.cc
@@ -291,7 +291,8 @@
             DynamicTo<CSSCustomPropertyDeclaration>(value)) {
       DCHECK(resolved_declaration->Value());
       value = resolved_declaration->Value()->ParseForSyntax(
-          registration_->Syntax(), state.GetDocument().GetSecureContextMode());
+          registration_->Syntax(),
+          state.GetDocument().GetExecutionContext()->GetSecureContextMode());
       if (!value)
         return nullptr;
     }
@@ -339,10 +340,12 @@
     resolved_tokens = declaration.Value();
   }
   const CSSValue* resolved_value =
-      resolved_tokens ? resolved_tokens->ParseForSyntax(
-                            registration_->Syntax(),
-                            state.GetDocument().GetSecureContextMode())
-                      : nullptr;
+      resolved_tokens
+          ? resolved_tokens->ParseForSyntax(registration_->Syntax(),
+                                            state.GetDocument()
+                                                .GetExecutionContext()
+                                                ->GetSecureContextMode())
+          : nullptr;
   if (!resolved_value) {
     return nullptr;
   }
diff --git a/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
index e5b9a9a..61fdbd2 100644
--- a/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_paint_interpolation_type.cc
@@ -21,10 +21,7 @@
 static bool GetColorFromPaint(const SVGPaint& paint, StyleColor& result) {
   if (!paint.IsColor())
     return false;
-  if (paint.HasCurrentColor())
-    result = StyleColor::CurrentColor();
-  else
-    result = paint.GetColor();
+  result = paint.GetColor();
   return true;
 }
 
diff --git a/third_party/blink/renderer/core/animation/effect_input.cc b/third_party/blink/renderer/core/animation/effect_input.cc
index e27f91a..0f8e30f 100644
--- a/third_party/blink/renderer/core/animation/effect_input.cc
+++ b/third_party/blink/renderer/core/animation/effect_input.cc
@@ -93,12 +93,14 @@
   if (css_property != CSSPropertyID::kInvalid) {
     MutableCSSPropertyValueSet::SetResult set_result =
         css_property == CSSPropertyID::kVariable
-            ? keyframe.SetCSSPropertyValue(AtomicString(property), value,
-                                           document.GetSecureContextMode(),
-                                           style_sheet_contents)
-            : keyframe.SetCSSPropertyValue(css_property, value,
-                                           document.GetSecureContextMode(),
-                                           style_sheet_contents);
+            ? keyframe.SetCSSPropertyValue(
+                  AtomicString(property), value,
+                  document.GetExecutionContext()->GetSecureContextMode(),
+                  style_sheet_contents)
+            : keyframe.SetCSSPropertyValue(
+                  css_property, value,
+                  document.GetExecutionContext()->GetSecureContextMode(),
+                  style_sheet_contents);
     if (!set_result.did_parse && execution_context) {
       if (document.GetFrame()) {
         document.GetFrame()->Console().AddMessage(
@@ -116,7 +118,8 @@
                                                                       element);
   if (css_property != CSSPropertyID::kInvalid) {
     keyframe.SetPresentationAttributeValue(
-        CSSProperty::Get(css_property), value, document.GetSecureContextMode(),
+        CSSProperty::Get(css_property), value,
+        document.GetExecutionContext()->GetSecureContextMode(),
         style_sheet_contents);
     return;
   }
diff --git a/third_party/blink/renderer/core/css/computed_style_field_aliases.json5 b/third_party/blink/renderer/core/css/computed_style_field_aliases.json5
index cef592a..f59f92f 100644
--- a/third_party/blink/renderer/core/css/computed_style_field_aliases.json5
+++ b/third_party/blink/renderer/core/css/computed_style_field_aliases.json5
@@ -13,8 +13,8 @@
         {
             "name": "<color>",
             "field_template": "external",
-            "type_name": "Color",
-            "include_paths": ["third_party/blink/renderer/platform/graphics/color.h"],
+            "type_name": "StyleColor",
+            "include_paths": ["third_party/blink/renderer/core/css/style_color.h"],
         }
     ]
 }
diff --git a/third_party/blink/renderer/core/css/css_paint_value.cc b/third_party/blink/renderer/core/css/css_paint_value.cc
index 0a997825..dd113798 100644
--- a/third_party/blink/renderer/core/css/css_paint_value.cc
+++ b/third_party/blink/renderer/core/css/css_paint_value.cc
@@ -210,7 +210,7 @@
   for (wtf_size_t i = 0; i < argument_variable_data_.size(); ++i) {
     // If we are parsing a paint() function, we must be a secure context.
     DCHECK_EQ(SecureContextMode::kSecureContext,
-              document.GetSecureContextMode());
+              document.GetExecutionContext()->GetSecureContextMode());
     const CSSValue* parsed_value = argument_variable_data_[i]->ParseForSyntax(
         input_argument_types[i], SecureContextMode::kSecureContext);
     if (!parsed_value) {
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 7574288..b973a00d 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -4404,8 +4404,8 @@
       inherited: true,
       field_group: "*",
       field_template: "<color>",
-      default_value: "LayoutTheme::TapHighlightColor()",
-      converter: "ConvertColor",
+      default_value: "StyleColor(LayoutTheme::TapHighlightColor())",
+      converter: "ConvertStyleColor",
       affected_by_forced_colors: true,
     },
     {
diff --git a/third_party/blink/renderer/core/css/font_face_set_document.cc b/third_party/blink/renderer/core/css/font_face_set_document.cc
index 7e9604a..d39e8ab1 100644
--- a/third_party/blink/renderer/core/css/font_face_set_document.cc
+++ b/third_party/blink/renderer/core/css/font_face_set_document.cc
@@ -169,7 +169,7 @@
   auto* parsed_style =
       MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLStandardMode);
   CSSParser::ParseValue(parsed_style, CSSPropertyID::kFont, font_string, true,
-                        GetDocument()->GetSecureContextMode());
+                        GetExecutionContext()->GetSecureContextMode());
   if (parsed_style->IsEmpty())
     return false;
 
diff --git a/third_party/blink/renderer/core/css/mathml.css b/third_party/blink/renderer/core/css/mathml.css
index ea75e51..994d94c3 100644
--- a/third_party/blink/renderer/core/css/mathml.css
+++ b/third_party/blink/renderer/core/css/mathml.css
@@ -47,7 +47,7 @@
     outline: auto 1px -webkit-focus-ring-color;
 }
 
-maction, merror, mfrac, mphantom, mrow, mspace, mstyle, msub, msup, msubsup, munder, mover, munderover, msqrt, mroot
+maction, merror, mfrac, mphantom, mrow, mspace, mstyle, msub, msup, msubsup, munder, mover, munderover, msqrt, mroot, mmultiscripts, mprescripts, none
 {
     display: math;
 }
diff --git a/third_party/blink/renderer/core/css/media_values.cc b/third_party/blink/renderer/core/css/media_values.cc
index 5eca5aa..4764298 100644
--- a/third_party/blink/renderer/core/css/media_values.cc
+++ b/third_party/blink/renderer/core/css/media_values.cc
@@ -231,8 +231,25 @@
 }
 
 ScreenSpanning MediaValues::CalculateScreenSpanning(LocalFrame* frame) {
-  // TODO(dlibby): Retrieve info propagated from the host as to our]
-  // screen-spanning state.
+  if (!frame->GetWidgetForLocalRoot())
+    return ScreenSpanning::kNone;
+
+  WebVector<WebRect> window_segments =
+      frame->GetWidgetForLocalRoot()->WindowSegments();
+
+  if (window_segments.size() == 2) {
+    // If there are two segments and the y value of the segments is the same,
+    // we have side-by-side segments which are represented as a single vertical
+    // fold.
+    if (window_segments[0].y == window_segments[1].y)
+      return ScreenSpanning::kSingleFoldVertical;
+
+    // If the x value of the segments is the same, we have stacked segments
+    // which are represented as a single horizontal fold.
+    if (window_segments[0].x == window_segments[1].x)
+      return ScreenSpanning::kSingleFoldHorizontal;
+  }
+
   return ScreenSpanning::kNone;
 }
 
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_context.cc b/third_party/blink/renderer/core/css/parser/css_parser_context.cc
index 5c1292c..fc8ea6f9 100644
--- a/third_party/blink/renderer/core/css/parser/css_parser_context.cc
+++ b/third_party/blink/renderer/core/css/parser/css_parser_context.cc
@@ -129,7 +129,9 @@
               ? document.GetSettings()
                     ->GetUseLegacyBackgroundSizeShorthandBehavior()
               : false,
-          document.GetSecureContextMode(),
+          document.GetExecutionContext()
+              ? document.GetExecutionContext()->GetSecureContextMode()
+              : SecureContextMode::kInsecureContext,
           ContentSecurityPolicy::ShouldBypassMainWorld(
               document.GetExecutionContext())
               ? network::mojom::CSPDisposition::DO_NOT_CHECK
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 18ae465..18dd0fc2 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
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
 #include "third_party/blink/renderer/core/css/parser/css_tokenizer.h"
 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/html/html_html_element.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
@@ -387,7 +388,10 @@
   auto dummy_page_holder = std::make_unique<DummyPageHolder>(IntSize(800, 600));
   Document& document = dummy_page_holder->GetDocument();
   Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage());
-  document.SetSecureContextModeForTesting(SecureContextMode::kSecureContext);
+  dummy_page_holder->GetFrame()
+      .DomWindow()
+      ->GetSecurityContext()
+      .SetSecureContextModeForTesting(SecureContextMode::kSecureContext);
   WebFeature feature = WebFeature::kCSSPaintFunction;
   EXPECT_FALSE(document.IsUseCounted(feature));
   document.documentElement()->setInnerHTML(
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
index 07b8910..e055cc9 100644
--- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -2235,20 +2235,19 @@
     CSSValueList* values = CSSValueList::CreateSpaceSeparated();
     values->Append(
         *MakeGarbageCollected<cssvalue::CSSURIValue>(paint.GetUrl()));
-    if (paint.type == SVG_PAINTTYPE_URI_NONE)
+    if (paint.type == SVG_PAINTTYPE_URI_NONE) {
       values->Append(*CSSIdentifierValue::Create(CSSValueID::kNone));
-    else if (paint.type == SVG_PAINTTYPE_URI_CURRENTCOLOR)
-      values->Append(*cssvalue::CSSColorValue::Create(current_color.Rgb()));
-    else if (paint.type == SVG_PAINTTYPE_URI_RGBCOLOR)
-      values->Append(*cssvalue::CSSColorValue::Create(paint.GetColor().Rgb()));
+    } else if (paint.type == SVG_PAINTTYPE_URI_COLOR) {
+      values->Append(*cssvalue::CSSColorValue::Create(
+          paint.GetColor().Resolve(current_color).Rgb()));
+    }
     return values;
   }
   if (paint.type == SVG_PAINTTYPE_NONE)
     return CSSIdentifierValue::Create(CSSValueID::kNone);
-  if (paint.type == SVG_PAINTTYPE_CURRENTCOLOR)
-    return cssvalue::CSSColorValue::Create(current_color.Rgb());
 
-  return cssvalue::CSSColorValue::Create(paint.GetColor().Rgb());
+  return cssvalue::CSSColorValue::Create(
+      paint.GetColor().Resolve(current_color).Rgb());
 }
 
 CSSValue* ComputedStyleUtils::ValueForSVGResource(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc b/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
index 74da284..11fcb59c 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/custom_property.cc
@@ -119,8 +119,8 @@
     if (registration_) {
       // TODO(andruud): Store CSSParserContext on CSSCustomPropertyDeclaration
       // and use that.
-      const CSSParserContext* context =
-          StrictCSSParserContext(state.GetDocument().GetSecureContextMode());
+      const CSSParserContext* context = StrictCSSParserContext(
+          state.GetDocument().GetExecutionContext()->GetSecureContextMode());
       auto mode = CSSParserLocalContext::VariableMode::kTyped;
       auto local_context = CSSParserLocalContext().WithVariableMode(mode);
       CSSParserTokenRange range = data->TokenRange();
diff --git a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc b/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc
index 8f60d1f9..e04870d 100644
--- a/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/css_variable_resolver.cc
@@ -49,8 +49,8 @@
     CSSParserTokenRange resolved_range(result.tokens);
     resolved_range = resolved_range.MakeSubRange(
         &resolved_range.Peek(first_fallback_token), resolved_range.end());
-    const CSSParserContext* context =
-        StrictCSSParserContext(state_.GetDocument().GetSecureContextMode());
+    const CSSParserContext* context = StrictCSSParserContext(
+        state_.GetDocument().GetExecutionContext()->GetSecureContextMode());
     const bool is_animation_tainted = false;
     if (!registration->Syntax().Parse(resolved_range, *context,
                                       is_animation_tainted))
@@ -110,7 +110,8 @@
   // may already have a CSSValue. If not, we must produce that value now.
   if (!resolved_value && resolved_data) {
     resolved_value = resolved_data->ParseForSyntax(
-        registration->Syntax(), state_.GetDocument().GetSecureContextMode());
+        registration->Syntax(),
+        state_.GetDocument().GetExecutionContext()->GetSecureContextMode());
     if (!resolved_value) {
       // Parsing failed. Set resolved_data to nullptr to indicate that we
       // currently don't have a token stream matching the registered syntax.
@@ -273,7 +274,8 @@
   // a CSSParserContext.
   if (value.ParserContext())
     return value.ParserContext();
-  return StrictCSSParserContext(state_.GetDocument().GetSecureContextMode());
+  return StrictCSSParserContext(
+      state_.GetDocument().GetExecutionContext()->GetSecureContextMode());
 }
 
 bool CSSVariableResolver::ResolveVariableReference(CSSParserTokenRange range,
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
index c448632..3d1e39d 100644
--- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -444,6 +444,8 @@
       if (!style.HasOutOfFlowPosition())
         style.SetIsFlexOrGridOrCustomItem();
     }
+    if (layout_parent_style.IsDisplayFlexibleOrGridBox())
+      style.SetIsFlexOrGridItem();
   }
 
   if (style.Display() == EDisplay::kBlock && !style.IsFloating())
@@ -510,8 +512,6 @@
     style.SetUserModify(EUserModify::kReadOnly);
 
   if (layout_parent_style.IsDisplayFlexibleOrGridBox()) {
-    style.SetFloating(EFloat::kNone);
-
     // We want to count vertical percentage paddings/margins on flex items
     // because our current behavior is different from the spec and we want to
     // gather compatibility data.
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index b9d6ab51..2d312174 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -112,14 +112,6 @@
   return reflection;
 }
 
-Color StyleBuilderConverter::ConvertColor(StyleResolverState& state,
-                                          const CSSValue& value,
-                                          bool for_visited_link) {
-  return state.GetDocument().GetTextLinkColors().ColorFromCSSValue(
-      value, state.Style()->GetCurrentColor(), state.Style()->UsedColorScheme(),
-      for_visited_link);
-}
-
 scoped_refptr<StyleSVGResource> StyleBuilderConverter::ConvertElementReference(
     StyleResolverState& state,
     const CSSValue& value) {
@@ -1538,15 +1530,10 @@
         local_identifier_value->GetValueID() == CSSValueID::kNone) {
       paint.type =
           !paint.resource ? SVG_PAINTTYPE_NONE : SVG_PAINTTYPE_URI_NONE;
-    } else if (local_identifier_value && local_identifier_value->GetValueID() ==
-                                             CSSValueID::kCurrentcolor) {
-      paint.color = state.Style()->GetCurrentColor();
-      paint.type = !paint.resource ? SVG_PAINTTYPE_CURRENTCOLOR
-                                   : SVG_PAINTTYPE_URI_CURRENTCOLOR;
     } else {
-      paint.color = ConvertColor(state, *local_value);
+      paint.color = ConvertStyleColor(state, *local_value);
       paint.type =
-          !paint.resource ? SVG_PAINTTYPE_RGBCOLOR : SVG_PAINTTYPE_URI_RGBCOLOR;
+          !paint.resource ? SVG_PAINTTYPE_COLOR : SVG_PAINTTYPE_URI_COLOR;
     }
   }
   return paint;
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
index 46df18e..3e55cb33 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.h
@@ -99,9 +99,6 @@
  public:
   static scoped_refptr<StyleReflection> ConvertBoxReflect(StyleResolverState&,
                                                           const CSSValue&);
-  static Color ConvertColor(StyleResolverState&,
-                            const CSSValue&,
-                            bool for_visited_link = false);
   template <typename T>
   static T ConvertComputedLength(StyleResolverState&, const CSSValue&);
   static LengthBox ConvertClip(StyleResolverState&, const CSSValue&);
diff --git a/third_party/blink/renderer/core/css/resolver/style_cascade.cc b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
index 34072e7..a6f40c4a 100644
--- a/third_party/blink/renderer/core/css/resolver/style_cascade.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_cascade.cc
@@ -845,7 +845,8 @@
   // CSSParserContext. (CSSUnparsedValue violates this).
   if (value.ParserContext())
     return value.ParserContext();
-  return StrictCSSParserContext(state_.GetDocument().GetSecureContextMode());
+  return StrictCSSParserContext(
+      state_.GetDocument().GetExecutionContext()->GetSecureContextMode());
 }
 
 bool StyleCascade::HasFontSizeDependency(const CustomProperty& property,
@@ -863,7 +864,8 @@
                                     CSSParserTokenRange range) const {
   if (!property.IsRegistered())
     return true;
-  auto context_mode = state_.GetDocument().GetSecureContextMode();
+  auto context_mode =
+      state_.GetDocument().GetExecutionContext()->GetSecureContextMode();
   auto var_mode = CSSParserLocalContext::VariableMode::kTyped;
   auto* context = StrictCSSParserContext(context_mode);
   auto local_context = CSSParserLocalContext().WithVariableMode(var_mode);
diff --git a/third_party/blink/renderer/core/css/style_environment_variables.cc b/third_party/blink/renderer/core/css/style_environment_variables.cc
index 39cb5693..d1e3e8e 100644
--- a/third_party/blink/renderer/core/css/style_environment_variables.cc
+++ b/third_party/blink/renderer/core/css/style_environment_variables.cc
@@ -87,6 +87,24 @@
     case UADefinedVariable::kKeyboardInsetRight:
       DCHECK(RuntimeEnabledFeatures::VirtualKeyboardEnabled());
       return "keyboard-inset-right";
+    case UADefinedVariable::kFoldTop:
+      DCHECK(RuntimeEnabledFeatures::CSSFoldablesEnabled());
+      return "fold-top";
+    case UADefinedVariable::kFoldRight:
+      DCHECK(RuntimeEnabledFeatures::CSSFoldablesEnabled());
+      return "fold-right";
+    case UADefinedVariable::kFoldBottom:
+      DCHECK(RuntimeEnabledFeatures::CSSFoldablesEnabled());
+      return "fold-bottom";
+    case UADefinedVariable::kFoldLeft:
+      DCHECK(RuntimeEnabledFeatures::CSSFoldablesEnabled());
+      return "fold-left";
+    case UADefinedVariable::kFoldWidth:
+      DCHECK(RuntimeEnabledFeatures::CSSFoldablesEnabled());
+      return "fold-width";
+    case UADefinedVariable::kFoldHeight:
+      DCHECK(RuntimeEnabledFeatures::CSSFoldablesEnabled());
+      return "fold-height";
     default:
       break;
   }
@@ -169,6 +187,10 @@
   parent_ = nullptr;
 }
 
+String StyleEnvironmentVariables::FormatPx(int value) {
+  return String::Format("%dpx", value);
+}
+
 void StyleEnvironmentVariables::ClearForTesting() {
   data_.clear();
 
diff --git a/third_party/blink/renderer/core/css/style_environment_variables.h b/third_party/blink/renderer/core/css/style_environment_variables.h
index 4a3e2b9..98368527 100644
--- a/third_party/blink/renderer/core/css/style_environment_variables.h
+++ b/third_party/blink/renderer/core/css/style_environment_variables.h
@@ -35,6 +35,17 @@
   kKeyboardInsetLeft,
   kKeyboardInsetBottom,
   kKeyboardInsetRight,
+
+  // The fold environment variables define a rectangle that is splitting the
+  // layout viewport.
+  // Explainers:
+  // https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/Foldables/explainer.md
+  kFoldTop,
+  kFoldRight,
+  kFoldBottom,
+  kFoldLeft,
+  kFoldWidth,
+  kFoldHeight,
 };
 
 // StyleEnvironmentVariables stores user agent and user defined CSS environment
@@ -72,6 +83,10 @@
   // Detach |this| from |parent|.
   void DetachFromParent();
 
+  // Stringify |value| and append 'px'. Helper for setting variables that are
+  // CSS lengths.
+  static String FormatPx(int value);
+
  protected:
   friend class StyleEnvironmentVariablesTest;
 
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 48983b6..1df122e 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -988,18 +988,6 @@
   return GetSecurityContext().GetSecurityOrigin();
 }
 
-ContentSecurityPolicy* Document::GetContentSecurityPolicy() const {
-  return GetSecurityContext().GetContentSecurityPolicy();
-}
-
-SecureContextMode Document::GetSecureContextMode() const {
-  return GetSecurityContext().GetSecureContextMode();
-}
-
-void Document::SetSecureContextModeForTesting(SecureContextMode mode) {
-  GetSecurityContext().SetSecureContextModeForTesting(mode);
-}
-
 String Document::addressSpaceForBindings(ScriptState* script_state) const {
   // "public" is the lowest-privilege value.
   if (!script_state->ContextIsValid())
@@ -3461,7 +3449,7 @@
     // the ones contained in the CSP.
     GetSecurityContext().ApplySandboxFlags(csp->GetSandboxMask());
     GetSecurityContext().SetContentSecurityPolicy(csp);
-    GetContentSecurityPolicy()->BindToDelegate(
+    GetExecutionContext()->GetContentSecurityPolicy()->BindToDelegate(
         GetExecutionContext()->GetContentSecurityPolicyDelegate());
     // Clear the hash fragment from the inherited URL to prevent a
     // scroll-into-view for any document.open()'d frame.
@@ -4523,7 +4511,8 @@
       if (!value.IsNull())
         target = &value;
     }
-    if (GetContentSecurityPolicy()->IsActive()) {
+    if (GetExecutionContext() &&
+        GetExecutionContext()->GetContentSecurityPolicy()->IsActive()) {
       UseCounter::Count(*this,
                         WebFeature::kContentSecurityPolicyWithBaseElement);
     }
@@ -4554,8 +4543,9 @@
 
   if (base_element_url != base_element_url_ &&
       !base_element_url.ProtocolIsData() &&
-      !base_element_url.ProtocolIsJavaScript() &&
-      GetContentSecurityPolicy()->AllowBaseURI(base_element_url)) {
+      !base_element_url.ProtocolIsJavaScript() && GetExecutionContext() &&
+      GetExecutionContext()->GetContentSecurityPolicy()->AllowBaseURI(
+          base_element_url)) {
     base_element_url_ = base_element_url;
     UpdateBaseURL();
   }
@@ -7138,12 +7128,6 @@
   GetSecurityContext().SetAddressSpace(initializer.GetIPAddressSpace());
 }
 
-void Document::BindContentSecurityPolicy() {
-  DCHECK(!GetContentSecurityPolicy()->IsBound());
-  GetContentSecurityPolicy()->BindToDelegate(
-      GetExecutionContext()->GetContentSecurityPolicyDelegate());
-}
-
 bool Document::AllowInlineEventHandler(Node* node,
                                        EventListener* listener,
                                        const String& context_url,
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 16f88a1..4fc6c542 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -336,12 +336,6 @@
 
   // Helpers for getting state off of SecurityContext.
   const SecurityOrigin* GetSecurityOrigin() const;
-  SecurityOrigin* GetMutableSecurityOrigin();
-  ContentSecurityPolicy* GetContentSecurityPolicy() const;
-  network::mojom::blink::WebSandboxFlags GetSandboxFlags() const;
-  bool IsSandboxed(network::mojom::blink::WebSandboxFlags mask) const;
-  SecureContextMode GetSecureContextMode() const;
-  void SetSecureContextModeForTesting(SecureContextMode);
 
   String addressSpaceForBindings(ScriptState*) const;
 
@@ -1583,11 +1577,6 @@
   bool IsAnimatedPropertyCounted(CSSPropertyID property) const;
   void ClearUseCounterForTesting(mojom::WebFeature);
 
-  // Bind Content Security Policy to this document. This will cause the
-  // CSP to resolve the 'self' attribute and all policies will then be
-  // applied to this document.
-  void BindContentSecurityPolicy();
-
   void UpdateForcedColors();
   bool InForcedColorsMode() const;
   bool InDarkMode();
diff --git a/third_party/blink/renderer/core/dom/document_init.cc b/third_party/blink/renderer/core/dom/document_init.cc
index fb6666ce..339648d 100644
--- a/third_party/blink/renderer/core/dom/document_init.cc
+++ b/third_party/blink/renderer/core/dom/document_init.cc
@@ -93,7 +93,6 @@
   DCHECK(!for_test_);
   for_test_ = true;
 #endif
-  content_security_policy_ = MakeGarbageCollected<ContentSecurityPolicy>();
   return *this;
 }
 
@@ -126,9 +125,9 @@
 }
 
 network::mojom::blink::WebSandboxFlags DocumentInit::GetSandboxFlags() const {
-  DCHECK(content_security_policy_);
-  network::mojom::blink::WebSandboxFlags flags =
-      sandbox_flags_ | content_security_policy_->GetSandboxMask();
+  network::mojom::blink::WebSandboxFlags flags = sandbox_flags_;
+  if (content_security_policy_)
+    flags |= content_security_policy_->GetSandboxMask();
   if (DocumentLoader* loader = TreeRootDocumentLoader())
     flags |= loader->GetFrame()->Loader().EffectiveSandboxFlags();
   return flags;
@@ -279,9 +278,6 @@
   DCHECK(!for_test_);
 #endif
   execution_context_ = execution_context;
-  content_security_policy_ = MakeGarbageCollected<ContentSecurityPolicy>();
-  content_security_policy_->CopyStateFrom(
-      execution_context_->GetContentSecurityPolicy());
   return *this;
 }
 
@@ -496,7 +492,6 @@
 }
 
 ContentSecurityPolicy* DocumentInit::GetContentSecurityPolicy() const {
-  DCHECK(content_security_policy_);
   return content_security_policy_;
 }
 
diff --git a/third_party/blink/renderer/core/dom/document_lifecycle.cc b/third_party/blink/renderer/core/dom/document_lifecycle.cc
index f472e18..a4710c5 100644
--- a/third_party/blink/renderer/core/dom/document_lifecycle.cc
+++ b/third_party/blink/renderer/core/dom/document_lifecycle.cc
@@ -137,7 +137,7 @@
       if (next_state == kLayoutClean)
         return true;
       if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-          next_state == kInCompositingUpdate)
+          next_state == kInCompositingInputsUpdate)
         return true;
       if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
           next_state == kInPrePaint)
@@ -160,6 +160,9 @@
       if (next_state == kLayoutClean)
         return true;
       if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+          next_state == kInCompositingInputsUpdate)
+        return true;
+      if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
           next_state == kInCompositingUpdate)
         return true;
       if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
@@ -203,6 +206,9 @@
       if (next_state == kInAccessibility)
         return true;
       if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+          next_state == kInCompositingInputsUpdate)
+        return true;
+      if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
           next_state == kInCompositingUpdate)
         return true;
       if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
@@ -215,18 +221,23 @@
       break;
     case kAccessibilityClean:
       if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+          next_state == kInCompositingInputsUpdate)
+        return true;
+      if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
           next_state == kInCompositingUpdate)
         return true;
       if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
           next_state == kInPrePaint)
         return true;
       break;
+    case kInCompositingInputsUpdate:
+      DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
+      return next_state == kCompositingInputsClean;
     case kInCompositingUpdate:
       DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
       // Once we are in the compositing update, we can either just clean the
       // inputs or do the whole of compositing.
-      return next_state == kCompositingInputsClean ||
-             next_state == kCompositingClean;
+      return next_state == kCompositingClean;
     case kCompositingInputsClean:
       DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
       // We can return to style re-calc, layout, or the start of compositing.
@@ -234,6 +245,8 @@
         return true;
       if (next_state == kInPreLayout)
         return true;
+      if (next_state == kInCompositingInputsUpdate)
+        return true;
       if (next_state == kInCompositingUpdate)
         return true;
       if (next_state == kInAccessibility)
@@ -248,6 +261,8 @@
         return true;
       if (next_state == kInPreLayout)
         return true;
+      if (next_state == kInCompositingInputsUpdate)
+        return true;
       if (next_state == kInCompositingUpdate)
         return true;
       if (next_state == kInPrePaint)
@@ -267,6 +282,9 @@
       if (next_state == kInPreLayout)
         return true;
       if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+          next_state == kInCompositingInputsUpdate)
+        return true;
+      if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
           next_state == kInCompositingUpdate)
         return true;
       if (next_state == kInPrePaint)
@@ -284,6 +302,9 @@
       if (next_state == kInPreLayout)
         return true;
       if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
+          next_state == kInCompositingInputsUpdate)
+        return true;
+      if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
           next_state == kInCompositingUpdate)
         return true;
       if (next_state == kInPrePaint)
@@ -337,6 +358,7 @@
     DEBUG_STRING_CASE(kLayoutClean);
     DEBUG_STRING_CASE(kInAccessibility);
     DEBUG_STRING_CASE(kAccessibilityClean);
+    DEBUG_STRING_CASE(kInCompositingInputsUpdate);
     DEBUG_STRING_CASE(kInCompositingUpdate);
     DEBUG_STRING_CASE(kCompositingInputsClean);
     DEBUG_STRING_CASE(kCompositingClean);
diff --git a/third_party/blink/renderer/core/dom/document_lifecycle.h b/third_party/blink/renderer/core/dom/document_lifecycle.h
index a590ce09..e665c7f7 100644
--- a/third_party/blink/renderer/core/dom/document_lifecycle.h
+++ b/third_party/blink/renderer/core/dom/document_lifecycle.h
@@ -71,8 +71,9 @@
     kInAccessibility,
     kAccessibilityClean,
 
-    kInCompositingUpdate,
+    kInCompositingInputsUpdate,
     kCompositingInputsClean,
+    kInCompositingUpdate,
     kCompositingClean,
 
     // In InPrePaint step, any data needed by painting are prepared.
@@ -270,7 +271,8 @@
   // FIXME: We should not allow mutations in InPreLayout or AfterPerformLayout
   // either, but we need to fix MediaList listeners and plugins first.
   return state_ != kInStyleRecalc && state_ != kInPerformLayout &&
-         state_ != kInCompositingUpdate && state_ != kInPrePaint &&
+         state_ != kInCompositingUpdate &&
+         state_ != kInCompositingInputsUpdate && state_ != kInPrePaint &&
          state_ != kInPaint;
 }
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index d43e2a8..c8db7e6 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -305,7 +305,8 @@
   }
   if (!style.IsOverflowVisible())
     return node.GetDocument().ViewportDefiningElement() != &node;
-  if (style.HasOutOfFlowPosition() || style.IsFloating() ||
+  if (style.HasOutOfFlowPosition() ||
+      (style.IsFloating() && !style.IsFlexOrGridItem()) ||
       style.ContainsPaint() || style.ContainsLayout() ||
       style.SpecifiesColumns())
     return true;
@@ -4768,8 +4769,11 @@
     return;
   if (!InActiveDocument())
     return;
-  if (GetDocument().GetContentSecurityPolicy()->HasHeaderDeliveredPolicy())
+  if (GetExecutionContext()
+          ->GetContentSecurityPolicy()
+          ->HasHeaderDeliveredPolicy()) {
     setAttribute(html_names::kNonceAttr, g_empty_atom);
+  }
 }
 
 ElementIntersectionObserverData* Element::IntersectionObserverData() const {
@@ -6142,9 +6146,12 @@
   } else {
     DCHECK(inline_style->IsMutable());
     static_cast<MutableCSSPropertyValueSet*>(inline_style.Get())
-        ->ParseDeclarationList(new_style_string,
-                               GetDocument().GetSecureContextMode(),
-                               GetDocument().ElementSheet().Contents());
+        ->ParseDeclarationList(
+            new_style_string,
+            GetExecutionContext()
+                ? GetExecutionContext()->GetSecureContextMode()
+                : SecureContextMode::kInsecureContext,
+            GetDocument().ElementSheet().Contents());
   }
 }
 
@@ -6230,11 +6237,14 @@
                                      const String& value,
                                      bool important) {
   DCHECK(IsStyledElement());
-  bool did_change = EnsureMutableInlineStyle()
-                        .SetProperty(property_id, value, important,
-                                     GetDocument().GetSecureContextMode(),
-                                     GetDocument().ElementSheet().Contents())
-                        .did_change;
+  bool did_change =
+      EnsureMutableInlineStyle()
+          .SetProperty(property_id, value, important,
+                       GetExecutionContext()
+                           ? GetExecutionContext()->GetSecureContextMode()
+                           : SecureContextMode::kInsecureContext,
+                       GetDocument().ElementSheet().Contents())
+          .did_change;
   if (did_change)
     InlineStyleChanged();
   return did_change;
@@ -6311,9 +6321,11 @@
     CSSPropertyID property_id,
     const String& value) {
   DCHECK(IsStyledElement());
-  Document& document = GetDocument();
-  style->SetProperty(property_id, value, false, document.GetSecureContextMode(),
-                     document.ElementSheet().Contents());
+  style->SetProperty(property_id, value, false,
+                     GetExecutionContext()
+                         ? GetExecutionContext()->GetSecureContextMode()
+                         : SecureContextMode::kInsecureContext,
+                     GetDocument().ElementSheet().Contents());
 }
 
 void Element::AddPropertyToPresentationAttributeStyle(
diff --git a/third_party/blink/renderer/core/editing/commands/apply_style_command.cc b/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
index e4f9e69..151283c 100644
--- a/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/apply_style_command.cc
@@ -787,7 +787,7 @@
     if (embedding_remove_end != remove_start || embedding_remove_end != end) {
       style_without_embedding = style->Copy();
       embedding_style = style_without_embedding->ExtractAndRemoveTextDirection(
-          GetDocument().GetSecureContextMode());
+          GetDocument().GetExecutionContext()->GetSecureContextMode());
 
       if (ComparePositions(embedding_remove_start, embedding_remove_end) <= 0) {
         RemoveInlineStyle(
@@ -858,7 +858,7 @@
         style_without_embedding = style->Copy();
         embedding_style =
             style_without_embedding->ExtractAndRemoveTextDirection(
-                GetDocument().GetSecureContextMode());
+                GetDocument().GetExecutionContext()->GetSecureContextMode());
       }
       FixRangeAndApplyInlineStyle(embedding_style, embedding_apply_start,
                                   embedding_apply_end, editing_state);
diff --git a/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc b/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc
index 7732a82..93ff98d 100644
--- a/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc
+++ b/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/selection_template.h"
 #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 
@@ -95,7 +96,7 @@
       MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode);
   style->SetProperty(CSSPropertyID::kWebkitFontSizeDelta, "3",
                      /* important */ false,
-                     GetDocument().GetSecureContextMode());
+                     GetFrame().DomWindow()->GetSecureContextMode());
   MakeGarbageCollected<ApplyStyleCommand>(
       GetDocument(), MakeGarbageCollected<EditingStyle>(style),
       InputEvent::InputType::kNone)
diff --git a/third_party/blink/renderer/core/editing/commands/editing_commands_utilities.cc b/third_party/blink/renderer/core/editing/commands/editing_commands_utilities.cc
index 4a71147d..754d5c86 100644
--- a/third_party/blink/renderer/core/editing/commands/editing_commands_utilities.cc
+++ b/third_party/blink/renderer/core/editing/commands/editing_commands_utilities.cc
@@ -158,7 +158,7 @@
       layout_object->Style()->Display() == EDisplay::kInlineTable)
     return true;
 
-  if (layout_object->Style()->IsFloating())
+  if (layout_object->IsFloating())
     return true;
 
   return false;
diff --git a/third_party/blink/renderer/core/editing/commands/editor_command.cc b/third_party/blink/renderer/core/editing/commands/editor_command.cc
index 9664589..8432969 100644
--- a/third_party/blink/renderer/core/editing/commands/editor_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/editor_command.cc
@@ -58,6 +58,7 @@
 #include "third_party/blink/renderer/core/editing/set_selection_options.h"
 #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
 #include "third_party/blink/renderer/core/editing/visible_position.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
@@ -258,7 +259,7 @@
   auto* style =
       MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode);
   style->SetProperty(property_id, property_value, /* important */ false,
-                     frame.GetDocument()->GetSecureContextMode());
+                     frame.DomWindow()->GetSecureContextMode());
   // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a
   // good reason for that?
   switch (source) {
diff --git a/third_party/blink/renderer/core/editing/commands/remove_css_property_command.cc b/third_party/blink/renderer/core/editing/commands/remove_css_property_command.cc
index 9fd66c3..164cece 100644
--- a/third_party/blink/renderer/core/editing/commands/remove_css_property_command.cc
+++ b/third_party/blink/renderer/core/editing/commands/remove_css_property_command.cc
@@ -56,15 +56,17 @@
   // Mutate using the CSSOM wrapper so we get the same event behavior as a
   // script. Setting to null string removes the property. We don't have internal
   // version of removeProperty.
-  element_->style()->SetPropertyInternal(property_, String(), String(), false,
-                                         GetDocument().GetSecureContextMode(),
-                                         IGNORE_EXCEPTION_FOR_TESTING);
+  element_->style()->SetPropertyInternal(
+      property_, String(), String(), false,
+      GetDocument().GetExecutionContext()->GetSecureContextMode(),
+      IGNORE_EXCEPTION_FOR_TESTING);
 }
 
 void RemoveCSSPropertyCommand::DoUnapply() {
   element_->style()->SetPropertyInternal(
       property_, String(), old_value_, important_,
-      GetDocument().GetSecureContextMode(), IGNORE_EXCEPTION_FOR_TESTING);
+      GetDocument().GetExecutionContext()->GetSecureContextMode(),
+      IGNORE_EXCEPTION_FOR_TESTING);
 }
 
 void RemoveCSSPropertyCommand::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/editing/commands/style_commands.cc b/third_party/blink/renderer/core/editing/commands/style_commands.cc
index 6ba5f3a..84c26596 100644
--- a/third_party/blink/renderer/core/editing/commands/style_commands.cc
+++ b/third_party/blink/renderer/core/editing/commands/style_commands.cc
@@ -109,7 +109,7 @@
   auto* const style =
       MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode);
   style->SetProperty(property_id, property_value, /* important */ false,
-                     frame.GetDocument()->GetSecureContextMode());
+                     frame.DomWindow()->GetSecureContextMode());
   return ApplyCommandToFrame(frame, source, input_type, style);
 }
 
@@ -208,7 +208,7 @@
                                            CSSPropertyID property_id,
                                            const String& value) {
   const SecureContextMode secure_context_mode =
-      frame.GetDocument()->GetSecureContextMode();
+      frame.DomWindow()->GetSecureContextMode();
 
   EditingStyle* const style_to_check = MakeGarbageCollected<EditingStyle>(
       property_id, value, secure_context_mode);
@@ -239,7 +239,7 @@
 
   EditingStyle* const style = MakeGarbageCollected<EditingStyle>(
       property_id, style_is_present ? off_value : on_value,
-      frame.GetDocument()->GetSecureContextMode());
+      frame.DomWindow()->GetSecureContextMode());
   return ApplyCommandToFrame(frame, source, input_type, style->Style());
 }
 
@@ -322,7 +322,7 @@
   auto* const new_mutable_style =
       MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode);
   new_mutable_style->SetProperty(property_id, new_style, /* important */ false,
-                                 frame.GetDocument()->GetSecureContextMode());
+                                 frame.DomWindow()->GetSecureContextMode());
   return ApplyCommandToFrame(frame, source, input_type, new_mutable_style);
 }
 
diff --git a/third_party/blink/renderer/core/editing/editing_style.cc b/third_party/blink/renderer/core/editing/editing_style.cc
index 622c1e2..0752a694 100644
--- a/third_party/blink/renderer/core/editing/editing_style.cc
+++ b/third_party/blink/renderer/core/editing/editing_style.cc
@@ -58,6 +58,7 @@
 #include "third_party/blink/renderer/core/editing/serializers/html_interchange.h"
 #include "third_party/blink/renderer/core/editing/visible_selection.h"
 #include "third_party/blink/renderer/core/editing/writing_direction.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/html_font_element.h"
 #include "third_party/blink/renderer/core/html/html_span_element.h"
@@ -251,7 +252,7 @@
                                        EditingStyle* style) const {
   style->SetProperty(property_id_, identifier_value_->CssText(),
                      /* important */ false,
-                     element->GetDocument().GetSecureContextMode());
+                     element->GetExecutionContext()->GetSecureContextMode());
 }
 
 class HTMLTextDecorationEquivalent final : public HTMLElementEquivalent {
@@ -354,7 +355,7 @@
                                          EditingStyle* style) const {
   if (const CSSValue* value = AttributeValueAsCSSValue(element)) {
     style->SetProperty(property_id_, value->CssText(), /* important */ false,
-                       element->GetDocument().GetSecureContextMode());
+                       element->GetExecutionContext()->GetSecureContextMode());
   }
 }
 
@@ -367,8 +368,9 @@
 
   auto* dummy_style =
       MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode);
-  dummy_style->SetProperty(property_id_, value, /* important */ false,
-                           element->GetDocument().GetSecureContextMode());
+  dummy_style->SetProperty(
+      property_id_, value, /* important */ false,
+      element->GetExecutionContext()->GetSecureContextMode());
   return dummy_style->GetPropertyCSSValue(property_id_);
 }
 
@@ -520,13 +522,15 @@
             EditingStyleUtilities::BackgroundColorValueInEffect(node)) {
       mutable_style_->SetProperty(
           CSSPropertyID::kBackgroundColor, value->CssText(),
-          /* important */ false, node->GetDocument().GetSecureContextMode());
+          /* important */ false,
+          node->GetExecutionContext()->GetSecureContextMode());
     }
     if (const CSSValue* value = computed_style_at_position->GetPropertyCSSValue(
             CSSPropertyID::kWebkitTextDecorationsInEffect)) {
       mutable_style_->SetProperty(
           CSSPropertyID::kTextDecoration, value->CssText(),
-          /* important */ false, node->GetDocument().GetSecureContextMode());
+          /* important */ false,
+          node->GetExecutionContext()->GetSecureContextMode());
     }
   }
 
@@ -546,12 +550,13 @@
           CSSNumericLiteralValue::Create(computed_style->SpecifiedFontSize(),
                                          CSSPrimitiveValue::UnitType::kPixels)
               ->CssText(),
-          /* important */ false, node->GetDocument().GetSecureContextMode());
+          /* important */ false,
+          node->GetExecutionContext()->GetSecureContextMode());
     }
 
     RemoveInheritedColorsIfNeeded(computed_style);
     ReplaceFontSizeByKeywordIfPossible(
-        computed_style, node->GetDocument().GetSecureContextMode(),
+        computed_style, node->GetExecutionContext()->GetSecureContextMode(),
         computed_style_at_position);
   }
 
@@ -958,7 +963,7 @@
             inline_style->GetPropertyValue(CSSPropertyID::kTextDecorationLine),
             inline_style->PropertyIsImportant(
                 CSSPropertyID::kTextDecorationLine),
-            element->GetDocument().GetSecureContextMode());
+            element->GetExecutionContext()->GetSecureContextMode());
       }
       continue;
     }
@@ -975,7 +980,7 @@
         extracted_style->SetProperty(
             property_id, inline_style->GetPropertyValue(property_id),
             inline_style->PropertyIsImportant(property_id),
-            element->GetDocument().GetSecureContextMode());
+            element->GetExecutionContext()->GetSecureContextMode());
       }
     }
 
@@ -988,7 +993,7 @@
       extracted_style->SetProperty(
           property_id, inline_style->GetPropertyValue(property_id),
           inline_style->PropertyIsImportant(property_id),
-          element->GetDocument().GetSecureContextMode());
+          element->GetExecutionContext()->GetSecureContextMode());
     }
   }
 
@@ -1154,7 +1159,7 @@
          GetPropertiesNotIn(
              mutable_style_.Get(),
              MakeGarbageCollected<CSSComputedStyleDeclaration>(node),
-             node->GetDocument().GetSecureContextMode())
+             node->GetExecutionContext()->GetSecureContextMode())
              ->IsEmpty();
 }
 
@@ -1513,7 +1518,7 @@
   DCHECK(element->GetDocument().IsActive());
 
   SecureContextMode secure_context_mode =
-      element->GetDocument().GetSecureContextMode();
+      element->GetExecutionContext()->GetSecureContextMode();
 
   // 1. Remove style from matched rules because style remain without repeating
   // it in inline style declaration
@@ -1635,11 +1640,12 @@
   CSSComputedStyleDeclaration* computed_style = EnsureComputedStyle(position);
   // FIXME: take care of background-color in effect
   MutableCSSPropertyValueSet* mutable_style = GetPropertiesNotIn(
-      style->Style(), computed_style, document->GetSecureContextMode());
+      style->Style(), computed_style,
+      document->GetExecutionContext()->GetSecureContextMode());
   DCHECK(mutable_style);
 
-  ReconcileTextDecorationProperties(mutable_style,
-                                    document->GetSecureContextMode());
+  ReconcileTextDecorationProperties(
+      mutable_style, document->GetExecutionContext()->GetSecureContextMode());
   if (!document->GetFrame()->GetEditor().ShouldStyleWithCSS())
     ExtractTextStyles(document, mutable_style,
                       computed_style->IsMonospaceFont());
@@ -1658,7 +1664,8 @@
     mutable_style->SetProperty(
         CSSPropertyID::kDirection,
         style->Style()->GetPropertyValue(CSSPropertyID::kDirection),
-        /* important */ false, document->GetSecureContextMode());
+        /* important */ false,
+        document->GetExecutionContext()->GetSecureContextMode());
   }
 
   // Save the result for later
@@ -1733,9 +1740,9 @@
       apply_line_through_ = true;
 
     // If trimTextDecorations, delete underline and line-through
-    SetTextDecorationProperty(style, new_text_decoration,
-                              CSSPropertyID::kTextDecorationLine,
-                              document->GetSecureContextMode());
+    SetTextDecorationProperty(
+        style, new_text_decoration, CSSPropertyID::kTextDecorationLine,
+        document->GetExecutionContext()->GetSecureContextMode());
   }
 
   CSSValueID vertical_align =
@@ -1949,7 +1956,7 @@
                                                 CSSPropertyID property_id,
                                                 const String& value) {
   const SecureContextMode secure_context_mode =
-      frame.GetDocument()->GetSecureContextMode();
+      frame.DomWindow()->GetSecureContextMode();
 
   return MakeGarbageCollected<EditingStyle>(property_id, value,
                                             secure_context_mode)
diff --git a/third_party/blink/renderer/core/editing/editing_style_utilities.cc b/third_party/blink/renderer/core/editing/editing_style_utilities.cc
index 9ee0f8e..ac003c5b 100644
--- a/third_party/blink/renderer/core/editing/editing_style_utilities.cc
+++ b/third_party/blink/renderer/core/editing/editing_style_utilities.cc
@@ -99,7 +99,7 @@
   // Call collapseTextDecorationProperties first or otherwise it'll copy the
   // value over from in-effect to text-decorations.
   wrapping_style->CollapseTextDecorationProperties(
-      context->GetDocument().GetSecureContextMode());
+      context->GetExecutionContext()->GetSecureContextMode());
 
   return wrapping_style;
 }
@@ -190,9 +190,10 @@
     const EphemeralRange range(selection.ToNormalizedEphemeralRange());
     if (const CSSValue* value =
             BackgroundColorValueInEffect(range.CommonAncestorContainer())) {
-      style->SetProperty(CSSPropertyID::kBackgroundColor, value->CssText(),
-                         /* important */ false,
-                         document.GetSecureContextMode());
+      style->SetProperty(
+          CSSPropertyID::kBackgroundColor, value->CssText(),
+          /* important */ false,
+          document.GetExecutionContext()->GetSecureContextMode());
     }
   }
 
diff --git a/third_party/blink/renderer/core/editing/editor.cc b/third_party/blink/renderer/core/editing/editor.cc
index 02b5f19..96dffd1 100644
--- a/third_party/blink/renderer/core/editing/editor.cc
+++ b/third_party/blink/renderer/core/editing/editor.cc
@@ -652,7 +652,7 @@
       direction == WritingDirection::kLeftToRight
           ? "ltr"
           : direction == WritingDirection::kRightToLeft ? "rtl" : "inherit",
-      /* important */ false, GetFrame().GetDocument()->GetSecureContextMode());
+      /* important */ false, GetFrame().DomWindow()->GetSecureContextMode());
   ApplyParagraphStyleToSelection(
       style, InputEvent::InputType::kFormatSetBlockTextDirection);
 }
diff --git a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
index d150e8ca..d9e9edf 100644
--- a/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
+++ b/third_party/blink/renderer/core/editing/serializers/styled_markup_serializer.cc
@@ -267,7 +267,8 @@
                       html_names::kBackgroundAttr) +
                   "')",
               /* important */ false,
-              fully_selected_root->GetDocument().GetSecureContextMode());
+              fully_selected_root->GetExecutionContext()
+                  ->GetSecureContextMode());
         }
 
         if (fully_selected_root_style->Style()) {
diff --git a/third_party/blink/renderer/core/events/application_cache_error_event.idl b/third_party/blink/renderer/core/events/application_cache_error_event.idl
index 040c370b..aee9544e 100644
--- a/third_party/blink/renderer/core/events/application_cache_error_event.idl
+++ b/third_party/blink/renderer/core/events/application_cache_error_event.idl
@@ -11,7 +11,7 @@
 [
     Exposed=Window,
     RuntimeEnabled=AppCache,
-    SecureContext=RestrictAppCacheToSecureContexts
+    SecureContext
 ] interface ApplicationCacheErrorEvent : Event {
     constructor(DOMString type, optional ApplicationCacheErrorEventInit eventInitDict = {});
     readonly attribute DOMString reason;
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
index f881ad9..d7570a69 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_impl.cc
@@ -522,7 +522,7 @@
   String script = DecodeURLEscapeSequences(kurl.GetString(),
                                            DecodeURLMode::kUTF8OrIsomorphic);
 
-  if (!element_->GetDocument().GetContentSecurityPolicy()->AllowInline(
+  if (!element_->GetExecutionContext()->GetContentSecurityPolicy()->AllowInline(
           ContentSecurityPolicy::InlineType::kNavigation, element_, script,
           String() /* nonce */, element_->GetDocument().Url(),
           OrdinalNumber())) {
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index ad4291b0..7816c84a 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -40,7 +40,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_security_policy_violation_event_init.h"
-#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_string_list.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/events/event_queue.h"
@@ -135,7 +134,7 @@
   }
 
   UseCounter::Count(
-      element->GetDocument(),
+      element->GetExecutionContext(),
       nonceable ? WebFeature::kCleanScriptElementWithNonce
                 : WebFeature::kPotentiallyInjectedScriptElementWithNonce);
 
@@ -630,20 +629,6 @@
   return true;
 }
 
-bool ContentSecurityPolicy::AllowPluginTypeForDocument(
-    const Document& document,
-    const String& type,
-    const String& type_attribute,
-    const KURL& url,
-    ReportingDisposition reporting_disposition) const {
-  if (document.GetContentSecurityPolicy() &&
-      !document.GetContentSecurityPolicy()->AllowPluginType(
-          type, type_attribute, url, reporting_disposition))
-    return false;
-
-  return true;
-}
-
 static base::Optional<ContentSecurityPolicy::DirectiveType>
 GetDirectiveTypeFromRequestContextType(mojom::RequestContextType context) {
   switch (context) {
@@ -1476,7 +1461,7 @@
 void ContentSecurityPolicy::LogToConsole(ConsoleMessage* console_message,
                                          LocalFrame* frame) {
   if (frame)
-    frame->GetDocument()->AddConsoleMessage(console_message);
+    frame->DomWindow()->AddConsoleMessage(console_message);
   else if (delegate_)
     delegate_->AddConsoleMessage(console_message);
   else
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index 74457d0..45375414 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -64,7 +64,6 @@
 class ConsoleMessage;
 class CSPDirectiveList;
 class CSPSource;
-class Document;
 class DOMWrapperWorld;
 class Element;
 class ExecutionContext;
@@ -259,15 +258,6 @@
       const String& type_attribute,
       const KURL&,
       ReportingDisposition = ReportingDisposition::kReport) const;
-  // Checks whether the plugin type should be allowed in the given
-  // document; enforces the CSP rule that PluginDocuments inherit
-  // plugin-types directives from the parent document.
-  bool AllowPluginTypeForDocument(
-      const Document&,
-      const String& type,
-      const String& type_attribute,
-      const KURL&,
-      ReportingDisposition = ReportingDisposition::kReport) const;
 
   // AllowFromSource() wrappers.
   bool AllowBaseURI(const KURL&) const;
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
index af3311c..86c23184 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -1319,9 +1319,9 @@
                                  g_empty_string));
   EXPECT_TRUE(csp->AllowPluginType("application/x-type-1",
                                    "application/x-type-1", example_url));
-  EXPECT_TRUE(csp->AllowPluginTypeForDocument(
-      *document, "application/x-type-1", "application/x-type-1", example_url,
-      ReportingDisposition::kSuppressReporting));
+  EXPECT_TRUE(csp->AllowPluginType("application/x-type-1",
+                                   "application/x-type-1", example_url,
+                                   ReportingDisposition::kSuppressReporting));
 
   ContentSecurityPolicy::DirectiveType types_to_test[] = {
       ContentSecurityPolicy::DirectiveType::kBaseURI,
diff --git a/third_party/blink/renderer/core/frame/display_cutout_client_impl.cc b/third_party/blink/renderer/core/frame/display_cutout_client_impl.cc
index 42541dc..16b1bf3 100644
--- a/third_party/blink/renderer/core/frame/display_cutout_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/display_cutout_client_impl.cc
@@ -17,10 +17,6 @@
 const char kSafeAreaInsetBottomName[] = "safe-area-inset-bottom";
 const char kSafeAreaInsetRightName[] = "safe-area-inset-right";
 
-String GetPx(int value) {
-  return String::Format("%dpx", value);
-}
-
 }  // namespace
 
 DisplayCutoutClientImpl::DisplayCutoutClientImpl(
@@ -41,10 +37,14 @@
     mojom::blink::DisplayCutoutSafeAreaPtr safe_area) {
   DocumentStyleEnvironmentVariables& vars =
       frame_->GetDocument()->GetStyleEngine().EnsureEnvironmentVariables();
-  vars.SetVariable(kSafeAreaInsetTopName, GetPx(safe_area->top));
-  vars.SetVariable(kSafeAreaInsetLeftName, GetPx(safe_area->left));
-  vars.SetVariable(kSafeAreaInsetBottomName, GetPx(safe_area->bottom));
-  vars.SetVariable(kSafeAreaInsetRightName, GetPx(safe_area->right));
+  vars.SetVariable(kSafeAreaInsetTopName,
+                   StyleEnvironmentVariables::FormatPx(safe_area->top));
+  vars.SetVariable(kSafeAreaInsetLeftName,
+                   StyleEnvironmentVariables::FormatPx(safe_area->left));
+  vars.SetVariable(kSafeAreaInsetBottomName,
+                   StyleEnvironmentVariables::FormatPx(safe_area->bottom));
+  vars.SetVariable(kSafeAreaInsetRightName,
+                   StyleEnvironmentVariables::FormatPx(safe_area->right));
 }
 
 void DisplayCutoutClientImpl::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index e00ab34..1d4fa3bc 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -243,6 +243,12 @@
           MakeGarbageCollected<
               HeapHashMap<int, Member<ContentSecurityPolicy>>>()) {}
 
+void LocalDOMWindow::BindContentSecurityPolicy() {
+  DCHECK(!GetContentSecurityPolicy()->IsBound());
+  GetContentSecurityPolicy()->BindToDelegate(
+      GetContentSecurityPolicyDelegate());
+}
+
 void LocalDOMWindow::AcceptLanguagesChanged() {
   if (navigator_)
     navigator_->SetLanguagesDirty();
@@ -1034,11 +1040,11 @@
   }
 
   KURL sender(event->origin());
-  if (!document()->GetContentSecurityPolicy()->AllowConnectToSource(
+  if (!GetContentSecurityPolicy()->AllowConnectToSource(
           sender, sender, RedirectStatus::kNoRedirect,
           ReportingDisposition::kSuppressReporting)) {
     UseCounter::Count(
-        document(), WebFeature::kPostMessageIncomingWouldBeBlockedByConnectSrc);
+        this, WebFeature::kPostMessageIncomingWouldBeBlockedByConnectSrc);
   }
 
   if (event->IsOriginCheckRequiredToAccessData()) {
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index ebb8f6c..3ae4c7c3 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -110,6 +110,11 @@
 
   LocalFrame* GetFrame() const { return To<LocalFrame>(DOMWindow::GetFrame()); }
 
+  // Bind Content Security Policy to this window. This will cause the
+  // CSP to resolve the 'self' attribute and all policies will then be
+  // applied to this document.
+  void BindContentSecurityPolicy();
+
   void Trace(Visitor*) const override;
 
   // ExecutionContext overrides:
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 3676f88..a10b29fa2 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -73,6 +73,7 @@
 #include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
 #include "third_party/blink/renderer/core/core_initializer.h"
 #include "third_party/blink/renderer/core/core_probe_sink.h"
+#include "third_party/blink/renderer/core/css/document_style_environment_variables.h"
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/dom/child_frame_disconnector.h"
 #include "third_party/blink/renderer/core/dom/document_init.h"
@@ -333,7 +334,10 @@
           GetTaskRunner(blink::TaskType::kInternalDefault)));
   GetInterfaceRegistry()->AddAssociatedInterface(WTF::BindRepeating(
       &LocalFrame::BindToReceiver, WrapWeakPersistent(this)));
-
+  GetInterfaceRegistry()->AddInterface(
+      WTF::BindRepeating(&LocalFrame::BindToHighPriorityReceiver,
+                         WrapWeakPersistent(this)),
+      GetTaskRunner(blink::TaskType::kInternalHighPriorityLocalFrame));
   loader_.Init();
 }
 
@@ -1037,6 +1041,79 @@
   }
 }
 
+void LocalFrame::WindowSegmentsChanged(
+    const WebVector<WebRect>& window_segments) {
+  if (!RuntimeEnabledFeatures::CSSFoldablesEnabled())
+    return;
+
+  // A change in the window segments requires re-evaluation of media queries
+  // for the local frame subtree (the segments affect the "screen-spanning"
+  // feature).
+  MediaQueryAffectingValueChangedForLocalSubtree(MediaValueChange::kOther);
+
+  // Also need to update the environment variables related to window segments
+  // on the local frame subtree.
+  UpdateCSSFoldEnvironmentVariables(window_segments);
+  for (Frame* child = Tree().FirstChild(); child;
+       child = child->Tree().NextSibling()) {
+    if (auto* child_local_frame = DynamicTo<LocalFrame>(child))
+      child_local_frame->UpdateCSSFoldEnvironmentVariables(window_segments);
+  }
+}
+
+void LocalFrame::UpdateCSSFoldEnvironmentVariables(
+    const WebVector<WebRect>& window_segments) {
+  DCHECK(RuntimeEnabledFeatures::CSSFoldablesEnabled());
+
+  DocumentStyleEnvironmentVariables& vars =
+      GetDocument()->GetStyleEngine().EnsureEnvironmentVariables();
+
+  // CSS environment variables related to window segments currently only
+  // expose values for a single fold (i.e. if there are two segments). In all
+  // other cases, these variables will not be defined - see the else clause for
+  // where these are unset.
+  if (window_segments.size() == 2) {
+    // We need to determine the rectangle between the two segments, which
+    // describes the fold area (note that this may have a zero width or height,
+    // but not negative).
+    gfx::Rect fold_rect;
+    if (window_segments[0].y == window_segments[1].y) {
+      int fold_width = window_segments[1].x - window_segments[0].width;
+      DCHECK_GE(fold_width, 0);
+      fold_rect.SetRect(window_segments[0].width, window_segments[0].y,
+                        fold_width, window_segments[0].height);
+    } else if (window_segments[0].x == window_segments[1].x) {
+      int fold_height = window_segments[1].y - window_segments[0].height;
+      DCHECK_GE(fold_height, 0);
+      fold_rect.SetRect(window_segments[0].x, window_segments[0].height,
+                        window_segments[0].width, fold_height);
+    }
+
+    vars.SetVariable(UADefinedVariable::kFoldTop,
+                     StyleEnvironmentVariables::FormatPx(fold_rect.y()));
+    vars.SetVariable(UADefinedVariable::kFoldRight,
+                     StyleEnvironmentVariables::FormatPx(fold_rect.right()));
+    vars.SetVariable(UADefinedVariable::kFoldBottom,
+                     StyleEnvironmentVariables::FormatPx(fold_rect.bottom()));
+    vars.SetVariable(UADefinedVariable::kFoldLeft,
+                     StyleEnvironmentVariables::FormatPx(fold_rect.x()));
+    vars.SetVariable(UADefinedVariable::kFoldWidth,
+                     StyleEnvironmentVariables::FormatPx(fold_rect.width()));
+    vars.SetVariable(UADefinedVariable::kFoldHeight,
+                     StyleEnvironmentVariables::FormatPx(fold_rect.height()));
+  } else {
+    // If there is not a single fold, we treat the variable as undefined
+    // (i.e. the fallback value specified in the env() function).
+    const UADefinedVariable vars_to_remove[] = {
+        UADefinedVariable::kFoldTop,    UADefinedVariable::kFoldRight,
+        UADefinedVariable::kFoldBottom, UADefinedVariable::kFoldLeft,
+        UADefinedVariable::kFoldWidth,  UADefinedVariable::kFoldHeight,
+    };
+    for (auto var : vars_to_remove)
+      vars.RemoveVariable(StyleEnvironmentVariables::GetVariableName(var));
+  }
+}
+
 double LocalFrame::DevicePixelRatio() const {
   if (!page_)
     return 0;
@@ -2552,6 +2629,11 @@
                           before_unload_end_time);
 }
 
+void LocalFrame::DispatchBeforeUnload(bool is_reload,
+                                      BeforeUnloadCallback callback) {
+  BeforeUnload(is_reload, std::move(callback));
+}
+
 void LocalFrame::MediaPlayerActionAtViewportPoint(
     const IntPoint& viewport_position,
     const blink::mojom::blink::MediaPlayerActionType type,
@@ -2698,7 +2780,7 @@
           ? this
           : nullptr;
 
-  GetDocument()->GetContentSecurityPolicy()->ReportViolation(
+  DomWindow()->GetContentSecurityPolicy()->ReportViolation(
       violation->directive, directive_type, violation->console_message,
       violation->blocked_url, violation->report_endpoints,
       violation->use_reporting_api, violation->header, violation->type,
@@ -2870,6 +2952,13 @@
       frame->GetTaskRunner(blink::TaskType::kInternalDefault));
 }
 
+void LocalFrame::BindToHighPriorityReceiver(
+    mojo::PendingReceiver<mojom::blink::HighPriorityLocalFrame> receiver) {
+  high_priority_frame_receiver_.Bind(
+      std::move(receiver),
+      GetTaskRunner(blink::TaskType::kInternalHighPriorityLocalFrame));
+}
+
 SpellChecker& LocalFrame::GetSpellChecker() const {
   DCHECK(DomWindow());
   return DomWindow()->GetSpellChecker();
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index 5e51bac..999d1af 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -135,11 +135,13 @@
 
 extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<LocalFrame>;
 
-class CORE_EXPORT LocalFrame final : public Frame,
-                                     public FrameScheduler::Delegate,
-                                     public Supplementable<LocalFrame>,
-                                     public mojom::blink::LocalFrame,
-                                     public mojom::blink::LocalMainFrame {
+class CORE_EXPORT LocalFrame final
+    : public Frame,
+      public FrameScheduler::Delegate,
+      public Supplementable<LocalFrame>,
+      public mojom::blink::LocalFrame,
+      public mojom::blink::LocalMainFrame,
+      public mojom::blink::HighPriorityLocalFrame {
   USING_GARBAGE_COLLECTED_MIXIN(LocalFrame);
 
  public:
@@ -299,6 +301,10 @@
   // media query value changed.
   void MediaQueryAffectingValueChangedForLocalSubtree(MediaValueChange);
 
+  void WindowSegmentsChanged(const WebVector<WebRect>& window_segments);
+  void UpdateCSSFoldEnvironmentVariables(
+      const WebVector<WebRect>& window_segments);
+
   String SelectedText() const;
   String SelectedTextForClipboard() const;
 
@@ -559,6 +565,8 @@
   void ReportBlinkFeatureUsage(const Vector<mojom::blink::WebFeature>&) final;
   void RenderFallbackContent() final;
   void BeforeUnload(bool is_reload, BeforeUnloadCallback callback) final;
+  void DispatchBeforeUnload(bool is_reload,
+                            BeforeUnloadCallback callback) final;
   void MediaPlayerActionAt(
       const gfx::Point& window_point,
       blink::mojom::blink::MediaPlayerActionPtr action) final;
@@ -684,6 +692,8 @@
   static void BindToMainFrameReceiver(
       blink::LocalFrame* frame,
       mojo::PendingAssociatedReceiver<mojom::blink::LocalMainFrame> receiver);
+  void BindToHighPriorityReceiver(
+      mojo::PendingReceiver<mojom::blink::HighPriorityLocalFrame> receiver);
 
   std::unique_ptr<FrameScheduler> frame_scheduler_;
 
@@ -807,6 +817,9 @@
                              HeapMojoWrapperMode::kWithoutContextObserver>
       main_frame_receiver_{this, nullptr};
 
+  mojo::Receiver<mojom::blink::HighPriorityLocalFrame>
+      high_priority_frame_receiver_{this};
+
   // Variable to control burst of download requests.
   int num_burst_download_requests_ = 0;
   base::TimeTicks burst_download_start_time_;
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 2383480..7458321f 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -1795,15 +1795,19 @@
     return;
 
   base_background_color_ = background_color;
-  if (auto* layout_view = GetLayoutView()) {
-    if (layout_view->Layer()->HasCompositedLayerMapping()) {
-      CompositedLayerMapping* composited_layer_mapping =
-          layout_view->Layer()->GetCompositedLayerMapping();
-      composited_layer_mapping->UpdateContentsOpaque();
-      if (composited_layer_mapping->MainGraphicsLayer())
-        composited_layer_mapping->MainGraphicsLayer()->SetNeedsDisplay();
-      if (composited_layer_mapping->ScrollingContentsLayer())
-        composited_layer_mapping->ScrollingContentsLayer()->SetNeedsDisplay();
+
+  if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+    DisableCompositingQueryAsserts disabler;
+    if (auto* layout_view = GetLayoutView()) {
+      if (layout_view->Layer()->HasCompositedLayerMapping()) {
+        CompositedLayerMapping* composited_layer_mapping =
+            layout_view->Layer()->GetCompositedLayerMapping();
+        composited_layer_mapping->UpdateContentsOpaque();
+        if (composited_layer_mapping->MainGraphicsLayer())
+          composited_layer_mapping->MainGraphicsLayer()->SetNeedsDisplay();
+        if (composited_layer_mapping->ScrollingContentsLayer())
+          composited_layer_mapping->ScrollingContentsLayer()->SetNeedsDisplay();
+      }
     }
   }
 
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
index 57651f76d..f14beab 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
@@ -826,8 +826,11 @@
 }
 
 void WebFrameWidgetBase::SetWindowSegments(WebVector<WebRect> window_segments) {
-  if (!window_segments_.Equals(window_segments))
+  if (!window_segments_.Equals(window_segments)) {
     window_segments_ = std::move(window_segments);
+    LocalFrame* frame = LocalRootImpl()->GetFrame();
+    frame->WindowSegmentsChanged(window_segments_);
+  }
 }
 
 void WebFrameWidgetBase::SetCursor(const ui::Cursor& cursor) {
diff --git a/third_party/blink/renderer/core/frame/window.idl b/third_party/blink/renderer/core/frame/window.idl
index f162439..789a3a0 100644
--- a/third_party/blink/renderer/core/frame/window.idl
+++ b/third_party/blink/renderer/core/frame/window.idl
@@ -75,7 +75,7 @@
     // the user agent
     // includes https://github.com/whatwg/html/pull/5545 (originIsolationRestricted)
     [Affects=Nothing, LogActivity=GetterOnly] readonly attribute Navigator navigator;
-    [LogActivity=GetterOnly, SecureContext=RestrictAppCacheToSecureContexts, RuntimeEnabled=AppCache] readonly attribute ApplicationCache applicationCache;
+    [LogActivity=GetterOnly, SecureContext, RuntimeEnabled=AppCache] readonly attribute ApplicationCache applicationCache;
     [RuntimeEnabled=OriginIsolationHeader, SecureContext] readonly attribute boolean originIsolationRestricted;
 
     // user prompts
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
index f246749..8a1a3a6 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_font_cache.cc
@@ -93,8 +93,9 @@
   } else {
     parsed_style =
         MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLStandardMode);
-    CSSParser::ParseValue(parsed_style, CSSPropertyID::kFont, font_string, true,
-                          document_->GetSecureContextMode());
+    CSSParser::ParseValue(
+        parsed_style, CSSPropertyID::kFont, font_string, true,
+        document_->GetExecutionContext()->GetSecureContextMode());
     if (parsed_style->IsEmpty())
       return nullptr;
     // According to
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.cc b/third_party/blink/renderer/core/html/forms/html_form_element.cc
index d26fe83d..e91d62b 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_form_element.cc
@@ -470,7 +470,7 @@
     return;
   }
 
-  if (!GetDocument().GetContentSecurityPolicy()->AllowFormAction(
+  if (!GetExecutionContext()->GetContentSecurityPolicy()->AllowFormAction(
           form_submission->Action())) {
     return;
   }
diff --git a/third_party/blink/renderer/core/html/forms/password_input_type_test.cc b/third_party/blink/renderer/core/html/forms/password_input_type_test.cc
index 9dc42a7..e24ea410 100644
--- a/third_party/blink/renderer/core/html/forms/password_input_type_test.cc
+++ b/third_party/blink/renderer/core/html/forms/password_input_type_test.cc
@@ -13,6 +13,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/mojom/insecure_input/insecure_input_service.mojom-blink.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -76,8 +77,10 @@
       nullptr /* extra_data */);
   blink::test::RunPendingTasks();
   MockInsecureInputService mock_service(page_holder->GetFrame());
-  page_holder->GetDocument().SetSecureContextModeForTesting(
-      SecureContextMode::kSecureContext);
+  page_holder->GetFrame()
+      .DomWindow()
+      ->GetSecurityContext()
+      .SetSecureContextModeForTesting(SecureContextMode::kSecureContext);
   page_holder->GetDocument().body()->setInnerHTML("<input type='password'>");
   page_holder->GetDocument().View()->UpdateAllLifecyclePhases(
       DocumentUpdateReason::kTest);
diff --git a/third_party/blink/renderer/core/html/html_font_element.cc b/third_party/blink/renderer/core/html/html_font_element.cc
index 3c78d66..f09b301d 100644
--- a/third_party/blink/renderer/core/html/html_font_element.cc
+++ b/third_party/blink/renderer/core/html/html_font_element.cc
@@ -186,7 +186,7 @@
     AddHTMLColorToStyle(style, CSSPropertyID::kColor, value);
   } else if (name == html_names::kFaceAttr && !value.IsEmpty()) {
     if (const CSSValueList* font_face_value = CreateFontFaceValueWithPool(
-            value, GetDocument().GetSecureContextMode())) {
+            value, GetExecutionContext()->GetSecureContextMode())) {
       style->SetProperty(
           CSSPropertyValue(GetCSSPropertyFontFamily(), *font_face_value));
     }
diff --git a/third_party/blink/renderer/core/html/html_html_element.cc b/third_party/blink/renderer/core/html/html_html_element.cc
index 929a82ab..5d6c0068 100644
--- a/third_party/blink/renderer/core/html/html_html_element.cc
+++ b/third_party/blink/renderer/core/html/html_html_element.cc
@@ -76,22 +76,15 @@
   if (!document_loader ||
       !GetDocument().Parser()->DocumentWasLoadedAsPartOfNavigation())
     return;
-  const AtomicString& manifest = FastGetAttribute(html_names::kManifestAttr);
 
-  if (RuntimeEnabledFeatures::RestrictAppCacheToSecureContextsEnabled() &&
-      !GetExecutionContext()->IsSecureContext()) {
-    if (!manifest.IsEmpty()) {
-      Deprecation::CountDeprecation(
-          GetExecutionContext(),
-          WebFeature::kApplicationCacheAPIInsecureOrigin);
-    }
+  if (!GetExecutionContext()->IsSecureContext())
     return;
-  }
 
   ApplicationCacheHostForFrame* host =
       document_loader->GetApplicationCacheHost();
   DCHECK(host);
 
+  const AtomicString& manifest = FastGetAttribute(html_names::kManifestAttr);
   if (manifest.IsEmpty())
     host->SelectCacheWithoutManifest();
   else
diff --git a/third_party/blink/renderer/core/html/html_marquee_element.cc b/third_party/blink/renderer/core/html/html_marquee_element.cc
index 9fc8c4e..4f85043 100644
--- a/third_party/blink/renderer/core/html/html_marquee_element.cc
+++ b/third_party/blink/renderer/core/html/html_marquee_element.cc
@@ -244,7 +244,7 @@
   MutableCSSPropertyValueSet::SetResult set_result;
 
   SecureContextMode secure_context_mode =
-      mover_->GetDocument().GetSecureContextMode();
+      mover_->GetExecutionContext()->GetSecureContextMode();
 
   StringKeyframeVector keyframes;
   auto* keyframe1 = MakeGarbageCollected<StringKeyframe>();
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.cc b/third_party/blink/renderer/core/html/html_plugin_element.cc
index de60841..fcaa2c5 100644
--- a/third_party/blink/renderer/core/html/html_plugin_element.cc
+++ b/third_party/blink/renderer/core/html/html_plugin_element.cc
@@ -710,9 +710,9 @@
     return false;
 
   AtomicString declared_mime_type = FastGetAttribute(html_names::kTypeAttr);
-  if (!GetDocument().GetContentSecurityPolicy()->AllowObjectFromSource(url) ||
-      !GetDocument().GetContentSecurityPolicy()->AllowPluginTypeForDocument(
-          GetDocument(), mime_type, declared_mime_type, url)) {
+  auto* csp = GetExecutionContext()->GetContentSecurityPolicy();
+  if (!csp->AllowObjectFromSource(url) ||
+      !csp->AllowPluginType(mime_type, declared_mime_type, url)) {
     if (auto* layout_object = GetLayoutEmbeddedObject()) {
       plugin_is_available_ = false;
       layout_object->SetPluginAvailability(
diff --git a/third_party/blink/renderer/core/html/imports/html_import_loader.cc b/third_party/blink/renderer/core/html/imports/html_import_loader.cc
index b23f609a..71e96ec 100644
--- a/third_party/blink/renderer/core/html/imports/html_import_loader.cc
+++ b/third_party/blink/renderer/core/html/imports/html_import_loader.cc
@@ -103,9 +103,6 @@
           .WithExecutionContext(tree_root->GetExecutionContext())
           .WithRegistrationContext(tree_root->RegistrationContext())
           .WithURL(response.CurrentRequestUrl()));
-  // imports expect to be able to log CSP errors, which requires binding the CSP
-  // to a CSP delegate.
-  document_->BindContentSecurityPolicy();
   document_->OpenForNavigation(
       RuntimeEnabledFeatures::ForceSynchronousHTMLParsingEnabled()
           ? kAllowDeferredParsing
diff --git a/third_party/blink/renderer/core/html/link_style.cc b/third_party/blink/renderer/core/html/link_style.cc
index 5036ac1..de09b3ea3 100644
--- a/third_party/blink/renderer/core/html/link_style.cc
+++ b/third_party/blink/renderer/core/html/link_style.cc
@@ -338,9 +338,12 @@
       return;
     if (!GetDocument().GetSecurityOrigin()->CanDisplay(params.href))
       return;
-    if (!GetDocument().GetContentSecurityPolicy()->AllowImageFromSource(
-            params.href, params.href, RedirectStatus::kNoRedirect))
+    if (!GetExecutionContext()
+             ->GetContentSecurityPolicy()
+             ->AllowImageFromSource(params.href, params.href,
+                                    RedirectStatus::kNoRedirect)) {
       return;
+    }
     if (GetDocument().GetFrame())
       GetDocument().GetFrame()->UpdateFaviconURL();
   }
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 b692dc5d..bd681ce 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
@@ -1495,7 +1495,8 @@
     return false;
   }
 
-  if (!GetDocument().GetContentSecurityPolicy()->AllowMediaFromSource(url)) {
+  if (!GetExecutionContext()->GetContentSecurityPolicy()->AllowMediaFromSource(
+          url)) {
     DVLOG(3) << "isSafeToLoadURL(" << *this << ", " << UrlForLoggingMedia(url)
              << ") -> rejected by Content Security Policy";
     return false;
diff --git a/third_party/blink/renderer/core/html/track/html_track_element.cc b/third_party/blink/renderer/core/html/track/html_track_element.cc
index e461bbb..56ef0d1c 100644
--- a/third_party/blink/renderer/core/html/track/html_track_element.cc
+++ b/third_party/blink/renderer/core/html/track/html_track_element.cc
@@ -226,7 +226,8 @@
   if (url.IsEmpty())
     return false;
 
-  if (!GetDocument().GetContentSecurityPolicy()->AllowMediaFromSource(url)) {
+  if (!GetExecutionContext()->GetContentSecurityPolicy()->AllowMediaFromSource(
+          url)) {
     DVLOG(TRACK_LOG_LEVEL) << "canLoadUrl(" << UrlForLoggingTrack(url)
                            << ") -> rejected by Content Security Policy";
     return false;
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
index 2fb9d17..1f98c32 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_css_agent.cc
@@ -121,8 +121,9 @@
                             const String& old_text,
                             const String& longhand,
                             const String& new_value) {
-  auto* style_sheet_contents = MakeGarbageCollected<StyleSheetContents>(
-      StrictCSSParserContext(document.GetSecureContextMode()));
+  auto* style_sheet_contents =
+      MakeGarbageCollected<StyleSheetContents>(StrictCSSParserContext(
+          document.GetExecutionContext()->GetSecureContextMode()));
   String text = " div { " + shorthand + ": " + old_text + "; }";
   CSSParser::ParseSheet(MakeGarbageCollected<CSSParserContext>(document),
                         style_sheet_contents, text);
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 6bc15a56..570649c3 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -380,6 +380,16 @@
         // recalculation.
         SetNeedsLayoutAndIntrinsicWidthsRecalc(
             layout_invalidation_reason::kStyleChange);
+
+        if (IsInLayoutNGInlineFormattingContext() &&
+            RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() &&
+            FirstInlineFragmentItemIndex()) {
+          // Out of flow are not part of |NGFragmentItems|, and that further
+          // changes including destruction cannot be tracked. Mark it is moved
+          // out from this IFC.
+          NGFragmentItems::LayoutObjectWillBeMoved(*this);
+          ClearFirstInlineFragmentItemIndex();
+        }
       } else {
         MarkContainerChainForLayout();
       }
@@ -626,7 +636,8 @@
   LayoutBoxModelObject::UpdateFromStyle();
 
   const ComputedStyle& style_to_use = StyleRef();
-  SetFloating(!IsOutOfFlowPositioned() && style_to_use.IsFloating());
+  SetFloating(style_to_use.IsFloating() && !IsOutOfFlowPositioned() &&
+              !style_to_use.IsFlexOrGridItem());
   SetHasTransformRelatedProperty(style_to_use.HasTransformRelatedProperty());
   SetHasReflection(style_to_use.BoxReflect());
   // LayoutTable and LayoutTableCell will overwrite this flag if needed.
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 5921913..dd048d5 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1356,7 +1356,7 @@
     return IsFlexItemCommon() && Parent()->IsFlexibleBoxIncludingNG();
   }
   bool IsFlexItemCommon() const {
-    return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent();
+    return !IsInline() && !IsOutOfFlowPositioned() && Parent();
   }
 
   bool IsGridItem() const { return Parent() && Parent()->IsLayoutGrid(); }
diff --git a/third_party/blink/renderer/core/layout/layout_fieldset.cc b/third_party/blink/renderer/core/layout/layout_fieldset.cc
index 9110d09..96b0bae 100644
--- a/third_party/blink/renderer/core/layout/layout_fieldset.cc
+++ b/third_party/blink/renderer/core/layout/layout_fieldset.cc
@@ -158,10 +158,7 @@
   }
   for (LayoutObject* legend = parent->FirstChild(); legend;
        legend = legend->NextSibling()) {
-    if (legend->IsFloatingOrOutOfFlowPositioned())
-      continue;
-
-    if (legend->IsHTMLLegendElement())
+    if (legend->IsRenderedLegendCandidate())
       return ToLayoutBox(legend);
   }
   return nullptr;
diff --git a/third_party/blink/renderer/core/layout/layout_media.cc b/third_party/blink/renderer/core/layout/layout_media.cc
index 359dc68..a59ab695 100644
--- a/third_party/blink/renderer/core/layout/layout_media.cc
+++ b/third_party/blink/renderer/core/layout/layout_media.cc
@@ -110,7 +110,8 @@
 
   // Out-of-flow positioned or floating child breaks layout hierarchy.
   // This check can be removed if ::-webkit-media-controls is made internal.
-  if (style.HasOutOfFlowPosition() || style.IsFloating())
+  if (style.HasOutOfFlowPosition() ||
+      (style.IsFloating() && !style.IsFlexOrGridItem()))
     return false;
 
   // The user agent stylesheet (mediaControls.css) has
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 8e517f7..e075967 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -544,10 +544,8 @@
 
 bool LayoutObject::IsRenderedLegendInternal() const {
   DCHECK(IsBox());
-  DCHECK(IsHTMLLegendElement());
+  DCHECK(IsRenderedLegendCandidate());
 
-  if (IsFloatingOrOutOfFlowPositioned())
-    return false;
   const auto* parent = Parent();
   if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled()) {
     // If there is a rendered legend, it will be found inside the anonymous
@@ -2463,7 +2461,8 @@
 
     affects_parent_block_ =
         IsFloatingOrOutOfFlowPositioned() &&
-        (!new_style.IsFloating() && !new_style.HasOutOfFlowPosition()) &&
+        ((!new_style.IsFloating() || new_style.IsFlexOrGridItem()) &&
+         !new_style.HasOutOfFlowPosition()) &&
         Parent() &&
         (Parent()->IsLayoutBlockFlow() || Parent()->IsLayoutInline());
 
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 542b3b6..84c146b 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1222,13 +1222,23 @@
 
   bool IsHTMLLegendElement() const { return bitfields_.IsHTMLLegendElement(); }
 
+  // Returns true if this can be used as a rendered legend.
+  bool IsRenderedLegendCandidate() const {
+    // Note, we can't directly use LayoutObject::IsFloating() because in the
+    // case where the legend is a flex/grid item, LayoutObject::IsFloating()
+    // could get set to false, even if the legend's computed style indicates
+    // that it is floating.
+    return IsHTMLLegendElement() && !IsOutOfFlowPositioned() &&
+           !Style()->IsFloating();
+  }
+
   // Return true if this is the "rendered legend" of a fieldset. They get
   // special treatment, in that they establish a new formatting context, and
   // shrink to fit if no logical width is specified.
   //
   // This function is performance sensitive.
   inline bool IsRenderedLegend() const {
-    if (LIKELY(!IsHTMLLegendElement()))
+    if (LIKELY(!IsRenderedLegendCandidate()))
       return false;
 
     return IsRenderedLegendInternal();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
index c7ac5e46..69eaf05 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -917,13 +917,6 @@
 template <typename OffsetMappingBuilder>
 void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::
     AppendOutOfFlowPositioned(LayoutObject* layout_object) {
-  // This object may have |FirstInlineFragmentItemIndex| if it was a floating
-  // object in the previous layout. Clear here because OOF will not produce
-  // |NGFragmentItem|.
-  if (layout_object->IsInLayoutNGInlineFormattingContext() &&
-      RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
-    layout_object->ClearFirstInlineFragmentItemIndex();
-
   AppendOpaque(NGInlineItem::kOutOfFlowPositioned, kObjectReplacementCharacter,
                layout_object);
 }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc
index 621ab54..cc420435 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.cc
@@ -69,77 +69,6 @@
           PhysicalSize(new_line_height, rect.size.height)};
 }
 
-// TODO(tkent): Rename this function. 'LogicalBottom' should not be used in NG.
-LayoutUnit LastLineTextLogicalBottom(const NGPhysicalBoxFragment& container,
-                                     LayoutUnit default_value) {
-  const ComputedStyle& container_style = container.Style();
-  if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
-    if (!container.Items())
-      return default_value;
-    NGInlineCursor cursor(*container.Items());
-    cursor.MoveToLastLine();
-    const auto* line_item = cursor.CurrentItem();
-    if (!line_item)
-      return default_value;
-    DCHECK_EQ(line_item->Type(), NGFragmentItem::kLine);
-    DCHECK(line_item->LineBoxFragment());
-    PhysicalRect line_rect =
-        line_item->LineBoxFragment()->ScrollableOverflowForLine(
-            container, container_style, *line_item, cursor,
-            NGPhysicalFragment::kEmHeight);
-    return container.ConvertChildToLogical(line_rect).BlockEndOffset();
-  }
-
-  const NGPhysicalLineBoxFragment* last_line = nullptr;
-  PhysicalOffset last_line_offset;
-  for (const auto& child_link : container.PostLayoutChildren()) {
-    if (const auto* maybe_line =
-            DynamicTo<NGPhysicalLineBoxFragment>(*child_link)) {
-      last_line = maybe_line;
-      last_line_offset = child_link.offset;
-    }
-  }
-  if (!last_line)
-    return default_value;
-  PhysicalRect line_rect = last_line->ScrollableOverflow(
-      container, container_style, NGPhysicalFragment::kEmHeight);
-
-  line_rect.Move(last_line_offset);
-  return container.ConvertChildToLogical(line_rect).BlockEndOffset();
-}
-
-// TODO(tkent): Rename this function. 'LogicalTop' should not be used in NG.
-LayoutUnit FirstLineTextLogicalTop(const NGPhysicalBoxFragment& container,
-                                   LayoutUnit default_value) {
-  const ComputedStyle& container_style = container.Style();
-  if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
-    if (!container.Items())
-      return default_value;
-    NGInlineCursor cursor(*container.Items());
-    cursor.MoveToFirstLine();
-    const auto* line_item = cursor.CurrentItem();
-    if (!line_item)
-      return default_value;
-    DCHECK_EQ(line_item->Type(), NGFragmentItem::kLine);
-    DCHECK(line_item->LineBoxFragment());
-    PhysicalRect line_rect =
-        line_item->LineBoxFragment()->ScrollableOverflowForLine(
-            container, container_style, *line_item, cursor,
-            NGPhysicalFragment::kEmHeight);
-    return container.ConvertChildToLogical(line_rect).offset.block_offset;
-  }
-
-  for (const auto& child_link : container.PostLayoutChildren()) {
-    if (const auto* line = DynamicTo<NGPhysicalLineBoxFragment>(*child_link)) {
-      PhysicalRect line_rect = line->ScrollableOverflow(
-          container, container_style, NGPhysicalFragment::kEmHeight);
-      line_rect.Move(child_link.offset);
-      return container.ConvertChildToLogical(line_rect).offset.block_offset;
-    }
-  }
-  return default_value;
-}
-
 // See LayoutRubyRun::GetOverhang().
 NGAnnotationOverhang GetOverhang(const NGInlineItemResult& item) {
   DCHECK(RuntimeEnabledFeatures::LayoutNGRubyEnabled());
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h b/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h
index 8210083..ba5ef76 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h
@@ -13,25 +13,10 @@
 class ComputedStyle;
 class NGLineInfo;
 class NGLogicalLineItems;
-class NGPhysicalBoxFragment;
 struct NGInlineItemResult;
 struct NGLineHeightMetrics;
 struct PhysicalRect;
 
-// Returns the logical bottom offset of the last line text, relative to
-// |container| origin. This is used to decide ruby annotation box position.
-//
-// See NGBlockLayoutAlgorithm::LayoutRubyText().
-LayoutUnit LastLineTextLogicalBottom(const NGPhysicalBoxFragment& container,
-                                     LayoutUnit default_value);
-
-// Returns the logical top offset of the first line text, relative to
-// |container| origin. This is used to decide ruby annotation box position.
-//
-// See NGBlockLayoutAlgorithm::LayoutRubyText().
-LayoutUnit FirstLineTextLogicalTop(const NGPhysicalBoxFragment& container,
-                                   LayoutUnit default_value);
-
 // Adjust the specified |rect| of a text fragment for 'em' height.
 // This is called on computing scrollable overflow with kEmHeight.
 PhysicalRect AdjustTextRectForEmHeight(const PhysicalRect& rect,
diff --git a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc
index 7a172e9..19c1ffca 100644
--- a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc
@@ -71,6 +71,33 @@
   return InFlowChildCountIs(node, 2);
 }
 
+static bool IsPrescriptDelimiter(const NGBlockNode& block_node) {
+  auto* node = block_node.GetLayoutBox()->GetNode();
+  return node && IsA<MathMLElement>(node) &&
+         node->HasTagName(mathml_names::kMprescriptsTag);
+}
+
+// Valid according to:
+// https://mathml-refresh.github.io/mathml-core/#prescripts-and-tensor-indices-mmultiscripts
+inline bool IsValidMultiscript(const NGBlockNode& node) {
+  auto child = To<NGBlockNode>(FirstChildInFlow(node));
+  if (!child || IsPrescriptDelimiter(child))
+    return false;
+  bool number_of_scripts_is_even = true;
+  while (child) {
+    child = To<NGBlockNode>(NextSiblingInFlow(child));
+    if (!child)
+      continue;
+    if (IsPrescriptDelimiter(child)) {
+      if (!number_of_scripts_is_even)
+        return false;
+      continue;
+    }
+    number_of_scripts_is_even = !number_of_scripts_is_even;
+  }
+  return number_of_scripts_is_even;
+}
+
 bool IsValidMathMLScript(const NGBlockNode& node) {
   switch (node.ScriptType()) {
     case MathScriptType::kUnder:
@@ -81,6 +108,8 @@
     case MathScriptType::kSubSup:
     case MathScriptType::kUnderOver:
       return InFlowChildCountIs(node, 3);
+    case MathScriptType::kMultiscripts:
+      return IsValidMultiscript(node);
     default:
       return false;
   }
diff --git a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc
index f3715e7..bde7bd4bf 100644
--- a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.cc
@@ -15,6 +15,12 @@
 
 using MathConstants = OpenTypeMathSupport::MathConstants;
 
+static bool IsPrescriptDelimiter(const NGBlockNode& blockNode) {
+  auto* node = blockNode.GetLayoutBox()->GetNode();
+  return node && IsA<MathMLElement>(node) &&
+         node->HasTagName(mathml_names::kMprescriptsTag);
+}
+
 LayoutUnit GetSpaceAfterScript(const ComputedStyle& style) {
   return LayoutUnit(MathConstant(style, MathConstants::kSpaceAfterScript)
                         .value_or(style.FontSize() / 5));
@@ -88,10 +94,13 @@
 
 void NGMathScriptsLayoutAlgorithm::GatherChildren(
     NGBlockNode* base,
-    NGBlockNode* sub,
-    NGBlockNode* sup,
+    Vector<SubSupPair>* sub_sup_pairs,
+    NGBlockNode* prescripts,
+    unsigned* first_prescript_index,
     NGBoxFragmentBuilder* container_builder) const {
   auto script_type = Node().ScriptType();
+  bool number_of_scripts_is_even = true;
+  sub_sup_pairs->resize(1);
   for (NGLayoutInputNode child = Node().FirstChild(); child;
        child = child.NextSibling()) {
     NGBlockNode block_child = To<NGBlockNode>(child);
@@ -114,47 +123,73 @@
         // The second child is a postscript and there are no prescripts.
         // <msub> base subscript </msub>
         // <msup> base superscript </msup>
-        DCHECK(!*sub);
-        *sub = block_child;
+        DCHECK(!sub_sup_pairs->at(0).sub);
+        sub_sup_pairs->at(0).sub = block_child;
         continue;
       case MathScriptType::kSuper:
-        DCHECK(!*sup);
-        *sup = block_child;
+        DCHECK(!sub_sup_pairs->at(0).sup);
+        sub_sup_pairs->at(0).sup = block_child;
         continue;
       case MathScriptType::kSubSup:
         // These elements must have exactly three children.
         // The second and third children are postscripts and there are no
         // prescripts. <msubsup> base subscript superscript </msubsup>
-        if (!*sub) {
-          *sub = block_child;
+        if (!sub_sup_pairs->at(0).sub) {
+          sub_sup_pairs->at(0).sub = block_child;
         } else {
-          DCHECK(!*sup);
-          *sup = block_child;
+          DCHECK(!sub_sup_pairs->at(0).sup);
+          sub_sup_pairs->at(0).sup = block_child;
         }
         continue;
+      case MathScriptType::kMultiscripts: {
+        // The structure of mmultiscripts is specified here:
+        // https://mathml-refresh.github.io/mathml-core/#prescripts-and-tensor-indices-mmultiscripts
+        if (IsPrescriptDelimiter(block_child)) {
+          if (!number_of_scripts_is_even || *first_prescript_index > 0) {
+            NOTREACHED();
+            return;
+          }
+          *first_prescript_index = sub_sup_pairs->size() - 1;
+          *prescripts = block_child;
+          continue;
+        }
+        if (!sub_sup_pairs->back().sub) {
+          sub_sup_pairs->back().sub = block_child;
+        } else {
+          DCHECK(!sub_sup_pairs->back().sup);
+          sub_sup_pairs->back().sup = block_child;
+        }
+        number_of_scripts_is_even = !number_of_scripts_is_even;
+        if (number_of_scripts_is_even)
+          sub_sup_pairs->resize(sub_sup_pairs->size() + 1);
+        continue;
+      }
       default:
         NOTREACHED();
     }
   }
+  DCHECK(number_of_scripts_is_even);
 }
 
 // Determines ascent/descent and shift metrics depending on script type.
 NGMathScriptsLayoutAlgorithm::VerticalMetrics
 NGMathScriptsLayoutAlgorithm::GetVerticalMetrics(
     const ChildAndMetrics& base_metrics,
-    const ChildAndMetrics& sub_metrics,
-    const ChildAndMetrics& sup_metrics) const {
+    const ChildrenAndMetrics& sub_metrics,
+    const ChildrenAndMetrics& sup_metrics) const {
   ScriptsVerticalParameters parameters = GetScriptsVerticalParameters(Style());
   VerticalMetrics metrics;
 
   MathScriptType type = Node().ScriptType();
-  if (type == MathScriptType::kSub || type == MathScriptType::kSubSup) {
+  if (type == MathScriptType::kSub || type == MathScriptType::kSubSup ||
+      type == MathScriptType::kMultiscripts) {
     metrics.sub_shift =
         std::max(parameters.subscript_shift_down,
                  base_metrics.descent + parameters.subscript_baseline_drop_min);
   }
   LayoutUnit shift_up = parameters.superscript_shift_up;
-  if (type == MathScriptType::kSuper || type == MathScriptType::kSubSup) {
+  if (type == MathScriptType::kSuper || type == MathScriptType::kSubSup ||
+      type == MathScriptType::kMultiscripts) {
     if (Style().MathSuperscriptShiftStyle() ==
         EMathSuperscriptShiftStyle::kInline)
       shift_up = parameters.superscript_shift_up_cramped;
@@ -165,53 +200,58 @@
 
   switch (type) {
     case MathScriptType::kSub: {
-      metrics.descent = sub_metrics.descent;
-      metrics.sub_shift = std::max(
-          metrics.sub_shift, sub_metrics.ascent - parameters.subscript_top_max);
+      metrics.descent = sub_metrics[0].descent;
+      metrics.sub_shift =
+          std::max(metrics.sub_shift,
+                   sub_metrics[0].ascent - parameters.subscript_top_max);
     } break;
     case MathScriptType::kSuper: {
-      metrics.ascent = sup_metrics.ascent;
+      metrics.ascent = sup_metrics[0].ascent;
       metrics.sup_shift =
           std::max(metrics.sup_shift,
-                   parameters.superscript_bottom_min + sup_metrics.descent);
+                   parameters.superscript_bottom_min + sup_metrics[0].descent);
     } break;
+    case MathScriptType::kMultiscripts:
     case MathScriptType::kSubSup: {
-      metrics.ascent = std::max(metrics.ascent, sup_metrics.ascent);
-      metrics.descent = std::max(metrics.descent, sub_metrics.descent);
-      LayoutUnit sub_script_shift = std::max(
-          parameters.subscript_shift_down,
-          base_metrics.descent + parameters.subscript_baseline_drop_min);
-      sub_script_shift = std::max(
-          sub_script_shift, sub_metrics.ascent - parameters.subscript_top_max);
-      LayoutUnit sup_script_shift =
-          std::max(shift_up, base_metrics.ascent -
-                                 parameters.superscript_baseline_drop_max);
-      sup_script_shift =
-          std::max(sup_script_shift,
-                   parameters.superscript_bottom_min + sup_metrics.descent);
+      for (wtf_size_t idx = 0; idx < sub_metrics.size(); ++idx) {
+        metrics.ascent = std::max(metrics.ascent, sup_metrics[idx].ascent);
+        metrics.descent = std::max(metrics.descent, sub_metrics[idx].descent);
+        LayoutUnit sub_script_shift = std::max(
+            parameters.subscript_shift_down,
+            base_metrics.descent + parameters.subscript_baseline_drop_min);
+        sub_script_shift =
+            std::max(sub_script_shift,
+                     sub_metrics[idx].ascent - parameters.subscript_top_max);
+        LayoutUnit sup_script_shift =
+            std::max(shift_up, base_metrics.ascent -
+                                   parameters.superscript_baseline_drop_max);
+        sup_script_shift =
+            std::max(sup_script_shift, parameters.superscript_bottom_min +
+                                           sup_metrics[idx].descent);
 
-      LayoutUnit sub_super_script_gap =
-          (sub_script_shift - sub_metrics.ascent) +
-          (sup_script_shift - sup_metrics.descent);
-      if (sub_super_script_gap < parameters.sub_superscript_gap_min) {
-        // First, we try and push the superscript up.
-        LayoutUnit delta = parameters.superscript_bottom_max_with_subscript -
-                           (sup_script_shift - sup_metrics.descent);
-        if (delta > 0) {
-          delta = std::min(
-              delta, parameters.sub_superscript_gap_min - sub_super_script_gap);
-          sup_script_shift += delta;
-          sub_super_script_gap += delta;
-        }
-        // If that is not enough, we push the subscript down.
+        LayoutUnit sub_super_script_gap =
+            (sub_script_shift - sub_metrics[idx].ascent) +
+            (sup_script_shift - sup_metrics[idx].descent);
         if (sub_super_script_gap < parameters.sub_superscript_gap_min) {
-          sub_script_shift +=
-              parameters.sub_superscript_gap_min - sub_super_script_gap;
+          // First, we try and push the superscript up.
+          LayoutUnit delta = parameters.superscript_bottom_max_with_subscript -
+                             (sup_script_shift - sup_metrics[idx].descent);
+          if (delta > 0) {
+            delta = std::min(delta, parameters.sub_superscript_gap_min -
+                                        sub_super_script_gap);
+            sup_script_shift += delta;
+            sub_super_script_gap += delta;
+          }
+          // If that is not enough, we push the subscript down.
+          if (sub_super_script_gap < parameters.sub_superscript_gap_min) {
+            sub_script_shift +=
+                parameters.sub_superscript_gap_min - sub_super_script_gap;
+          }
         }
-      }
 
-      metrics.sub_shift = std::max(metrics.sub_shift, sub_script_shift);
-      metrics.sup_shift = std::max(metrics.sup_shift, sup_script_shift);
+        metrics.sub_shift = std::max(metrics.sub_shift, sub_script_shift);
+        metrics.sup_shift = std::max(metrics.sup_shift, sup_script_shift);
+      }
     } break;
     case MathScriptType::kOver:
     case MathScriptType::kUnder:
@@ -241,6 +281,7 @@
   child_and_metrics.descent = fragment.BlockSize() - child_and_metrics.ascent +
                               child_and_metrics.margins.block_end;
   child_and_metrics.ascent += child_and_metrics.margins.block_start;
+  child_and_metrics.node = child;
   return child_and_metrics;
 }
 
@@ -248,16 +289,22 @@
   DCHECK(!BreakToken());
 
   NGBlockNode base = nullptr;
-  NGBlockNode sub = nullptr;
-  NGBlockNode sup = nullptr;
-  GatherChildren(&base, &sub, &sup, &container_builder_);
+  NGBlockNode prescripts = nullptr;
+  Vector<SubSupPair> sub_sup_pairs;
+  wtf_size_t first_prescript_index = 0;
+  GatherChildren(&base, &sub_sup_pairs, &prescripts, &first_prescript_index,
+                 &container_builder_);
+  ChildrenAndMetrics sub_metrics, sup_metrics;
+  if (prescripts)
+    LayoutAndGetMetrics(prescripts);
+  for (auto sub_sup_pair : sub_sup_pairs) {
+    if (sub_sup_pair.sub)
+      sub_metrics.emplace_back(LayoutAndGetMetrics(sub_sup_pair.sub));
+    if (sub_sup_pair.sup)
+      sup_metrics.emplace_back(LayoutAndGetMetrics(sub_sup_pair.sup));
+  }
 
   ChildAndMetrics base_metrics = LayoutAndGetMetrics(base);
-  ChildAndMetrics sub_metrics, sup_metrics;
-  if (sub)
-    sub_metrics = LayoutAndGetMetrics(sub);
-  if (sup)
-    sup_metrics = LayoutAndGetMetrics(sup);
   VerticalMetrics metrics =
       GetVerticalMetrics(base_metrics, sub_metrics, sup_metrics);
 
@@ -270,9 +317,37 @@
   LayoutUnit descent =
       std::max(base_metrics.descent, metrics.descent + metrics.sub_shift);
   // TODO(rbuis): take into account italic correction.
-  LayoutUnit inline_offset =
-      content_start_offset.inline_offset + base_metrics.margins.inline_start;
+  LayoutUnit inline_offset = content_start_offset.inline_offset;
 
+  LayoutUnit space = GetSpaceAfterScript(Style());
+  // Position pre scripts if needed.
+  if (prescripts) {
+    for (wtf_size_t idx = first_prescript_index; idx < sub_metrics.size();
+         ++idx) {
+      auto& sub_metric = sub_metrics[idx];
+      auto& sup_metric = sup_metrics[idx];
+      LayoutUnit sub_sup_pair_inline_size =
+          std::max(sub_metric.inline_size, sup_metric.inline_size);
+      inline_offset += space + sub_sup_pair_inline_size;
+      LogicalOffset sub_offset(inline_offset - sub_metric.inline_size +
+                                   sub_metric.margins.inline_start,
+                               ascent + metrics.sub_shift - sub_metric.ascent +
+                                   sub_metric.margins.block_start);
+      container_builder_.AddChild(sub_metric.result->PhysicalFragment(),
+                                  sub_offset);
+      sub_metric.node.StoreMargins(ConstraintSpace(), sub_metric.margins);
+      LogicalOffset sup_offset(inline_offset - sup_metric.inline_size +
+                                   sup_metric.margins.inline_start,
+                               ascent - metrics.sup_shift - sup_metric.ascent +
+                                   sup_metric.margins.block_start);
+      container_builder_.AddChild(sup_metric.result->PhysicalFragment(),
+                                  sup_offset);
+      sup_metric.node.StoreMargins(ConstraintSpace(), sup_metric.margins);
+    }
+  } else {
+    first_prescript_index = std::max(sub_metrics.size(), sup_metrics.size());
+  }
+  inline_offset += base_metrics.margins.inline_start;
   LogicalOffset base_offset(
       inline_offset,
       ascent - base_metrics.ascent + base_metrics.margins.block_start);
@@ -281,21 +356,33 @@
   base.StoreMargins(ConstraintSpace(), base_metrics.margins);
   inline_offset += base_metrics.inline_size + base_metrics.margins.inline_end;
 
-  if (sub) {
-    LogicalOffset sub_offset(inline_offset + sub_metrics.margins.inline_start,
-                             ascent + metrics.sub_shift - sub_metrics.ascent +
-                                 sub_metrics.margins.block_start);
-    container_builder_.AddChild(sub_metrics.result->PhysicalFragment(),
-                                sub_offset);
-    sub.StoreMargins(ConstraintSpace(), sub_metrics.margins);
-  }
-  if (sup) {
-    LogicalOffset sup_offset(inline_offset + sup_metrics.margins.inline_start,
-                             ascent - metrics.sup_shift - sup_metrics.ascent +
-                                 sup_metrics.margins.block_start);
-    container_builder_.AddChild(sup_metrics.result->PhysicalFragment(),
-                                sup_offset);
-    sup.StoreMargins(ConstraintSpace(), sup_metrics.margins);
+  // Position post scripts if needed.
+  for (unsigned idx = 0; idx < first_prescript_index; ++idx) {
+    ChildAndMetrics sub_metric, sup_metric;
+    if (idx < sub_metrics.size())
+      sub_metric = sub_metrics[idx];
+    if (idx < sup_metrics.size())
+      sup_metric = sup_metrics[idx];
+
+    if (sub_metric.node) {
+      LogicalOffset sub_offset(inline_offset + sub_metric.margins.inline_start,
+                               ascent + metrics.sub_shift - sub_metric.ascent +
+                                   sub_metric.margins.block_start);
+      container_builder_.AddChild(sub_metric.result->PhysicalFragment(),
+                                  sub_offset);
+      sub_metric.node.StoreMargins(ConstraintSpace(), sub_metric.margins);
+    }
+    if (sup_metric.node) {
+      LogicalOffset sup_offset(inline_offset + sup_metric.margins.inline_start,
+                               ascent - metrics.sup_shift - sup_metric.ascent +
+                                   sup_metric.margins.block_start);
+      container_builder_.AddChild(sup_metric.result->PhysicalFragment(),
+                                  sup_offset);
+      sup_metric.node.StoreMargins(ConstraintSpace(), sup_metric.margins);
+    }
+    LayoutUnit sub_sup_pair_inline_size =
+        std::max(sub_metric.inline_size, sup_metric.inline_size);
+    inline_offset += space + sub_sup_pair_inline_size;
   }
 
   container_builder_.SetBaseline(ascent);
@@ -324,26 +411,30 @@
     return *result;
 
   NGBlockNode base = nullptr;
-  NGBlockNode sub = nullptr;
-  NGBlockNode sup = nullptr;
-  GatherChildren(&base, &sub, &sup);
+  NGBlockNode prescripts = nullptr;
+  Vector<SubSupPair> sub_sup_pairs;
+  unsigned first_prescript_index = 0;
+  GatherChildren(&base, &sub_sup_pairs, &prescripts, &first_prescript_index);
+  DCHECK_GE(sub_sup_pairs.size(), 1ul);
 
   MinMaxSizes sizes;
   bool depends_on_percentage_block_size = false;
 
   MinMaxSizesResult base_result =
       ComputeMinAndMaxContentContribution(Style(), base, child_input);
-  base_result.sizes += ComputeMinMaxMargins(Style(), base).InlineSum() +
-                       GetSpaceAfterScript(Style());
+  base_result.sizes += ComputeMinMaxMargins(Style(), base).InlineSum();
 
   sizes = base_result.sizes;
   depends_on_percentage_block_size |=
       base_result.depends_on_percentage_block_size;
 
+  LayoutUnit space = GetSpaceAfterScript(Style());
   switch (Node().ScriptType()) {
     case MathScriptType::kSub:
     case MathScriptType::kSuper: {
       // TODO(fwang): Take italic correction into account.
+      NGBlockNode sub = sub_sup_pairs[0].sub;
+      NGBlockNode sup = sub_sup_pairs[0].sup;
       auto first_post_script = sub ? sub : sup;
       auto first_post_script_result = ComputeMinAndMaxContentContribution(
           Style(), first_post_script, child_input);
@@ -351,28 +442,40 @@
           ComputeMinMaxMargins(Style(), first_post_script).InlineSum();
 
       sizes += first_post_script_result.sizes;
+      sizes += space;
       depends_on_percentage_block_size |=
           first_post_script_result.depends_on_percentage_block_size;
       break;
     }
-    case MathScriptType::kSubSup: {
+    case MathScriptType::kSubSup:
+    case MathScriptType::kMultiscripts: {
       // TODO(fwang): Take italic correction into account.
       MinMaxSizes sub_sup_pair_size;
-      auto sub_result =
-          ComputeMinAndMaxContentContribution(Style(), sub, child_input);
-      sub_result.sizes += ComputeMinMaxMargins(Style(), sub).InlineSum();
-      sub_sup_pair_size.Encompass(sub_result.sizes);
+      unsigned index = 0;
+      do {
+        auto sub = sub_sup_pairs[index].sub;
+        if (!sub)
+          continue;
+        auto sub_result =
+            ComputeMinAndMaxContentContribution(Style(), sub, child_input);
+        sub_result.sizes += ComputeMinMaxMargins(Style(), sub).InlineSum();
+        sub_sup_pair_size.Encompass(sub_result.sizes);
 
-      auto sup_result =
-          ComputeMinAndMaxContentContribution(Style(), sup, child_input);
-      sup_result.sizes += ComputeMinMaxMargins(Style(), sup).InlineSum();
-      sub_sup_pair_size.Encompass(sup_result.sizes);
+        auto sup = sub_sup_pairs[index].sup;
+        if (!sup)
+          continue;
+        auto sup_result =
+            ComputeMinAndMaxContentContribution(Style(), sup, child_input);
+        sup_result.sizes += ComputeMinMaxMargins(Style(), sup).InlineSum();
+        sub_sup_pair_size.Encompass(sup_result.sizes);
 
-      sizes += sub_sup_pair_size;
-      depends_on_percentage_block_size |=
-          sub_result.depends_on_percentage_block_size;
-      depends_on_percentage_block_size |=
-          sup_result.depends_on_percentage_block_size;
+        sizes += sub_sup_pair_size;
+        sizes += space;
+        depends_on_percentage_block_size |=
+            sub_result.depends_on_percentage_block_size;
+        depends_on_percentage_block_size |=
+            sup_result.depends_on_percentage_block_size;
+      } while (++index < sub_sup_pairs.size());
       break;
     }
     case MathScriptType::kUnder:
diff --git a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.h
index ce65ecd1d..aa750df66 100644
--- a/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/mathml/ng_math_scripts_layout_algorithm.h
@@ -22,15 +22,21 @@
   explicit NGMathScriptsLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
 
  private:
+  struct SubSupPair {
+    NGBlockNode sub = nullptr;
+    NGBlockNode sup = nullptr;
+  };
+
   void GatherChildren(NGBlockNode* base,
-                      NGBlockNode* sup,
-                      NGBlockNode* sub,
+                      Vector<SubSupPair>*,
+                      NGBlockNode* prescripts,
+                      unsigned* first_prescript_index,
                       NGBoxFragmentBuilder* = nullptr) const;
 
   MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const final;
 
   struct ChildAndMetrics {
-    STACK_ALLOCATED();
+    DISALLOW_NEW();
 
    public:
     scoped_refptr<const NGLayoutResult> result;
@@ -38,7 +44,9 @@
     LayoutUnit descent;
     LayoutUnit inline_size;
     NGBoxStrut margins;
+    NGBlockNode node = nullptr;
   };
+  typedef Vector<ChildAndMetrics, 4> ChildrenAndMetrics;
 
   ChildAndMetrics LayoutAndGetMetrics(NGBlockNode child) const;
 
@@ -52,9 +60,10 @@
     LayoutUnit descent;
     NGBoxStrut margins;
   };
-  VerticalMetrics GetVerticalMetrics(const ChildAndMetrics& base_metrics,
-                                     const ChildAndMetrics& sub_metrics,
-                                     const ChildAndMetrics& sup_metrics) const;
+  VerticalMetrics GetVerticalMetrics(
+      const ChildAndMetrics& base_metrics,
+      const ChildrenAndMetrics& sub_metrics,
+      const ChildrenAndMetrics& sup_metrics) const;
 
   scoped_refptr<const NGLayoutResult> Layout() final;
 };
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index b384cb6..99663c02 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_ruby_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
 #include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_child_iterator.h"
@@ -2795,20 +2794,26 @@
   LayoutUnit ruby_text_box_top;
   const NGPhysicalBoxFragment& ruby_text_fragment =
       To<NGPhysicalBoxFragment>(result->PhysicalFragment());
+  const LogicalRect ruby_text_box = ruby_text_fragment.ConvertChildToLogical(
+      ruby_text_fragment.ScrollableOverflow(NGPhysicalFragment::kEmHeight));
   RubyPosition block_start_position = Style().IsFlippedLinesWritingMode()
                                           ? RubyPosition::kAfter
                                           : RubyPosition::kBefore;
   if (Style().GetRubyPosition() == block_start_position) {
-    LayoutUnit last_line_ruby_text_bottom = LastLineTextLogicalBottom(
-        ruby_text_fragment, result->IntrinsicBlockSize());
+    LayoutUnit last_line_ruby_text_bottom = ruby_text_box.BlockEndOffset();
 
     // Find a fragment for RubyBase, and get the top of text in it.
     LayoutUnit first_line_top;
     for (const auto& child : container_builder_.Children()) {
       if (const auto* layout_object = child.fragment->GetLayoutObject()) {
         if (layout_object->IsRubyBase()) {
-          first_line_top = FirstLineTextLogicalTop(
-              To<NGPhysicalBoxFragment>(*child.fragment), LayoutUnit());
+          const auto& ruby_base_fragment =
+              To<NGPhysicalBoxFragment>(*child.fragment);
+          first_line_top =
+              ruby_base_fragment
+                  .ConvertChildToLogical(ruby_base_fragment.ScrollableOverflow(
+                      NGPhysicalFragment::kEmHeight))
+                  .offset.block_offset;
           first_line_top += child.offset.block_offset;
           break;
         }
@@ -2816,13 +2821,11 @@
     }
     ruby_text_box_top = first_line_top - last_line_ruby_text_bottom;
     const LayoutUnit ruby_text_top =
-        ruby_text_box_top +
-        FirstLineTextLogicalTop(ruby_text_fragment, LayoutUnit());
+        ruby_text_box_top + ruby_text_box.offset.block_offset;
     if (ruby_text_top < LayoutUnit())
       container_builder_.SetAnnotationOverflow(ruby_text_top);
   } else {
-    LayoutUnit first_line_ruby_text_top =
-        FirstLineTextLogicalTop(ruby_text_fragment, LayoutUnit());
+    LayoutUnit first_line_ruby_text_top = ruby_text_box.offset.block_offset;
 
     // Find a fragment for RubyBase, and get the bottom of text in it.
     LayoutUnit last_line_bottom;
@@ -2834,8 +2837,13 @@
               child.fragment->Size()
                   .ConvertToLogical(Style().GetWritingMode())
                   .block_size;
-          last_line_bottom = LastLineTextLogicalBottom(
-              To<NGPhysicalBoxFragment>(*child.fragment), base_block_size);
+          const auto& ruby_base_fragment =
+              To<NGPhysicalBoxFragment>(*child.fragment);
+          last_line_bottom =
+              ruby_base_fragment
+                  .ConvertChildToLogical(ruby_base_fragment.ScrollableOverflow(
+                      NGPhysicalFragment::kEmHeight))
+                  .BlockEndOffset();
           last_line_bottom += child.offset.block_offset;
           base_logical_bottom = child.offset.block_offset + base_block_size;
           break;
@@ -2843,14 +2851,9 @@
       }
     }
     ruby_text_box_top = last_line_bottom - first_line_ruby_text_top;
-    LayoutUnit ruby_text_height =
-        ruby_text_fragment.Size()
-            .ConvertToLogical(Style().GetWritingMode())
-            .block_size;
-    ruby_text_height =
-        LastLineTextLogicalBottom(ruby_text_fragment, ruby_text_height);
-    LayoutUnit logical_bottom_overflow =
-        ruby_text_box_top + ruby_text_height - base_logical_bottom;
+    LayoutUnit logical_bottom_overflow = ruby_text_box_top +
+                                         ruby_text_box.BlockEndOffset() -
+                                         base_logical_bottom;
     if (logical_bottom_overflow > LayoutUnit())
       container_builder_.SetAnnotationOverflow(logical_bottom_overflow);
   }
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc
index 58231ff8..094f56b5 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc
@@ -79,20 +79,15 @@
   if (paint.IsNone())
     return SVGPaintDescription();
 
-  Color color = paint.GetColor();
+  Color color = style.ResolvedColor(paint.GetColor());
   bool has_color = paint.HasColor();
 
-  if (paint.HasCurrentColor())
-    color = style.VisitedDependentColor(GetCSSPropertyColor());
-
   if (style.InsideLink() == EInsideLink::kInsideVisitedLink) {
     // FIXME: This code doesn't support the uri component of the visited link
     // paint, https://bugs.webkit.org/show_bug.cgi?id=70006
-
-    // If the color (primary or fallback) is 'currentcolor', then |color|
-    // already contains the 'visited color'.
-    if (!visited_paint.HasUrl() && !visited_paint.HasCurrentColor()) {
-      const Color& visited_color = visited_paint.GetColor();
+    if (!visited_paint.HasUrl()) {
+      const Color& visited_color =
+          style.ResolvedColor(visited_paint.GetColor());
       color = Color(visited_color.Red(), visited_color.Green(),
                     visited_color.Blue(), color.Alpha());
       has_color = true;
diff --git a/third_party/blink/renderer/core/loader/appcache/application_cache.idl b/third_party/blink/renderer/core/loader/appcache/application_cache.idl
index 0efa107..76923b3 100644
--- a/third_party/blink/renderer/core/loader/appcache/application_cache.idl
+++ b/third_party/blink/renderer/core/loader/appcache/application_cache.idl
@@ -29,7 +29,7 @@
     Exposed=Window,
     DoNotCheckConstants,
     RuntimeEnabled=AppCache,
-    SecureContext=RestrictAppCacheToSecureContexts
+    SecureContext
 ] interface ApplicationCache : EventTarget {
     // update status
     const unsigned short UNCACHED = 0;
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index dd5581fe..96c6a98 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -1307,9 +1307,8 @@
   //
   // It is important to forward all the CSP data before loading the response
   // body, otherwise some loaded content might not be blocked.
-  frame_->GetSecurityContext()
-      ->GetContentSecurityPolicy()
-      ->ReportAccumulatedHeaders(frame_);
+  frame_->DomWindow()->GetContentSecurityPolicy()->ReportAccumulatedHeaders(
+      frame_);
 
   CreateParserPostCommit();
 
@@ -1366,7 +1365,7 @@
 }
 
 void DocumentLoader::DidInstallNewDocument(Document* document) {
-  document->BindContentSecurityPolicy();
+  frame_->DomWindow()->BindContentSecurityPolicy();
 
   if (history_item_ && IsBackForwardLoadType(load_type_))
     document->SetStateForNewControls(history_item_->GetDocumentState());
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index cb6b831..2015bfff 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -872,7 +872,7 @@
     const {
   if (GetResourceFetcherProperties().IsDetached())
     return frozen_state_->content_security_policy;
-  return document_->GetContentSecurityPolicy();
+  return document_->domWindow()->GetContentSecurityPolicy();
 }
 
 void FrameFetchContext::AddConsoleMessage(ConsoleMessage* message) const {
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index eb588be..bd40d7ca 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -1734,7 +1734,7 @@
   // Document.
   if (commit_reason == CommitReason::kXSLT) {
     ContentSecurityPolicy* csp = MakeGarbageCollected<ContentSecurityPolicy>();
-    csp->CopyStateFrom(frame_->GetDocument()->GetContentSecurityPolicy());
+    csp->CopyStateFrom(frame_->DomWindow()->GetContentSecurityPolicy());
     return csp;
   }
 
diff --git a/third_party/blink/renderer/core/loader/http_equiv.cc b/third_party/blink/renderer/core/loader/http_equiv.cc
index b918b93..aa3e19a 100644
--- a/third_party/blink/renderer/core/loader/http_equiv.cc
+++ b/third_party/blink/renderer/core/loader/http_equiv.cc
@@ -90,7 +90,7 @@
   if (EqualIgnoringASCIICase(equiv, "default-style")) {
     ProcessHttpEquivDefaultStyle(document, content);
   } else if (EqualIgnoringASCIICase(equiv, "refresh")) {
-    ProcessHttpEquivRefresh(document, content, element);
+    ProcessHttpEquivRefresh(document.domWindow(), content, element);
   } else if (EqualIgnoringASCIICase(equiv, "set-cookie")) {
     ProcessHttpEquivSetCookie(document, content, element);
   } else if (EqualIgnoringASCIICase(equiv, "content-language")) {
@@ -108,10 +108,12 @@
   } else if (EqualIgnoringASCIICase(equiv, "content-security-policy") ||
              EqualIgnoringASCIICase(equiv,
                                     "content-security-policy-report-only")) {
-    if (in_document_head_element)
-      ProcessHttpEquivContentSecurityPolicy(document, equiv, content);
-    else
-      document.GetContentSecurityPolicy()->ReportMetaOutsideHead(content);
+    if (in_document_head_element) {
+      ProcessHttpEquivContentSecurityPolicy(document.domWindow(), equiv,
+                                            content);
+    } else if (auto* window = document.domWindow()) {
+      window->GetContentSecurityPolicy()->ReportMetaOutsideHead(content);
+    }
   } else if (EqualIgnoringASCIICase(equiv, http_names::kOriginTrial)) {
     if (in_document_head_element) {
       ProcessHttpEquivOriginTrial(document.domWindow(), content);
@@ -120,20 +122,20 @@
 }
 
 void HttpEquiv::ProcessHttpEquivContentSecurityPolicy(
-    Document& document,
+    LocalDOMWindow* window,
     const AtomicString& equiv,
     const AtomicString& content) {
-  if (document.ImportLoader())
+  if (!window || !window->GetFrame())
     return;
-  if (document.GetSettings() && document.GetSettings()->BypassCSP())
+  if (window->GetFrame()->GetSettings()->BypassCSP())
     return;
   if (EqualIgnoringASCIICase(equiv, "content-security-policy")) {
-    document.GetContentSecurityPolicy()->DidReceiveHeader(
+    window->GetContentSecurityPolicy()->DidReceiveHeader(
         content, network::mojom::ContentSecurityPolicyType::kEnforce,
         network::mojom::ContentSecurityPolicySource::kMeta);
   } else if (EqualIgnoringASCIICase(equiv,
                                     "content-security-policy-report-only")) {
-    document.GetContentSecurityPolicy()->DidReceiveHeader(
+    window->GetContentSecurityPolicy()->DidReceiveHeader(
         content, network::mojom::ContentSecurityPolicyType::kReport,
         network::mojom::ContentSecurityPolicySource::kMeta);
   } else {
@@ -194,19 +196,22 @@
   window->GetOriginTrialContext()->AddToken(content);
 }
 
-void HttpEquiv::ProcessHttpEquivRefresh(Document& document,
+void HttpEquiv::ProcessHttpEquivRefresh(LocalDOMWindow* window,
                                         const AtomicString& content,
                                         Element* element) {
-  UseCounter::Count(document, WebFeature::kMetaRefresh);
-  if (!document.GetContentSecurityPolicy()->AllowInline(
+  if (!window)
+    return;
+  UseCounter::Count(window, WebFeature::kMetaRefresh);
+  if (!window->GetContentSecurityPolicy()->AllowInline(
           ContentSecurityPolicy::InlineType::kScript, element, "" /* content */,
           "" /* nonce */, NullURL(), OrdinalNumber(),
           ReportingDisposition::kSuppressReporting)) {
-    UseCounter::Count(document,
+    UseCounter::Count(window,
                       WebFeature::kMetaRefreshWhenCSPBlocksInlineScript);
   }
 
-  document.MaybeHandleHttpRefresh(content, Document::kHttpRefreshFromMetaTag);
+  window->document()->MaybeHandleHttpRefresh(content,
+                                             Document::kHttpRefreshFromMetaTag);
 }
 
 void HttpEquiv::ProcessHttpEquivSetCookie(Document& document,
diff --git a/third_party/blink/renderer/core/loader/http_equiv.h b/third_party/blink/renderer/core/loader/http_equiv.h
index c722a59e..72377bc 100644
--- a/third_party/blink/renderer/core/loader/http_equiv.h
+++ b/third_party/blink/renderer/core/loader/http_equiv.h
@@ -37,14 +37,14 @@
                                            const AtomicString& content);
   static void ProcessHttpEquivOriginTrial(LocalDOMWindow*,
                                           const AtomicString& content);
-  static void ProcessHttpEquivRefresh(Document&,
+  static void ProcessHttpEquivRefresh(LocalDOMWindow*,
                                       const AtomicString& content,
                                       Element*);
   static void ProcessHttpEquivSetCookie(Document&,
                                         const AtomicString& content,
                                         Element*);
   static void ProcessHttpEquivContentSecurityPolicy(
-      Document&,
+      LocalDOMWindow*,
       const AtomicString& equiv,
       const AtomicString& content);
   static void ProcessHttpEquivAcceptCH(Document&, const AtomicString& content);
diff --git a/third_party/blink/renderer/core/loader/link_loader_test.cc b/third_party/blink/renderer/core/loader/link_loader_test.cc
index 40272f4c..b0e41958 100644
--- a/third_party/blink/renderer/core/loader/link_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/link_loader_test.cc
@@ -14,6 +14,7 @@
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/html/link_rel_attribute.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
@@ -370,8 +371,9 @@
 
 TEST_P(LinkLoaderPreloadNonceTest, Preload) {
   const auto& test_case = GetParam();
-  dummy_page_holder_->GetDocument()
-      .GetContentSecurityPolicy()
+  dummy_page_holder_->GetFrame()
+      .DomWindow()
+      ->GetContentSecurityPolicy()
       ->DidReceiveHeader(test_case.content_security_policy,
                          network::mojom::ContentSecurityPolicyType::kEnforce,
                          network::mojom::ContentSecurityPolicySource::kHTTP);
diff --git a/third_party/blink/renderer/core/mathml/mathml_element.cc b/third_party/blink/renderer/core/mathml/mathml_element.cc
index eda5fc5..dd78a14e 100644
--- a/third_party/blink/renderer/core/mathml/mathml_element.cc
+++ b/third_party/blink/renderer/core/mathml/mathml_element.cc
@@ -118,7 +118,8 @@
     return base::nullopt;
   auto value = FastGetAttribute(attr_name);
   const CSSPrimitiveValue* parsed_value = CSSParser::ParseLengthPercentage(
-      value, StrictCSSParserContext(GetDocument().GetSecureContextMode()));
+      value,
+      StrictCSSParserContext(GetExecutionContext()->GetSecureContextMode()));
   if (!parsed_value || parsed_value->IsCalculated())
     return base::nullopt;
   return parsed_value->ConvertToLength(conversion_data);
diff --git a/third_party/blink/renderer/core/mathml/mathml_scripts_element.cc b/third_party/blink/renderer/core/mathml/mathml_scripts_element.cc
index d754a1d..d8c4cd0 100644
--- a/third_party/blink/renderer/core/mathml/mathml_scripts_element.cc
+++ b/third_party/blink/renderer/core/mathml/mathml_scripts_element.cc
@@ -17,8 +17,10 @@
     return MathScriptType::kUnder;
   if (tagName == mathml_names::kMoverTag)
     return MathScriptType::kOver;
-  DCHECK(tagName == mathml_names::kMunderoverTag);
-  return MathScriptType::kUnderOver;
+  if (tagName == mathml_names::kMunderoverTag)
+    return MathScriptType::kUnderOver;
+  DCHECK_EQ(tagName, mathml_names::kMmultiscriptsTag);
+  return MathScriptType::kMultiscripts;
 }
 
 MathMLScriptsElement::MathMLScriptsElement(const QualifiedName& tagName,
diff --git a/third_party/blink/renderer/core/mathml/mathml_scripts_element.h b/third_party/blink/renderer/core/mathml/mathml_scripts_element.h
index 5ad049a1..ddea0b9 100644
--- a/third_party/blink/renderer/core/mathml/mathml_scripts_element.h
+++ b/third_party/blink/renderer/core/mathml/mathml_scripts_element.h
@@ -11,7 +11,15 @@
 
 class Document;
 
-enum class MathScriptType { kSub, kSuper, kSubSup, kUnder, kOver, kUnderOver };
+enum class MathScriptType {
+  kSub,
+  kSuper,
+  kSubSup,
+  kMultiscripts,
+  kUnder,
+  kOver,
+  kUnderOver
+};
 
 class CORE_EXPORT MathMLScriptsElement : public MathMLElement {
  public:
@@ -39,7 +47,8 @@
            mathml_element.HasTagName(mathml_names::kMunderoverTag) ||
            mathml_element.HasTagName(mathml_names::kMsubTag) ||
            mathml_element.HasTagName(mathml_names::kMsupTag) ||
-           mathml_element.HasTagName(mathml_names::kMsubsupTag);
+           mathml_element.HasTagName(mathml_names::kMsubsupTag) ||
+           mathml_element.HasTagName(mathml_names::kMmultiscriptsTag);
   }
 };
 
diff --git a/third_party/blink/renderer/core/mathml/mathml_tag_names.json5 b/third_party/blink/renderer/core/mathml/mathml_tag_names.json5
index e3cd91b..dcc7157e 100644
--- a/third_party/blink/renderer/core/mathml/mathml_tag_names.json5
+++ b/third_party/blink/renderer/core/mathml/mathml_tag_names.json5
@@ -60,6 +60,14 @@
       interfaceName: "MathMLScriptsElement",
     },
     {
+      name: "mmultiscripts",
+      interfaceName: "MathMLScriptsElement",
+    },
+    {
+      name: "mprescripts",
+      interfaceName: "MathMLRowElement",
+    },
+    {
       name: "mi",
       interfaceName: "MathMLElement",
     },
@@ -111,5 +119,9 @@
       name: "semantics",
       interfaceName: "MathMLRowElement",
     },
+    {
+      name: "none",
+      interfaceName: "MathMLRowElement",
+    },
   ]
 }
diff --git a/third_party/blink/renderer/core/page/link_highlight.cc b/third_party/blink/renderer/core/page/link_highlight.cc
index 9d7882d..984652f 100644
--- a/third_party/blink/renderer/core/page/link_highlight.cc
+++ b/third_party/blink/renderer/core/page/link_highlight.cc
@@ -54,7 +54,8 @@
   DCHECK(!node->IsTextNode());
 
   Color highlight_color =
-      node->GetLayoutObject()->StyleRef().TapHighlightColor();
+      node->GetLayoutObject()->StyleRef().VisitedDependentColor(
+          GetCSSPropertyWebkitTapHighlightColor());
   // Safari documentation for -webkit-tap-highlight-color says if the
   // specified color has 0 alpha, then tap highlighting is disabled.
   // http://developer.apple.com/library/safari/#documentation/appleapplications/reference/safaricssref/articles/standardcssproperties.html
diff --git a/third_party/blink/renderer/core/paint/clip_path_clipper.cc b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
index 2091d94..fdd4d1a 100644
--- a/third_party/blink/renderer/core/paint/clip_path_clipper.cc
+++ b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
@@ -115,17 +115,6 @@
   return true;
 }
 
-ClipPathClipper::ClipPathClipper(GraphicsContext& context,
-                                 const LayoutObject& layout_object,
-                                 const DisplayItemClient& display_item_client,
-                                 const PhysicalOffset& paint_offset)
-    : context_(context),
-      layout_object_(layout_object),
-      display_item_client_(display_item_client),
-      paint_offset_(paint_offset) {
-  DCHECK(layout_object.StyleRef().ClipPath());
-}
-
 static AffineTransform MaskToContentTransform(
     const LayoutSVGResourceClipper& resource_clipper,
     bool is_svg_child,
@@ -144,81 +133,13 @@
   return mask_to_content;
 }
 
-ClipPathClipper::~ClipPathClipper() {
-  const auto* properties = layout_object_.FirstFragment().PaintProperties();
-  if (!properties || !properties->ClipPath())
-    return;
-  ScopedPaintChunkProperties scoped_properties(
-      context_.GetPaintController(),
-      layout_object_.FirstFragment().ClipPathProperties(), display_item_client_,
-      DisplayItem::kSVGClip);
-
-  bool is_svg_child = layout_object_.IsSVGChild();
-  FloatRect reference_box = LocalReferenceBox(layout_object_);
-
-  if (DrawingRecorder::UseCachedDrawingIfPossible(
-          context_, display_item_client_, DisplayItem::kSVGClip))
-    return;
-  DrawingRecorder recorder(context_, display_item_client_,
-                           DisplayItem::kSVGClip);
-  context_.Save();
-  context_.Translate(paint_offset_.left, paint_offset_.top);
-
-  bool is_first = true;
-  bool rest_of_the_chain_already_appled = false;
-  const LayoutObject* current_object = &layout_object_;
-  while (!rest_of_the_chain_already_appled && current_object) {
-    const ClipPathOperation* clip_path = current_object->StyleRef().ClipPath();
-    if (!clip_path)
-      break;
-    LayoutSVGResourceClipper* resource_clipper = nullptr;
-    if (!IsClipPathOperationValid(*clip_path, *current_object,
-                                  resource_clipper))
-      break;
-
-    if (is_first)
-      context_.Save();
-    else
-      context_.BeginLayer(1.f, SkBlendMode::kDstIn);
-
-    // We wouldn't have reached here if the current clip-path is a shape,
-    // because it would have been applied as path-based clip already.
-    DCHECK(resource_clipper);
-    DCHECK_EQ(clip_path->GetType(), ClipPathOperation::REFERENCE);
-    if (resource_clipper->StyleRef().ClipPath()) {
-      // Try to apply nested clip-path as path-based clip.
-      bool unused;
-      if (base::Optional<Path> path = PathBasedClip(
-              *resource_clipper, is_svg_child, reference_box, unused)) {
-        context_.ClipPath(path->GetSkPath(), kAntiAliased);
-        rest_of_the_chain_already_appled = true;
-      }
-    }
-    context_.ConcatCTM(
-        MaskToContentTransform(*resource_clipper, is_svg_child, reference_box));
-    context_.DrawRecord(resource_clipper->CreatePaintRecord());
-
-    if (is_first)
-      context_.Restore();
-    else
-      context_.EndLayer();
-
-    is_first = false;
-    current_object = resource_clipper;
-  }
-  context_.Restore();
-}
-
-base::Optional<Path> ClipPathClipper::PathBasedClip(
+static base::Optional<Path> PathBasedClipInternal(
     const LayoutObject& clip_path_owner,
     bool is_svg_child,
-    const FloatRect& reference_box,
-    bool& is_valid) {
+    const FloatRect& reference_box) {
   const ClipPathOperation& clip_path = *clip_path_owner.StyleRef().ClipPath();
   LayoutSVGResourceClipper* resource_clipper = nullptr;
-  is_valid =
-      IsClipPathOperationValid(clip_path, clip_path_owner, resource_clipper);
-  if (!is_valid)
+  if (!IsClipPathOperationValid(clip_path, clip_path_owner, resource_clipper))
     return base::nullopt;
 
   if (resource_clipper) {
@@ -233,7 +154,95 @@
 
   DCHECK_EQ(clip_path.GetType(), ClipPathOperation::SHAPE);
   auto& shape = To<ShapeClipPathOperation>(clip_path);
-  return base::Optional<Path>(shape.GetPath(reference_box));
+  return shape.GetPath(reference_box);
+}
+
+void ClipPathClipper::PaintClipPathAsMaskImage(
+    GraphicsContext& context,
+    const LayoutObject& layout_object,
+    const DisplayItemClient& display_item_client,
+    const PhysicalOffset& paint_offset) {
+  const auto* properties = layout_object.FirstFragment().PaintProperties();
+  DCHECK(properties);
+  DCHECK(properties->MaskClip());
+  DCHECK(properties->ClipPathMask());
+  PropertyTreeStateOrAlias property_tree_state(
+      properties->MaskClip()->LocalTransformSpace(), *properties->MaskClip(),
+      *properties->ClipPathMask());
+  ScopedPaintChunkProperties scoped_properties(
+      context.GetPaintController(), property_tree_state, display_item_client,
+      DisplayItem::kSVGClip);
+
+  if (DrawingRecorder::UseCachedDrawingIfPossible(context, display_item_client,
+                                                  DisplayItem::kSVGClip))
+    return;
+
+  DrawingRecorder recorder(context, display_item_client, DisplayItem::kSVGClip);
+  context.Save();
+  context.Translate(paint_offset.left, paint_offset.top);
+
+  bool is_svg_child = layout_object.IsSVGChild();
+  FloatRect reference_box = LocalReferenceBox(layout_object);
+  bool is_first = true;
+  bool rest_of_the_chain_already_appled = false;
+  const LayoutObject* current_object = &layout_object;
+  while (!rest_of_the_chain_already_appled && current_object) {
+    const ClipPathOperation* clip_path = current_object->StyleRef().ClipPath();
+    if (!clip_path)
+      break;
+    LayoutSVGResourceClipper* resource_clipper = nullptr;
+    if (!IsClipPathOperationValid(*clip_path, *current_object,
+                                  resource_clipper))
+      break;
+
+    if (is_first)
+      context.Save();
+    else
+      context.BeginLayer(1.f, SkBlendMode::kDstIn);
+
+    // We wouldn't have reached here if the current clip-path is a shape,
+    // because it would have been applied as path-based clip already.
+    DCHECK(resource_clipper);
+    DCHECK_EQ(clip_path->GetType(), ClipPathOperation::REFERENCE);
+    if (resource_clipper->StyleRef().ClipPath()) {
+      // Try to apply nested clip-path as path-based clip.
+      if (const base::Optional<Path>& path = PathBasedClipInternal(
+              *resource_clipper, is_svg_child, reference_box)) {
+        context.ClipPath(path->GetSkPath(), kAntiAliased);
+        rest_of_the_chain_already_appled = true;
+      }
+    }
+    context.ConcatCTM(
+        MaskToContentTransform(*resource_clipper, is_svg_child, reference_box));
+    context.DrawRecord(resource_clipper->CreatePaintRecord());
+
+    if (is_first)
+      context.Restore();
+    else
+      context.EndLayer();
+
+    is_first = false;
+    current_object = resource_clipper;
+  }
+  context.Restore();
+}
+
+bool ClipPathClipper::ShouldUseMaskBasedClip(const LayoutObject& object) {
+  if (object.IsText())
+    return false;
+  const ClipPathOperation* clip_path = object.StyleRef().ClipPath();
+  if (!clip_path)
+    return false;
+  LayoutSVGResourceClipper* resource_clipper = nullptr;
+  if (!IsClipPathOperationValid(*clip_path, object, resource_clipper))
+    return false;
+  return resource_clipper && !resource_clipper->AsPath();
+}
+
+base::Optional<Path> ClipPathClipper::PathBasedClip(
+    const LayoutObject& clip_path_owner) {
+  return PathBasedClipInternal(clip_path_owner, clip_path_owner.IsSVGChild(),
+                               LocalReferenceBox(clip_path_owner));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/clip_path_clipper.h b/third_party/blink/renderer/core/paint/clip_path_clipper.h
index a52caedb..2e9de92 100644
--- a/third_party/blink/renderer/core/paint/clip_path_clipper.h
+++ b/third_party/blink/renderer/core/paint/clip_path_clipper.h
@@ -7,7 +7,6 @@
 
 #include "base/optional.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/graphics/path.h"
 
@@ -16,46 +15,39 @@
 class DisplayItemClient;
 class GraphicsContext;
 class LayoutObject;
+struct PhysicalOffset;
 
 class CORE_EXPORT ClipPathClipper {
-  DISALLOW_NEW();
+  STATIC_ONLY(ClipPathClipper);
 
  public:
-  ClipPathClipper(GraphicsContext&,
-                  const LayoutObject&,
-                  const DisplayItemClient&,
-                  const PhysicalOffset& paint_offset);
-  ~ClipPathClipper();
+  static void PaintClipPathAsMaskImage(GraphicsContext&,
+                                       const LayoutObject&,
+                                       const DisplayItemClient&,
+                                       const PhysicalOffset& paint_offset);
 
   // Returns the reference box used by CSS clip-path. For HTML objects,
   // this is the border box of the element. For SVG objects this is the
   // object bounding box.
   static FloatRect LocalReferenceBox(const LayoutObject&);
+
   // Returns the bounding box of the computed clip path, which could be
   // smaller or bigger than the reference box. Returns nullopt if the
   // clip path is invalid.
   static base::Optional<FloatRect> LocalClipPathBoundingBox(
       const LayoutObject&);
+
+  // Returns true if the object has a clip-path that must be implemented with
+  // a mask.
+  static bool ShouldUseMaskBasedClip(const LayoutObject&);
+
   // The argument |clip_path_owner| is the layout object that owns the
   // ClipPathOperation we are currently processing. Usually it is the
   // same as the layout object getting clipped, but in the case of nested
   // clip-path, it could be one of the SVG clip path in the chain.
-  // The output is tri-state:
-  // is_valid == false: The clip path is invalid. Always returns nullopt.
-  // is_valid == true && return == nullopt: The clip path is valid,
-  //   but cannot use path-based clip.
-  // is_valid == true && return != nullopt: The clip path can be applied
-  //   as path-based clip, and the computed path is returned.
-  static base::Optional<Path> PathBasedClip(const LayoutObject& clip_path_owner,
-                                            bool is_svg_child,
-                                            const FloatRect& reference_box,
-                                            bool& is_valid);
-
- private:
-  GraphicsContext& context_;
-  const LayoutObject& layout_object_;
-  const DisplayItemClient& display_item_client_;
-  PhysicalOffset paint_offset_;
+  // Returns the path if the clip-path can use path-based clip.
+  static base::Optional<Path> PathBasedClip(
+      const LayoutObject& clip_path_owner);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 5fd8004..edde229 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -427,9 +427,9 @@
   bool has_mask =
       CSSMaskPainter::MaskBoundingBox(GetLayoutObject(), PhysicalOffset())
           .has_value();
-  bool has_clip_path =
-      ClipPathClipper::LocalClipPathBoundingBox(GetLayoutObject()).has_value();
-  if (UpdateMaskLayer(has_mask || has_clip_path))
+  bool has_mask_based_clip_path =
+      ClipPathClipper::ShouldUseMaskBasedClip(GetLayoutObject());
+  if (UpdateMaskLayer(has_mask || has_mask_based_clip_path))
     layer_config_changed = true;
 
   if (layer_config_changed)
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
index cabdc25..afe9771 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.cc
@@ -192,9 +192,13 @@
   }
   if (!descendant_has_direct_compositing_reason &&
       layer->GetLayoutObject().IsLayoutEmbeddedContent()) {
-    if (ToLayoutEmbeddedContent(layer->GetLayoutObject())
-            .ContentDocumentIsCompositing()) {
-      descendant_has_direct_compositing_reason = true;
+    if (LayoutView* root_of_child =
+            ToLayoutEmbeddedContent(layer->GetLayoutObject())
+                .ChildLayoutView()) {
+      if (CompositingInputsUpdater(root_of_child->Layer(),
+                                   root_of_child->Layer())
+              .LayerOrDescendantShouldBeComposited(root_of_child->Layer()))
+        descendant_has_direct_compositing_reason = true;
     }
   }
   layer->SetDescendantHasDirectOrScrollingCompositingReason(
@@ -238,6 +242,8 @@
   PaintLayer* enclosing_squashing_composited_layer =
       info.enclosing_squashing_composited_layer;
 
+  DisableCompositingQueryAsserts disabler;
+
   if (layer->NeedsCompositingInputsUpdate()) {
     if (enclosing_stacking_composited_layer) {
       enclosing_stacking_composited_layer->GetCompositedLayerMapping()
@@ -252,7 +258,6 @@
     update_type = kForceUpdate;
   }
 
-
   switch (layer->GetCompositingState()) {
     case kNotComposited:
       break;
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
index c4b49027..df7dc3bc 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_inputs_updater.h
@@ -26,6 +26,9 @@
   static void AssertNeedsCompositingInputsUpdateBitsCleared(PaintLayer*);
 #endif
 
+  // Combine all reasons for compositing a layer into a single boolean value
+  bool LayerOrDescendantShouldBeComposited(PaintLayer*);
+
  private:
   enum UpdateType {
     kDoNotForceUpdate,
@@ -83,9 +86,6 @@
   // current value of AncestorInfo.
   void UpdateAncestorInfo(PaintLayer* const, UpdateType&, AncestorInfo&);
 
-  // Combine all reasons for compositing a layer into a single boolean value
-  bool LayerOrDescendantShouldBeComposited(PaintLayer*);
-
   LayoutGeometryMap geometry_map_;
   PaintLayer* root_layer_;
   PaintLayer* compositing_inputs_root_;
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
index 75e403b5..d2c55bc3 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater.cc
@@ -186,9 +186,10 @@
     auto state = fragment_data.LocalBorderBoxProperties();
     const auto* properties = fragment_data.PaintProperties();
     DCHECK(properties);
-    DCHECK(properties->Mask());
+    DCHECK(properties->Mask() || properties->ClipPathMask());
     DCHECK(properties->MaskClip());
-    state.SetEffect(*properties->Mask());
+    state.SetEffect(properties->Mask() ? *properties->Mask()
+                                       : *properties->ClipPathMask());
     state.SetClip(*properties->MaskClip());
 
     mask_layer->SetLayerState(
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater_test.cc
index 463e86b..efaa6ac3 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater_test.cc
@@ -26,24 +26,84 @@
 
 TEST_F(CompositingLayerPropertyUpdaterTest, MaskLayerState) {
   SetBodyInnerHTML(R"HTML(
-    <div id=target style="position: absolute;
-        clip-path: polygon(-1px -1px, 86px 400px);
-        clip: rect(9px, -1px, -1px, 96px); will-change: transform">
+    <svg width="0" height="0">
+      <defs>
+        <clipPath id="text">
+          <text>Text</text>
+        </clipPath>
+      </defs>
+    </svg>
+    <style>
+      .clip-path-mask { clip-path: url(#text); }
+      .clip-path-path { clip-path: circle(50%); }
+      .mask-image { -webkit-mask-image: linear-gradient(black, transparent); }
+    </style>
+    <div id=target class="clip-path-mask"
+         style="position: absolute; will-change: transform;
+                clip: rect(9px, -1px, -1px, 96px)">
     </div>
     )HTML");
 
-  PaintLayer* target =
-      ToLayoutBoxModelObject(GetLayoutObjectByElementId("target"))->Layer();
+  auto* target_element = GetDocument().getElementById("target");
+  auto* target = target_element->GetLayoutBoxModelObject();
   EXPECT_EQ(kPaintsIntoOwnBacking, target->GetCompositingState());
-  auto* mapping = target->GetCompositedLayerMapping();
+  auto* mapping = target->Layer()->GetCompositedLayerMapping();
   auto* mask_layer = mapping->MaskLayer();
 
-  auto* paint_properties =
-      target->GetLayoutObject().FirstFragment().PaintProperties();
+  auto* paint_properties = target->FirstFragment().PaintProperties();
   EXPECT_TRUE(paint_properties->CssClip());
   EXPECT_TRUE(paint_properties->MaskClip());
   EXPECT_EQ(paint_properties->MaskClip(),
             &mask_layer->GetPropertyTreeState().Clip());
+  EXPECT_FALSE(paint_properties->Mask());
+  EXPECT_EQ(paint_properties->ClipPathMask(),
+            &mask_layer->GetPropertyTreeState().Effect());
+
+  target_element->setAttribute(html_names::kClassAttr,
+                               "clip-path-mask mask-image");
+  UpdateAllLifecyclePhasesForTest();
+  ASSERT_EQ(mapping, target->Layer()->GetCompositedLayerMapping());
+  ASSERT_EQ(mask_layer, mapping->MaskLayer());
+  ASSERT_EQ(paint_properties, target->FirstFragment().PaintProperties());
+  EXPECT_FALSE(paint_properties->ClipPathClip());
+  EXPECT_EQ(paint_properties->MaskClip(),
+            &mask_layer->GetPropertyTreeState().Clip());
+  EXPECT_TRUE(paint_properties->ClipPathMask());
+  EXPECT_EQ(paint_properties->Mask(),
+            &mask_layer->GetPropertyTreeState().Effect());
+
+  target_element->setAttribute(html_names::kClassAttr, "mask-image");
+  UpdateAllLifecyclePhasesForTest();
+  ASSERT_EQ(mapping, target->Layer()->GetCompositedLayerMapping());
+  ASSERT_EQ(mask_layer, mapping->MaskLayer());
+  ASSERT_EQ(paint_properties, target->FirstFragment().PaintProperties());
+  EXPECT_EQ(paint_properties->MaskClip(),
+            &mask_layer->GetPropertyTreeState().Clip());
+  EXPECT_FALSE(paint_properties->ClipPathMask());
+  EXPECT_EQ(paint_properties->Mask(),
+            &mask_layer->GetPropertyTreeState().Effect());
+
+  target_element->setAttribute(html_names::kClassAttr,
+                               "clip-path-path mask-image");
+  UpdateAllLifecyclePhasesForTest();
+  ASSERT_EQ(mapping, target->Layer()->GetCompositedLayerMapping());
+  ASSERT_EQ(mask_layer, mapping->MaskLayer());
+  ASSERT_EQ(paint_properties, target->FirstFragment().PaintProperties());
+  EXPECT_TRUE(paint_properties->ClipPathClip());
+  EXPECT_EQ(paint_properties->MaskClip(),
+            &mask_layer->GetPropertyTreeState().Clip());
+  EXPECT_FALSE(paint_properties->ClipPathMask());
+  EXPECT_EQ(paint_properties->Mask(),
+            &mask_layer->GetPropertyTreeState().Effect());
+
+  target_element->setAttribute(html_names::kClassAttr, "clip-path-path");
+  UpdateAllLifecyclePhasesForTest();
+  ASSERT_EQ(mapping, target->Layer()->GetCompositedLayerMapping());
+  EXPECT_FALSE(mapping->MaskLayer());
+  ASSERT_EQ(paint_properties, target->FirstFragment().PaintProperties());
+  EXPECT_TRUE(paint_properties->ClipPathClip());
+  EXPECT_FALSE(paint_properties->ClipPathMask());
+  EXPECT_FALSE(paint_properties->Mask());
 }
 
 TEST_F(CompositingLayerPropertyUpdaterTest,
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
index 09b703e..4edb395 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
@@ -1381,6 +1381,7 @@
   auto* main_iframe_element =
       To<HTMLIFrameElement>(GetDocument().getElementById("main_iframe"));
   NonThrowableExceptionState exception_state;
+
   GetDocument().setDomain(String("origin-a.com"), exception_state);
   auto* child_iframe_element = To<HTMLIFrameElement>(
       main_iframe_element->contentDocument()->getElementById("child_iframe"));
@@ -1392,7 +1393,6 @@
   // We may not have scheduled a visual update so force an update instead of
   // using BeginFrame.
   UpdateAllLifecyclePhases();
-
   iframe_doc = To<HTMLFrameOwnerElement>(GetElementById("main_iframe"))
                    ->contentDocument();
   EXPECT_FALSE(CcLayerByOwnerNodeId(iframe_doc));
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
index c7e2c69..c16af12 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.cc
@@ -72,7 +72,7 @@
 
 void PaintLayerCompositor::CleanUp() {
   if (InCompositingMode())
-    SetOwnerNeedsCompositingUpdate();
+    SetOwnerNeedsCompositingInputsUpdate();
 }
 
 bool PaintLayerCompositor::InCompositingMode() const {
@@ -97,8 +97,87 @@
     root_layer->SetNeedsCompositingInputsUpdate();
 }
 
+void PaintLayerCompositor::UpdateCompositingInputsIfNeededRecursive(
+    DocumentLifecycle::LifecycleState target_state) {
+  DCHECK_GE(target_state, DocumentLifecycle::kCompositingInputsClean);
+  TRACE_EVENT0(
+      "blink,benchmark",
+      "PaintLayerCompositor::UpdateCompositingInputsIfNeededRecursive");
+  UpdateCompositingInputsIfNeededRecursiveInternal(target_state);
+}
+
+void PaintLayerCompositor::UpdateCompositingInputsIfNeededRecursiveInternal(
+    DocumentLifecycle::LifecycleState target_state) {
+  if (layout_view_.GetFrameView()->ShouldThrottleRendering())
+    return;
+
+  for (Frame* child =
+           layout_view_.GetFrameView()->GetFrame().Tree().FirstChild();
+       child; child = child->Tree().NextSibling()) {
+    auto* local_frame = DynamicTo<LocalFrame>(child);
+    if (!local_frame)
+      continue;
+    // It's possible for trusted Pepper plugins to force hit testing in
+    // situations where the frame tree is in an inconsistent state, such as in
+    // the middle of frame detach.
+    // TODO(bbudge) Remove this check when trusted Pepper plugins are gone.
+    if (local_frame->GetDocument()->IsActive() &&
+        local_frame->ContentLayoutObject()) {
+      local_frame->ContentLayoutObject()
+          ->Compositor()
+          ->UpdateCompositingInputsIfNeededRecursiveInternal(target_state);
+    }
+  }
+
+  ScriptForbiddenScope forbid_script;
+
+#if DCHECK_IS_ON()
+  LocalFrameView* view = layout_view_.GetFrameView();
+  view->SetIsUpdatingDescendantDependentFlags(true);
+#endif
+  {
+    TRACE_EVENT0("blink", "PaintLayer::UpdateDescendantDependentFlags");
+    RootLayer()->UpdateDescendantDependentFlags();
+  }
+#if DCHECK_IS_ON()
+  view->SetIsUpdatingDescendantDependentFlags(false);
+#endif
+
+  layout_view_.CommitPendingSelection();
+
+  Lifecycle().AdvanceTo(DocumentLifecycle::kInCompositingInputsUpdate);
+
+  if (pending_update_type_ >= kCompositingUpdateAfterCompositingInputChange) {
+    CompositingInputsUpdater updater(RootLayer(), GetCompositingInputsRoot());
+    updater.Update();
+    // TODO(chrishtr): we should only need to do this if compositing state
+    // changed, but
+    // compositing/iframe-graphics-tree-changes-parents-does-not.html
+    // breaks otherwise.
+    if (updater.LayerOrDescendantShouldBeComposited(RootLayer()))
+      SetOwnerNeedsCompositingInputsUpdate();
+  }
+
+  Lifecycle().AdvanceTo(DocumentLifecycle::kCompositingInputsClean);
+
+#if DCHECK_IS_ON()
+  if (!layout_view_.GetDocument()
+           .GetSettings()
+           ->GetAcceleratedCompositingEnabled()) {
+    DCHECK(!layout_view_.GetDocument()
+                .GetSettings()
+                ->GetAcceleratedCompositingEnabled());
+  }
+
+  CompositingInputsUpdater::AssertNeedsCompositingInputsUpdateBitsCleared(
+      RootLayer());
+#endif
+}
+
 void PaintLayerCompositor::UpdateIfNeededRecursive(
     DocumentLifecycle::LifecycleState target_state) {
+  DCHECK_GE(target_state, DocumentLifecycle::kCompositingInputsClean);
+  UpdateCompositingInputsIfNeededRecursiveInternal(target_state);
   CompositingReasonsStats compositing_reasons_stats;
   UpdateIfNeededRecursiveInternal(target_state, compositing_reasons_stats);
   UMA_HISTOGRAM_CUSTOM_COUNTS("Blink.Compositing.LayerPromotionCount.Overlap",
@@ -121,11 +200,12 @@
 void PaintLayerCompositor::UpdateIfNeededRecursiveInternal(
     DocumentLifecycle::LifecycleState target_state,
     CompositingReasonsStats& compositing_reasons_stats) {
-  DCHECK(target_state >= DocumentLifecycle::kCompositingInputsClean);
-
   if (layout_view_.GetFrameView()->ShouldThrottleRendering())
     return;
 
+  if (target_state == DocumentLifecycle::kCompositingInputsClean)
+    return;
+
   LocalFrameView* view = layout_view_.GetFrameView();
   view->ResetNeedsForcedCompositingUpdate();
 
@@ -155,24 +235,7 @@
 
   ScriptForbiddenScope forbid_script;
 
-#if DCHECK_IS_ON()
-  view->SetIsUpdatingDescendantDependentFlags(true);
-#endif
-  {
-    TRACE_EVENT0("blink", "PaintLayer::UpdateDescendantDependentFlags");
-    RootLayer()->UpdateDescendantDependentFlags();
-  }
-#if DCHECK_IS_ON()
-  view->SetIsUpdatingDescendantDependentFlags(false);
-#endif
-
-  layout_view_.CommitPendingSelection();
-
   UpdateIfNeeded(target_state, compositing_reasons_stats);
-  DCHECK(Lifecycle().GetState() == DocumentLifecycle::kCompositingInputsClean ||
-         Lifecycle().GetState() == DocumentLifecycle::kCompositingClean);
-  if (target_state == DocumentLifecycle::kCompositingInputsClean)
-    return;
 
 #if DCHECK_IS_ON()
   DCHECK_EQ(Lifecycle().GetState(), DocumentLifecycle::kCompositingClean);
@@ -212,22 +275,6 @@
   Lifecycle().EnsureStateAtMost(DocumentLifecycle::kLayoutClean);
 }
 
-void PaintLayerCompositor::UpdateWithoutAcceleratedCompositing(
-    CompositingUpdateType update_type) {
-  DCHECK(!layout_view_.GetDocument()
-              .GetSettings()
-              ->GetAcceleratedCompositingEnabled());
-
-  if (update_type >= kCompositingUpdateAfterCompositingInputChange) {
-    CompositingInputsUpdater(RootLayer(), GetCompositingInputsRoot()).Update();
-  }
-
-#if DCHECK_IS_ON()
-  CompositingInputsUpdater::AssertNeedsCompositingInputsUpdateBitsCleared(
-      RootLayer());
-#endif
-}
-
 void PaintLayerCompositor::
     ForceRecomputeVisualRectsIncludingNonCompositingDescendants(
         LayoutObject& layout_object) {
@@ -258,34 +305,18 @@
 void PaintLayerCompositor::UpdateIfNeeded(
     DocumentLifecycle::LifecycleState target_state,
     CompositingReasonsStats& compositing_reasons_stats) {
-  DCHECK(target_state >= DocumentLifecycle::kCompositingInputsClean);
+  DCHECK(target_state >= DocumentLifecycle::kCompositingClean);
 
   Lifecycle().AdvanceTo(DocumentLifecycle::kInCompositingUpdate);
 
-  if (pending_update_type_ < kCompositingUpdateAfterCompositingInputChange &&
-      target_state == DocumentLifecycle::kCompositingInputsClean) {
-    // The compositing inputs are already clean and that is our target state.
-    // Early-exit here without clearing the pending update type since we haven't
-    // handled e.g. geometry updates.
-    Lifecycle().AdvanceTo(DocumentLifecycle::kCompositingInputsClean);
-    return;
-  }
-
   CompositingUpdateType update_type = pending_update_type_;
   pending_update_type_ = kCompositingUpdateNone;
 
   if (!layout_view_.GetDocument()
            .GetSettings()
-           ->GetAcceleratedCompositingEnabled()) {
-    UpdateWithoutAcceleratedCompositing(update_type);
-    Lifecycle().AdvanceTo(
-        std::min(DocumentLifecycle::kCompositingClean, target_state));
-    return;
-  }
-
-  if (update_type == kCompositingUpdateNone) {
-    Lifecycle().AdvanceTo(
-        std::min(DocumentLifecycle::kCompositingClean, target_state));
+           ->GetAcceleratedCompositingEnabled() ||
+      update_type == kCompositingUpdateNone) {
+    Lifecycle().AdvanceTo(DocumentLifecycle::kCompositingClean);
     return;
   }
 
@@ -293,38 +324,18 @@
 
   Vector<PaintLayer*> layers_needing_paint_invalidation;
 
-  if (update_type >= kCompositingUpdateAfterCompositingInputChange) {
-    CompositingInputsUpdater(RootLayer(), GetCompositingInputsRoot()).Update();
+  CompositingRequirementsUpdater(layout_view_)
+      .Update(update_root, compositing_reasons_stats);
 
-#if DCHECK_IS_ON()
-    // FIXME: Move this check to the end of the compositing update.
-    CompositingInputsUpdater::AssertNeedsCompositingInputsUpdateBitsCleared(
-        update_root);
-#endif
+  CompositingLayerAssigner layer_assigner(this);
+  layer_assigner.Assign(update_root, layers_needing_paint_invalidation);
 
-    // In the case where we only want to make compositing inputs clean, we
-    // early-exit here. Because we have not handled the other implications of
-    // |pending_update_type_| > kCompositingUpdateNone, we must restore the
-    // pending update type for a future call.
-    if (target_state == DocumentLifecycle::kCompositingInputsClean) {
-      pending_update_type_ = update_type;
-      Lifecycle().AdvanceTo(DocumentLifecycle::kCompositingInputsClean);
-      return;
-    }
-
-    CompositingRequirementsUpdater(layout_view_)
-        .Update(update_root, compositing_reasons_stats);
-
-    CompositingLayerAssigner layer_assigner(this);
-    layer_assigner.Assign(update_root, layers_needing_paint_invalidation);
-
-    if (layer_assigner.LayersChanged()) {
-      update_type = std::max(update_type, kCompositingUpdateRebuildTree);
-      if (ScrollingCoordinator* scrolling_coordinator =
-              GetScrollingCoordinator()) {
-        LocalFrameView* frame_view = layout_view_.GetFrameView();
-        scrolling_coordinator->NotifyGeometryChanged(frame_view);
-      }
+  if (layer_assigner.LayersChanged()) {
+    update_type = std::max(update_type, kCompositingUpdateRebuildTree);
+    if (ScrollingCoordinator* scrolling_coordinator =
+            GetScrollingCoordinator()) {
+      LocalFrameView* frame_view = layout_view_.GetFrameView();
+      scrolling_coordinator->NotifyGeometryChanged(frame_view);
     }
   }
 
@@ -364,9 +375,6 @@
     if (!child_list.IsEmpty()) {
       CHECK(compositing_);
       DCHECK_EQ(1u, child_list.size());
-      // Schedule an update in the parent frame so the <iframe>'s layer in the
-      // owner document matches the compositing state here.
-      SetOwnerNeedsCompositingUpdate();
       root_layer_attachment_dirty_ = true;
     }
   }
@@ -550,10 +558,15 @@
   const bool has_compositor_animation =
       CompositingReasonFinder::CompositingReasonsForAnimation(
           layer->GetLayoutObject()) != CompositingReason::kNone;
+
+  // Throttled frames have stale visibility state.
+  bool frame_is_visible =
+      !frame_view->ShouldThrottleRendering() && !layer->SubtreeIsInvisible();
+
   return layout_view_.GetDocument()
              .GetSettings()
              ->GetAcceleratedCompositingEnabled() &&
-         (has_compositor_animation || !layer->SubtreeIsInvisible()) &&
+         (has_compositor_animation || frame_is_visible) &&
          layer->IsSelfPaintingLayer() &&
          !layer->GetLayoutObject().IsLayoutFlowThread() &&
          // Don't composite <foreignObject> for the moment, to reduce
@@ -592,10 +605,14 @@
     UpdateTrackingRasterInvalidationsRecursive(root_layer);
 }
 
-void PaintLayerCompositor::SetOwnerNeedsCompositingUpdate() {
+void PaintLayerCompositor::SetOwnerNeedsCompositingInputsUpdate() {
   if (HTMLFrameOwnerElement* owner_element =
           layout_view_.GetDocument().LocalOwner()) {
-    owner_element->SetNeedsCompositingUpdate();
+    LayoutBoxModelObject* layout_object =
+        owner_element->GetLayoutBoxModelObject();
+    if (!layout_object || !layout_object->HasLayer())
+      return;
+    layout_object->Layer()->SetNeedsCompositingInputsUpdate();
   }
 }
 
diff --git a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
index e41c6fe7..47a23731c 100644
--- a/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
+++ b/third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h
@@ -82,6 +82,8 @@
   void CleanUp();
 
   void UpdateIfNeededRecursive(DocumentLifecycle::LifecycleState target_state);
+  void UpdateCompositingInputsIfNeededRecursive(
+      DocumentLifecycle::LifecycleState target_state);
 
   // Return true if this LayoutView is in "compositing mode" (i.e. has one or
   // more composited Layers)
@@ -162,12 +164,13 @@
   void UpdateIfNeededRecursiveInternal(
       DocumentLifecycle::LifecycleState target_state,
       CompositingReasonsStats&);
+  void UpdateCompositingInputsIfNeededRecursiveInternal(
+      DocumentLifecycle::LifecycleState target_state);
 
-  void UpdateWithoutAcceleratedCompositing(CompositingUpdateType);
   void UpdateIfNeeded(DocumentLifecycle::LifecycleState target_state,
                       CompositingReasonsStats&);
 
-  void SetOwnerNeedsCompositingUpdate();
+  void SetOwnerNeedsCompositingInputsUpdate();
 
   Page* GetPage() const;
 
diff --git a/third_party/blink/renderer/core/paint/fragment_data.h b/third_party/blink/renderer/core/paint/fragment_data.h
index a9adb04..9927c0c 100644
--- a/third_party/blink/renderer/core/paint/fragment_data.h
+++ b/third_party/blink/renderer/core/paint/fragment_data.h
@@ -202,19 +202,6 @@
                                     PostIsolationEffect());
   }
 
-  // This is the complete set of property nodes that can be used to
-  // paint mask-based clip-path.
-  PropertyTreeStateOrAlias ClipPathProperties() const {
-    DCHECK(rare_data_);
-    const auto* properties = rare_data_->paint_properties.get();
-    DCHECK(properties);
-    DCHECK(properties->MaskClip());
-    DCHECK(properties->ClipPath());
-    return PropertyTreeStateOrAlias(
-        properties->MaskClip()->LocalTransformSpace(), *properties->MaskClip(),
-        *properties->ClipPath());
-  }
-
   const TransformPaintPropertyNodeOrAlias& PreTransform() const;
   const TransformPaintPropertyNodeOrAlias& PostScrollTranslation() const;
   const ClipPaintPropertyNodeOrAlias& PreClip() const;
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
index 6d00812..47fbe86 100644
--- a/third_party/blink/renderer/core/paint/link_highlight_impl.cc
+++ b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -270,7 +270,8 @@
   DCHECK(!object->GetFrameView()->ShouldThrottleRendering());
 
   static const FloatSize rect_rounding_radii(3, 3);
-  auto color = object->StyleRef().TapHighlightColor();
+  auto color = object->StyleRef().VisitedDependentColor(
+      GetCSSPropertyWebkitTapHighlightColor());
 
   // For now, we'll only use rounded rects if we have a single rect because
   // otherwise we may sometimes get a chain of adjacent boxes (e.g. for text
diff --git a/third_party/blink/renderer/core/paint/object_paint_properties.h b/third_party/blink/renderer/core/paint/object_paint_properties.h
index 41ed3023..875b2deb 100644
--- a/third_party/blink/renderer/core/paint/object_paint_properties.h
+++ b/third_party/blink/renderer/core/paint/object_paint_properties.h
@@ -134,24 +134,25 @@
 
   // The hierarchy of the effect subtree created by a LayoutObject is as
   // follows:
-  // [ effect ]
+  // [ Effect ]
   // |     Isolated group to apply various CSS effects, including opacity,
   // |     mix-blend-mode, backdrop-filter, and for isolation if a mask needs
   // |     to be applied or backdrop-dependent children are present.
-  // +-[ filter ]
+  // +-[ Filter ]
   // |     Isolated group for CSS filter.
-  // +-[ vertical/horizontal scrollbar effect ]
-  // |     Overlay Scrollbars on Aura and Android need effect node for fade
-  // |     animation.
-  // +-[ mask ]
-  // |     Isolated group for painting the CSS mask. This node will have
-  // |     SkBlendMode::kDstIn and shall paint last, i.e. after masked contents.
-  // +-[ clip path ]
-  //       Isolated group for painting the CSS clip-path. This node will have
-  //       SkBlendMode::kDstIn and shall paint last, i.e. after clipped
-  //       contents.
+  // +-[ Mask ]
+  // | |   Isolated group for painting the CSS mask or the mask-based CSS
+  // | |   clip-path. This node will have SkBlendMode::kDstIn and shall paint
+  // | |   last, i.e. after masked contents.
+  // | +-[ ClipPathMask ]
+  // |     Isolated group for painting the mask-based CSS clip-path. This node
+  // |     will have SkBlendMode::kDstIn and shall paint last, i.e. after
+  // |     clipped contents.
+  // +-[ VerticalScrollbarEffect / HorizontalScrollbarEffect ]
+  //       Overlay Scrollbars on Aura and Android need effect node for fade
+  //       animation.
   //
-  // ... +-[ effectIsolationNode ]
+  // ... +-[ EffectIsolationNode ]
   //       This serves as a parent to subtree effects on an element with paint
   //       containment, It is the deepest child of any effect tree on the
   //       contain: paint element.
@@ -160,44 +161,43 @@
   ADD_EFFECT(VerticalScrollbarEffect, vertical_scrollbar_effect_);
   ADD_EFFECT(HorizontalScrollbarEffect, horizontal_scrollbar_effect_);
   ADD_EFFECT(Mask, mask_);
-  ADD_EFFECT(ClipPath, clip_path_);
+  ADD_EFFECT(ClipPathMask, clip_path_mask_);
   ADD_ALIAS_NODE(Effect, EffectIsolationNode, effect_isolation_node_);
 
   // The hierarchy of the clip subtree created by a LayoutObject is as follows:
-  // [ fragment clip ]
+  // [ FragmentClip ]
   // |    Clips to a fragment's bounds.
   // |    This is only present for content under a fragmentation container.
-  // +-[ clip path clip ]
+  // +-[ ClipPathClip ]
   //   |  Clip created by path-based CSS clip-path. Only exists if the
   //  /   clip-path is "simple" that can be applied geometrically. This and
-  // /    the clip path effect node are mutually exclusive.
-  // | NOTE: for composited SPv1 clip path clips, we move clip path clip
-  // |       below mask.
-  // +-[ mask clip ]
-  //   |   Clip created by CSS mask or CSS clip-path. It serves two purposes:
+  // /    the ClipPathMask effect node are mutually exclusive.
+  // +-[ MaskClip ]
+  //   |   Clip created by CSS mask or mask-based CSS clip-path.
+  //   |   It serves two purposes:
   //   |   1. Cull painting of the masked subtree. Because anything outside of
   //   |      the mask is never visible, it is pointless to paint them.
   //   |   2. Raster clip of the masked subtree. Because the mask implemented
   //   |      as SkBlendMode::kDstIn, pixels outside of mask's bound will be
   //   |      intact when they shall be masked out. This clip ensures no pixels
   //   |      leak out.
-  //   +-[ css clip ]
+  //   +-[ CssClip ]
   //     |   Clip created by CSS clip. CSS clip applies to all descendants, this
   //     |   node only applies to containing block descendants. For descendants
   //     |   not contained by this object, use [ css clip fixed position ].
-  //     +-[ overflow controls clip ]
+  //     +-[ OverflowControlsClip ]
   //     |   Clip created by overflow clip to clip overflow controls
   //     |   (scrollbars, resizer, scroll corner) that would overflow the box.
-  //     +-[ inner border radius clip]
+  //     +-[ InnerBorderRadiusClip ]
   //       |   Clip created by a rounded border with overflow clip. This clip is
   //       |   not inset by scrollbars.
-  //       +-[ overflow clip ]
+  //       +-[ OverflowClip ]
   //             Clip created by overflow clip and is inset by the scrollbar.
-  //   [ css clip fixed position ]
+  //   [ CssClipFixedPosition ]
   //       Clip created by CSS clip. Only exists if the current clip includes
   //       some clip that doesn't apply to our fixed position descendants.
   //
-  //  ... +-[ clipIsolationNode ]
+  //  ... +-[ ClipIsolationNode ]
   //       This serves as a parent to subtree clips on an element with paint
   //       containment. It is the deepest child of any clip tree on the contain:
   //       paint element.
@@ -228,7 +228,7 @@
     DCHECK(!ScrollTranslation() || !ReplacedContentTransform())
         << "Replaced elements don't scroll so there should never be both a "
            "scroll translation and a replaced content transform.";
-    DCHECK(!ClipPathClip() || !ClipPath())
+    DCHECK(!ClipPathClip() || !ClipPathMask())
         << "ClipPathClip and ClipPathshould be mutually exclusive.";
     DCHECK((!TransformIsolationNode() && !ClipIsolationNode() &&
             !EffectIsolationNode()) ||
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
index 4f07e7b..621b42b 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -397,23 +397,6 @@
   if (!PhysicalRect(painting_info.cull_rect.Rect()).Contains(bounds))
     result = kMayBeClippedByCullRect;
 
-  // These helpers output clip and compositing operations using a RAII pattern.
-  // Stack-allocated-varibles are destructed in the reverse order of
-  // construction, so they are nested properly.
-  base::Optional<ClipPathClipper> clip_path_clipper;
-  bool should_paint_clip_path =
-      is_painting_mask && paint_layer_.GetLayoutObject().HasClipPath();
-  if (should_paint_clip_path) {
-    PhysicalOffset visual_offset_from_root =
-        paint_layer_.EnclosingPaginationLayer()
-            ? paint_layer_.VisualOffsetFromAncestor(painting_info.root_layer,
-                                                    subpixel_accumulation)
-            : offset_from_root;
-    clip_path_clipper.emplace(context, paint_layer_.GetLayoutObject(),
-                              paint_layer_.GetLayoutObject(),
-                              visual_offset_from_root);
-  }
-
   PaintLayerPaintingInfo local_painting_info(painting_info);
   local_painting_info.sub_pixel_accumulation = subpixel_accumulation;
 
@@ -443,130 +426,109 @@
     }
   }
 
-  {  // Begin block for the lifetime of any filter.
-    bool is_painting_root_layer = (&paint_layer_) == painting_info.root_layer;
-    bool should_paint_background =
-        should_paint_content && !selection_drag_image_only &&
-        (is_painting_composited_background ||
-         (is_painting_root_layer &&
-          !(paint_flags & kPaintLayerPaintingSkipRootBackground)));
-    bool should_paint_neg_z_order_list =
-        !is_painting_overlay_overflow_controls &&
-        (is_painting_scrolling_content ? is_painting_overflow_contents
-                                       : is_painting_composited_background);
-    bool should_paint_own_contents =
-        is_painting_composited_foreground && should_paint_content;
-    bool should_paint_normal_flow_and_pos_z_order_lists =
-        is_painting_composited_foreground &&
-        !is_painting_overlay_overflow_controls;
-    bool is_video = IsA<LayoutVideo>(paint_layer_.GetLayoutObject());
+  bool is_painting_root_layer = (&paint_layer_) == painting_info.root_layer;
+  bool should_paint_background =
+      should_paint_content && !selection_drag_image_only &&
+      (is_painting_composited_background ||
+       (is_painting_root_layer &&
+        !(paint_flags & kPaintLayerPaintingSkipRootBackground)));
+  bool should_paint_neg_z_order_list =
+      !is_painting_overlay_overflow_controls &&
+      (is_painting_scrolling_content ? is_painting_overflow_contents
+                                     : is_painting_composited_background);
+  bool should_paint_own_contents =
+      is_painting_composited_foreground && should_paint_content;
+  bool should_paint_normal_flow_and_pos_z_order_lists =
+      is_painting_composited_foreground &&
+      !is_painting_overlay_overflow_controls;
+  bool is_video = IsA<LayoutVideo>(paint_layer_.GetLayoutObject());
 
-    base::Optional<ScopedPaintChunkHint> paint_chunk_hint;
-    if (should_paint_content) {
-      paint_chunk_hint.emplace(context.GetPaintController(),
-                               paint_layer_.GetLayoutObject()
-                                   .FirstFragment()
-                                   .LocalBorderBoxProperties(),
-                               paint_layer_, DisplayItem::kLayerChunk);
-    }
-
-    if (should_paint_background) {
-      PaintBackgroundForFragments(layer_fragments, context, local_painting_info,
-                                  paint_flags);
-    }
-
-    if (should_paint_neg_z_order_list) {
-      if (PaintChildren(kNegativeZOrderChildren, context, painting_info,
-                        paint_flags) == kMayBeClippedByCullRect)
-        result = kMayBeClippedByCullRect;
-    }
-
-    if (should_paint_own_contents) {
-      base::Optional<ScopedPaintChunkHint> paint_chunk_hint_foreground;
-      if (paint_chunk_hint && paint_chunk_hint->HasCreatedPaintChunk()) {
-        // Hint a foreground chunk if we have created any chunks, to give the
-        // paint chunk after the previous forced paint chunks a stable id.
-        paint_chunk_hint_foreground.emplace(context.GetPaintController(),
-                                            paint_layer_,
-                                            DisplayItem::kLayerChunkForeground);
-      }
-      if (selection_drag_image_only) {
-        PaintForegroundForFragmentsWithPhase(PaintPhase::kSelectionDragImage,
-                                             layer_fragments, context,
-                                             local_painting_info, paint_flags);
-      } else {
-        PaintForegroundForFragments(layer_fragments, context,
-                                    local_painting_info, paint_flags);
-      }
-    }
-
-    if (!is_video && should_paint_self_outline) {
-      PaintSelfOutlineForFragments(layer_fragments, context,
-                                   local_painting_info, paint_flags);
-    }
-
-    if (should_paint_normal_flow_and_pos_z_order_lists) {
-      if (PaintChildren(kNormalFlowAndPositiveZOrderChildren, context,
-                        painting_info, paint_flags) == kMayBeClippedByCullRect)
-        result = kMayBeClippedByCullRect;
-    }
-
-    if (paint_layer_.GetScrollableArea() &&
-        paint_layer_.GetScrollableArea()->HasOverlayOverflowControls()) {
-      if (is_painting_overlay_overflow_controls ||
-          !paint_layer_.NeedsReorderOverlayOverflowControls()) {
-        PaintOverlayOverflowControlsForFragments(
-            layer_fragments, context, local_painting_info, paint_flags);
-      }
-    }
-
-    if (is_video && should_paint_self_outline) {
-      // We paint outlines for video later so that they aren't obscured by the
-      // video controls.
-      PaintSelfOutlineForFragments(layer_fragments, context,
-                                   local_painting_info, paint_flags);
-    }
-  }  // FilterPainter block
-
-  bool should_paint_mask = is_painting_mask && should_paint_content &&
-                           paint_layer_.GetLayoutObject().HasMask() &&
-                           !selection_drag_image_only;
-  if (should_paint_mask) {
-    PaintMaskForFragments(layer_fragments, context, local_painting_info,
-                          paint_flags);
-  } else if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
-             is_painting_mask &&
-             !(painting_info.GetGlobalPaintFlags() &
-               kGlobalPaintFlattenCompositingLayers) &&
-             paint_layer_.GetCompositedLayerMapping() &&
-             paint_layer_.GetCompositedLayerMapping()->MaskLayer()) {
-    // In SPv1 it is possible for CompositedLayerMapping to create a mask layer
-    // for just CSS clip-path but without a CSS mask. In that case we need to
-    // paint a fully filled mask (which will subsequently clipped by the
-    // clip-path), otherwise the mask layer will be empty.
-    const auto& fragment_data = paint_layer_.GetLayoutObject().FirstFragment();
-    auto state = fragment_data.LocalBorderBoxProperties();
-    const auto* properties = fragment_data.PaintProperties();
-    DCHECK(properties && properties->Mask());
-    state.SetEffect(*properties->Mask());
-    if (properties && properties->ClipPathClip()) {
-      DCHECK_EQ(properties->ClipPathClip()->Parent(), properties->MaskClip());
-      state.SetClip(*properties->ClipPathClip());
-    }
-    ScopedPaintChunkProperties path_based_clip_path_scope(
-        context.GetPaintController(), state,
-        *paint_layer_.GetCompositedLayerMapping()->MaskLayer(),
-        DisplayItem::kClippingMask);
-
-    const GraphicsLayer* mask_layer =
-        paint_layer_.GetCompositedLayerMapping()->MaskLayer();
-    ClipRect layer_rect =
-        PhysicalRect(PhysicalOffset(mask_layer->OffsetFromLayoutObject()),
-                     PhysicalSize(IntSize(mask_layer->Size())));
-    FillMaskingFragment(context, layer_rect, *mask_layer);
+  base::Optional<ScopedPaintChunkHint> paint_chunk_hint;
+  if (should_paint_content) {
+    paint_chunk_hint.emplace(context.GetPaintController(),
+                             paint_layer_.GetLayoutObject()
+                                 .FirstFragment()
+                                 .LocalBorderBoxProperties(),
+                             paint_layer_, DisplayItem::kLayerChunk);
   }
 
-  clip_path_clipper = base::nullopt;
+  if (should_paint_background) {
+    PaintBackgroundForFragments(layer_fragments, context, local_painting_info,
+                                paint_flags);
+  }
+
+  if (should_paint_neg_z_order_list) {
+    if (PaintChildren(kNegativeZOrderChildren, context, painting_info,
+                      paint_flags) == kMayBeClippedByCullRect)
+      result = kMayBeClippedByCullRect;
+  }
+
+  if (should_paint_own_contents) {
+    base::Optional<ScopedPaintChunkHint> paint_chunk_hint_foreground;
+    if (paint_chunk_hint && paint_chunk_hint->HasCreatedPaintChunk()) {
+      // Hint a foreground chunk if we have created any chunks, to give the
+      // paint chunk after the previous forced paint chunks a stable id.
+      paint_chunk_hint_foreground.emplace(context.GetPaintController(),
+                                          paint_layer_,
+                                          DisplayItem::kLayerChunkForeground);
+    }
+    if (selection_drag_image_only) {
+      PaintForegroundForFragmentsWithPhase(PaintPhase::kSelectionDragImage,
+                                           layer_fragments, context,
+                                           local_painting_info, paint_flags);
+    } else {
+      PaintForegroundForFragments(layer_fragments, context, local_painting_info,
+                                  paint_flags);
+    }
+  }
+
+  if (!is_video && should_paint_self_outline) {
+    PaintSelfOutlineForFragments(layer_fragments, context, local_painting_info,
+                                 paint_flags);
+  }
+
+  if (should_paint_normal_flow_and_pos_z_order_lists) {
+    if (PaintChildren(kNormalFlowAndPositiveZOrderChildren, context,
+                      painting_info, paint_flags) == kMayBeClippedByCullRect)
+      result = kMayBeClippedByCullRect;
+  }
+
+  if (paint_layer_.GetScrollableArea() &&
+      paint_layer_.GetScrollableArea()->HasOverlayOverflowControls()) {
+    if (is_painting_overlay_overflow_controls ||
+        !paint_layer_.NeedsReorderOverlayOverflowControls()) {
+      PaintOverlayOverflowControlsForFragments(
+          layer_fragments, context, local_painting_info, paint_flags);
+    }
+  }
+
+  if (is_video && should_paint_self_outline) {
+    // We paint outlines for video later so that they aren't obscured by the
+    // video controls.
+    PaintSelfOutlineForFragments(layer_fragments, context, local_painting_info,
+                                 paint_flags);
+  }
+
+  if (is_painting_mask && should_paint_content && !selection_drag_image_only) {
+    const auto* properties =
+        paint_layer_.GetLayoutObject().FirstFragment().PaintProperties();
+    if (properties) {
+      if (properties->Mask()) {
+        PaintMaskForFragments(layer_fragments, context, local_painting_info,
+                              paint_flags);
+      }
+      if (properties->ClipPathMask()) {
+        PhysicalOffset visual_offset_from_root =
+            paint_layer_.EnclosingPaginationLayer()
+                ? paint_layer_.VisualOffsetFromAncestor(
+                      local_painting_info.root_layer, subpixel_accumulation)
+                : offset_from_root;
+        ClipPathClipper::PaintClipPathAsMaskImage(
+            context, paint_layer_.GetLayoutObject(),
+            paint_layer_.GetLayoutObject(), visual_offset_from_root);
+      }
+    }
+  }
 
   paint_layer_.SetPreviousPaintResult(result);
   paint_layer_.SetPreviousCullRect(local_painting_info.cull_rect);
@@ -689,15 +651,9 @@
   auto chunk_properties = fragment.fragment_data->LocalBorderBoxProperties();
   if (phase == PaintPhase::kMask) {
     const auto* properties = fragment.fragment_data->PaintProperties();
-    DCHECK(properties && properties->Mask());
+    DCHECK(properties);
+    DCHECK(properties->Mask());
     chunk_properties.SetEffect(*properties->Mask());
-    // Special case for SPv1 composited mask layer. Path-based clip-path
-    // is only applies to the mask chunk, but not to the layer property
-    // or local box box property.
-    if (properties->ClipPathClip() &&
-        properties->ClipPathClip()->Parent() == properties->MaskClip()) {
-      chunk_properties.SetClip(*properties->ClipPathClip());
-    }
   }
   ScopedPaintChunkProperties fragment_paint_chunk_properties(
       context.GetPaintController(), chunk_properties, paint_layer_,
@@ -826,16 +782,4 @@
   Paint(context, painting_info, kPaintLayerPaintingOverlayOverflowControls);
 }
 
-void PaintLayerPainter::FillMaskingFragment(GraphicsContext& context,
-                                            const ClipRect& clip_rect,
-                                            const DisplayItemClient& client) {
-  if (DrawingRecorder::UseCachedDrawingIfPossible(context, client,
-                                                  DisplayItem::kClippingMask))
-    return;
-
-  DrawingRecorder recorder(context, client, DisplayItem::kClippingMask);
-  IntRect snapped_clip_rect = PixelSnappedIntRect(clip_rect.Rect());
-  context.FillRect(snapped_clip_rect, Color::kBlack);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_layer_painter.h b/third_party/blink/renderer/core/paint/paint_layer_painter.h
index 29e13df..fd6326d 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_painter.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_painter.h
@@ -17,7 +17,6 @@
 class CullRect;
 class ClipRect;
 class ComputedStyle;
-class DisplayItemClient;
 class GraphicsContext;
 struct PhysicalOffset;
 
@@ -101,10 +100,6 @@
                              const PaintLayerPaintingInfo&,
                              PaintLayerFlags);
 
-  void FillMaskingFragment(GraphicsContext&,
-                           const ClipRect&,
-                           const DisplayItemClient&);
-
   void AdjustForPaintProperties(const GraphicsContext&,
                                 PaintLayerPaintingInfo&,
                                 PaintLayerFlags&);
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 1978c54..d84a7d6 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -2481,10 +2481,17 @@
 
 bool PaintLayerScrollableArea::ComputeNeedsCompositedScrolling(
     bool force_prefer_compositing_to_lcd_text) {
-  DCHECK_EQ(RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
-                ? DocumentLifecycle::kInPrePaint
-                : DocumentLifecycle::kInCompositingUpdate,
-            GetDocument()->Lifecycle().GetState());
+#if DCHECK_IS_ON()
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+    DCHECK_EQ(DocumentLifecycle::kInPrePaint,
+              GetDocument()->Lifecycle().GetState());
+  } else {
+    DCHECK(GetDocument()->Lifecycle().GetState() ==
+               DocumentLifecycle::kInCompositingInputsUpdate ||
+           GetDocument()->Lifecycle().GetState() ==
+               DocumentLifecycle::kInCompositingUpdate);
+  }
+#endif
 
   const auto* box = GetLayoutBox();
   auto old_background_paint_location = box->GetBackgroundPaintLocation();
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index f0da26d..71f6cdc2 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -200,7 +200,7 @@
   ALWAYS_INLINE void UpdateFilter();
   ALWAYS_INLINE void UpdateFragmentClip();
   ALWAYS_INLINE void UpdateCssClip();
-  ALWAYS_INLINE void UpdateClipPathClip(bool spv1_compositing_specific_pass);
+  ALWAYS_INLINE void UpdateClipPathClip();
   ALWAYS_INLINE void UpdateLocalBorderBoxContext();
   ALWAYS_INLINE bool NeedsOverflowControlsClip() const;
   ALWAYS_INLINE void UpdateOverflowControlsClip();
@@ -935,13 +935,6 @@
     if (layer->HasNonIsolatedDescendantWithBlendMode())
       return true;
 
-    // In SPv1* a mask layer can be created for clip-path in absence of mask,
-    // and a mask effect node must be created whether the clip-path is
-    // path-based or not.
-    if (layer->GetCompositedLayerMapping() &&
-        layer->GetCompositedLayerMapping()->MaskLayer())
-      return true;
-
     // An effect node is required by cc if the layer flattens its subtree but it
     // is treated as a 3D object by its parent.
     if (!layer->Preserves3D() && layer->HasSelfPaintingLayerDescendant() &&
@@ -1026,27 +1019,11 @@
           object_, context_.current.paint_offset);
       bool has_clip_path =
           style.ClipPath() && fragment_data_.ClipPathBoundingBox();
-      bool is_spv1_composited =
-          object_.HasLayer() &&
-          ToLayoutBoxModelObject(object_).Layer()->GetCompositedLayerMapping();
-      bool has_spv1_composited_clip_path = has_clip_path && is_spv1_composited;
       bool has_mask_based_clip_path =
           has_clip_path && !fragment_data_.ClipPathPath();
       base::Optional<IntRect> clip_path_clip;
-      if (has_spv1_composited_clip_path || has_mask_based_clip_path) {
+      if (has_mask_based_clip_path)
         clip_path_clip = fragment_data_.ClipPathBoundingBox();
-      } else if (!mask_clip && is_spv1_composited &&
-                 ToLayoutBoxModelObject(object_)
-                     .Layer()
-                     ->GetCompositedLayerMapping()
-                     ->MaskLayer()) {
-        // TODO(crbug.com/856818): This should never happen.
-        // This is a band-aid to avoid nullptr properties on the mask layer
-        // crashing the renderer, but will result in incorrect rendering.
-        NOTREACHED();
-        has_spv1_composited_clip_path = true;
-        clip_path_clip = IntRect();
-      }
 
       const auto* output_clip = EffectCanUseCurrentClipAsOutputClip()
                                     ? context_.current.clip
@@ -1067,7 +1044,7 @@
       }
 
       CompositorElementId mask_compositor_element_id;
-      if (mask_clip || has_spv1_composited_clip_path) {
+      if (mask_clip) {
         mask_compositor_element_id =
             GetCompositorElementId(CompositorElementIdNamespace::kEffectMask);
       }
@@ -1150,7 +1127,7 @@
       }
       OnUpdate(effective_change_type);
 
-      if (mask_clip || has_spv1_composited_clip_path) {
+      if (mask_clip) {
         EffectPaintPropertyNode::State mask_state;
         mask_state.local_transform_space = context_.current.transform;
         mask_state.output_clip = output_clip;
@@ -1164,24 +1141,22 @@
       }
 
       if (has_mask_based_clip_path) {
-        const EffectPaintPropertyNode& parent = has_spv1_composited_clip_path
-                                                    ? *properties_->Mask()
-                                                    : *properties_->Effect();
         EffectPaintPropertyNode::State clip_path_state;
         clip_path_state.local_transform_space = context_.current.transform;
         clip_path_state.output_clip = output_clip;
         clip_path_state.blend_mode = SkBlendMode::kDstIn;
         clip_path_state.compositor_element_id = GetCompositorElementId(
             CompositorElementIdNamespace::kEffectClipPath);
-        OnUpdate(
-            properties_->UpdateClipPath(parent, std::move(clip_path_state)));
+        OnUpdate(properties_->UpdateClipPathMask(
+            properties_->Mask() ? *properties_->Mask() : *properties_->Effect(),
+            std::move(clip_path_state)));
       } else {
-        OnClear(properties_->ClearClipPath());
+        OnClear(properties_->ClearClipPathMask());
       }
     } else {
       OnClear(properties_->ClearEffect());
       OnClear(properties_->ClearMask());
-      OnClear(properties_->ClearClipPath());
+      OnClear(properties_->ClearClipPathMask());
       OnClearClip(properties_->ClearMaskClip());
     }
   }
@@ -1372,17 +1347,7 @@
     context_.current.clip = properties_->CssClip();
 }
 
-void FragmentPaintPropertyTreeBuilder::UpdateClipPathClip(
-    bool spv1_compositing_specific_pass) {
-  // In SPv1*, composited path-based clip-path applies to a mask paint chunk
-  // instead of actual contents. We have to delay until mask clip node has been
-  // created first so we can parent under it.
-  bool is_spv1_composited =
-      object_.HasLayer() &&
-      ToLayoutBoxModelObject(object_).Layer()->GetCompositedLayerMapping();
-  if (is_spv1_composited != spv1_compositing_specific_pass)
-    return;
-
+void FragmentPaintPropertyTreeBuilder::UpdateClipPathClip() {
   if (NeedsPaintPropertyUpdate()) {
     if (!NeedsClipPathClip(object_)) {
       OnClearClip(properties_->ClearClipPathClip());
@@ -1396,7 +1361,7 @@
     }
   }
 
-  if (properties_->ClipPathClip() && !spv1_compositing_specific_pass) {
+  if (properties_->ClipPathClip()) {
     context_.current.clip = context_.absolute_position.clip =
         context_.fixed_position.clip = properties_->ClipPathClip();
   }
@@ -2573,11 +2538,7 @@
   }
   bounding_box->MoveBy(FloatPoint(fragment_data_.PaintOffset()));
 
-  bool is_valid = false;
-  base::Optional<Path> path = ClipPathClipper::PathBasedClip(
-      object_, object_.IsSVGChild(),
-      ClipPathClipper::LocalReferenceBox(object_), is_valid);
-  DCHECK(is_valid);
+  base::Optional<Path> path = ClipPathClipper::PathBasedClip(object_);
   if (path)
     path->Translate(ToFloatSize(FloatPoint(fragment_data_.PaintOffset())));
   fragment_data_.SetClipPathCache(
@@ -2622,9 +2583,8 @@
   if (properties_) {
     UpdateStickyTranslation();
     UpdateTransform();
-    UpdateClipPathClip(false);
+    UpdateClipPathClip();
     UpdateEffect();
-    UpdateClipPathClip(true);  // Special pass for SPv1 composited clip-path.
     UpdateCssClip();
     UpdateFilter();
     UpdateOverflowControlsClip();
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 3b8e3e4..62affd8 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -5560,7 +5560,7 @@
     const auto* rect = GetLayoutObjectByElementId("rect");
     ASSERT_TRUE(rect);
     EXPECT_TRUE(rect->FirstFragment().PaintProperties()->MaskClip());
-    EXPECT_TRUE(rect->FirstFragment().PaintProperties()->ClipPath());
+    EXPECT_TRUE(rect->FirstFragment().PaintProperties()->ClipPathMask());
   }
 
   Element* clip = GetDocument().getElementById("clip");
@@ -5573,7 +5573,7 @@
     const auto* rect = GetLayoutObjectByElementId("rect");
     ASSERT_TRUE(rect);
     EXPECT_FALSE(rect->FirstFragment().PaintProperties()->MaskClip());
-    EXPECT_FALSE(rect->FirstFragment().PaintProperties()->ClipPath());
+    EXPECT_FALSE(rect->FirstFragment().PaintProperties()->ClipPathMask());
   }
 }
 
@@ -6378,81 +6378,35 @@
   EXPECT_EQ(properties->PaintOffsetTranslation(), transform->Parent());
   EXPECT_TRUE(transform->HasDirectCompositingReasons());
 
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-    EXPECT_EQ(nullptr, properties->MaskClip());
+  EXPECT_EQ(nullptr, properties->MaskClip());
 
-    const auto* clip_path_clip = properties->ClipPathClip();
-    ASSERT_NE(nullptr, clip_path_clip);
-    EXPECT_EQ(DocContentClip(), clip_path_clip->Parent());
-    EXPECT_EQ(FloatRect(75, 0, 150, 150),
-              clip_path_clip->UnsnappedClipRect().Rect());
-    EXPECT_EQ(transform, &clip_path_clip->LocalTransformSpace());
-    EXPECT_NE(nullptr, clip_path_clip->ClipPath());
+  const auto* clip_path_clip = properties->ClipPathClip();
+  ASSERT_NE(nullptr, clip_path_clip);
+  EXPECT_EQ(DocContentClip(), clip_path_clip->Parent());
+  EXPECT_EQ(FloatRect(75, 0, 150, 150),
+            clip_path_clip->UnsnappedClipRect().Rect());
+  EXPECT_EQ(transform, &clip_path_clip->LocalTransformSpace());
+  EXPECT_NE(nullptr, clip_path_clip->ClipPath());
 
-    const auto* overflow_clip = properties->OverflowClip();
-    ASSERT_NE(nullptr, overflow_clip);
-    EXPECT_EQ(clip_path_clip, overflow_clip->Parent());
-    EXPECT_EQ(FloatRect(0, 0, 300, 150),
-              overflow_clip->UnsnappedClipRect().Rect());
-    EXPECT_EQ(transform, &overflow_clip->LocalTransformSpace());
+  const auto* overflow_clip = properties->OverflowClip();
+  ASSERT_NE(nullptr, overflow_clip);
+  EXPECT_EQ(clip_path_clip, overflow_clip->Parent());
+  EXPECT_EQ(FloatRect(0, 0, 300, 150),
+            overflow_clip->UnsnappedClipRect().Rect());
+  EXPECT_EQ(transform, &overflow_clip->LocalTransformSpace());
 
-    const auto* effect = properties->Effect();
-    ASSERT_NE(nullptr, effect);
-    EXPECT_EQ(&EffectPaintPropertyNode::Root(), effect->Parent());
-    EXPECT_EQ(transform, &effect->LocalTransformSpace());
-    EXPECT_EQ(clip_path_clip, effect->OutputClip());
-    EXPECT_EQ(SkBlendMode::kSrcOver, effect->BlendMode());
+  const auto* effect = properties->Effect();
+  ASSERT_NE(nullptr, effect);
+  EXPECT_EQ(&EffectPaintPropertyNode::Root(), effect->Parent());
+  EXPECT_EQ(transform, &effect->LocalTransformSpace());
+  EXPECT_EQ(clip_path_clip, effect->OutputClip());
+  EXPECT_EQ(SkBlendMode::kSrcOver, effect->BlendMode());
 
-    EXPECT_EQ(nullptr, properties->Mask());
-    EXPECT_EQ(nullptr, properties->ClipPath());
-  } else {
-    const auto* mask_clip = properties->MaskClip();
-    ASSERT_NE(nullptr, mask_clip);
-    EXPECT_EQ(DocContentClip(), mask_clip->Parent());
-    EXPECT_EQ(FloatRect(75, 0, 150, 150),
-              mask_clip->UnsnappedClipRect().Rect());
-    EXPECT_EQ(nullptr, mask_clip->ClipPath());
-    EXPECT_EQ(transform, &mask_clip->LocalTransformSpace());
-
-    const auto* clip_path_clip = properties->ClipPathClip();
-    ASSERT_NE(nullptr, clip_path_clip);
-    EXPECT_EQ(mask_clip, clip_path_clip->Parent());
-    EXPECT_EQ(FloatRect(75, 0, 150, 150),
-              clip_path_clip->UnsnappedClipRect().Rect());
-    EXPECT_EQ(transform, &clip_path_clip->LocalTransformSpace());
-    EXPECT_NE(nullptr, clip_path_clip->ClipPath());
-
-    const auto* overflow_clip = properties->OverflowClip();
-    ASSERT_NE(nullptr, overflow_clip);
-    EXPECT_EQ(mask_clip, overflow_clip->Parent());
-    EXPECT_EQ(FloatRect(0, 0, 300, 150),
-              overflow_clip->UnsnappedClipRect().Rect());
-    EXPECT_EQ(transform, &overflow_clip->LocalTransformSpace());
-
-    const auto* effect = properties->Effect();
-    ASSERT_NE(nullptr, effect);
-    EXPECT_EQ(&EffectPaintPropertyNode::Root(), effect->Parent());
-    EXPECT_EQ(transform, &effect->LocalTransformSpace());
-    EXPECT_EQ(mask_clip, effect->OutputClip());
-    EXPECT_EQ(SkBlendMode::kSrcOver, effect->BlendMode());
-
-    const auto* mask = properties->Mask();
-    ASSERT_NE(nullptr, mask);
-    EXPECT_EQ(effect, mask->Parent());
-    EXPECT_EQ(transform, &mask->LocalTransformSpace());
-    EXPECT_EQ(mask_clip, mask->OutputClip());
-    EXPECT_EQ(SkBlendMode::kDstIn, mask->BlendMode());
-
-    EXPECT_EQ(nullptr, properties->ClipPath());
-  }
+  EXPECT_EQ(nullptr, properties->Mask());
+  EXPECT_EQ(nullptr, properties->ClipPathMask());
 }
 
 TEST_P(PaintPropertyTreeBuilderTest, SimpleOpacityChangeDoesNotCausePacUpdate) {
-  // TODO(vmpstr): For CompositeAfterPaint, we don't seem to get a
-  // cc_effect, which we need to investigate.
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    return;
-
   SetHtmlInnerHTML(R"HTML(
     <style>
       div {
@@ -6631,12 +6585,8 @@
   const auto& span_all_state = GetLayoutObjectByElementId("span-all")
                                    ->FirstFragment()
                                    .LocalBorderBoxProperties();
-  EXPECT_EQ(clip_path_properties->MaskClip(),
+  EXPECT_EQ(clip_path_properties->ClipPathClip(),
             span_all_state.Clip().Parent()->Parent());
-  // TODO(crbug.com/900241): We create effect and filter nodes when the
-  // transform node needs compositing, for crbug.com/942681.
-  EXPECT_EQ(clip_path_properties->Effect(),
-            span_all_state.Effect().Parent()->Parent()->Parent());
 }
 
 TEST_P(PaintPropertyTreeBuilderTest, VideoClipRect) {
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc b/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc
index 7cf6258d..0d4bc13 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_printer.cc
@@ -123,7 +123,7 @@
     printer.AddNode(properties.VerticalScrollbarEffect());
     printer.AddNode(properties.HorizontalScrollbarEffect());
     printer.AddNode(properties.Mask());
-    printer.AddNode(properties.ClipPath());
+    printer.AddNode(properties.ClipPathMask());
     printer.AddNode(properties.EffectIsolationNode());
   }
 };
@@ -206,7 +206,7 @@
   SetDebugName(properties.HorizontalScrollbarEffect(),
                "HorizontalScrollbarEffect", object);
   SetDebugName(properties.Mask(), "Mask", object);
-  SetDebugName(properties.ClipPath(), "ClipPath", object);
+  SetDebugName(properties.ClipPathMask(), "ClipPathMask", object);
   SetDebugName(properties.EffectIsolationNode(), "EffectIsolationNode", object);
 
   SetDebugName(properties.Scroll(), "Scroll", object);
diff --git a/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc b/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
index a3a2e9389..4c78d7e0 100644
--- a/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
+++ b/third_party/blink/renderer/core/paint/scoped_svg_paint_state.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
+#include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
@@ -103,21 +104,31 @@
                          filter_data_);
     filter_data_ = nullptr;
   }
+
+  if (should_paint_clip_path_as_mask_image_) {
+    ClipPathClipper::PaintClipPathAsMaskImage(GetPaintInfo().context, object_,
+                                              display_item_client_,
+                                              PhysicalOffset());
+  }
 }
 
 bool ScopedSVGPaintState::ApplyEffects() {
 #if DCHECK_IS_ON()
-  DCHECK(!apply_clip_mask_and_filter_if_necessary_called_);
-  apply_clip_mask_and_filter_if_necessary_called_ = true;
+  DCHECK(!apply_effects_called_);
+  apply_effects_called_ = true;
 #endif
-  ApplyPaintPropertyState();
+
+  const auto* properties = object_.FirstFragment().PaintProperties();
+  if (properties)
+    ApplyPaintPropertyState(*properties);
 
   // When rendering clip paths as masks, only geometric operations should be
-  // included so skip non-geometric operations such as compositing, masking, and
-  // filtering.
+  // included so skip non-geometric operations such as compositing, masking,
+  // and filtering.
   if (GetPaintInfo().IsRenderingClipPathAsMaskImage()) {
     DCHECK(!object_.IsSVGRoot());
-    ApplyClipIfNecessary();
+    if (properties && properties->ClipPathMask())
+      should_paint_clip_path_as_mask_image_ = true;
     return true;
   }
 
@@ -126,12 +137,10 @@
   bool is_svg_root_or_foreign_object =
       object_.IsSVGRoot() || object_.IsSVGForeignObject();
   if (is_svg_root_or_foreign_object) {
-    // PaintLayerPainter takes care of opacity and blend mode.
-    DCHECK(object_.HasLayer() || !(object_.StyleRef().HasOpacity() ||
-                                   object_.StyleRef().HasBlendMode() ||
-                                   object_.StyleRef().ClipPath()));
-  } else {
-    ApplyClipIfNecessary();
+    // PaintLayerPainter takes care of clip path.
+    DCHECK(object_.HasLayer() || !properties || !properties->ClipPathMask());
+  } else if (properties && properties->ClipPathMask()) {
+    should_paint_clip_path_as_mask_image_ = true;
   }
 
   SVGResources* resources =
@@ -141,47 +150,37 @@
 
   if (is_svg_root_or_foreign_object) {
     // PaintLayerPainter takes care of filter.
-    DCHECK(object_.HasLayer() || !object_.StyleRef().HasFilter());
+    DCHECK(object_.HasLayer() || !properties || !properties->Filter());
   } else if (!ApplyFilterIfNecessary(resources)) {
     return false;
   }
   return true;
 }
 
-void ScopedSVGPaintState::ApplyPaintPropertyState() {
+void ScopedSVGPaintState::ApplyPaintPropertyState(
+    const ObjectPaintProperties& properties) {
   // SVGRoot works like normal CSS replaced element and its effects are
   // applied as stacking context effect by PaintLayerPainter.
   if (object_.IsSVGRoot())
     return;
 
-  const auto* fragment = GetPaintInfo().FragmentToPaint(object_);
-  if (!fragment)
-    return;
-  const auto* properties = fragment->PaintProperties();
   // MaskClip() implies Effect(), thus we don't need to check MaskClip().
-  if (!properties || (!properties->Effect() && !properties->ClipPathClip()))
+  if (!properties.Effect() && !properties.ClipPathClip())
     return;
 
   auto& paint_controller = GetPaintInfo().context.GetPaintController();
   auto state = paint_controller.CurrentPaintChunkProperties();
-  if (const auto* effect = properties->Effect())
+  if (const auto* effect = properties.Effect())
     state.SetEffect(*effect);
-  if (const auto* mask_clip = properties->MaskClip())
+  if (const auto* mask_clip = properties.MaskClip())
     state.SetClip(*mask_clip);
-  else if (const auto* clip_path_clip = properties->ClipPathClip())
+  else if (const auto* clip_path_clip = properties.ClipPathClip())
     state.SetClip(*clip_path_clip);
   scoped_paint_chunk_properties_.emplace(
       paint_controller, state, display_item_client_,
       DisplayItem::PaintPhaseToSVGEffectType(GetPaintInfo().phase));
 }
 
-void ScopedSVGPaintState::ApplyClipIfNecessary() {
-  if (object_.StyleRef().ClipPath()) {
-    clip_path_clipper_.emplace(GetPaintInfo().context, object_,
-                               display_item_client_, PhysicalOffset());
-  }
-}
-
 void ScopedSVGPaintState::ApplyMaskIfNecessary(SVGResources* resources) {
   if (resources && resources->Masker())
     mask_painter_.emplace(paint_info_.context, object_, display_item_client_);
diff --git a/third_party/blink/renderer/core/paint/scoped_svg_paint_state.h b/third_party/blink/renderer/core/paint/scoped_svg_paint_state.h
index 2cbc046..89d9572 100644
--- a/third_party/blink/renderer/core/paint/scoped_svg_paint_state.h
+++ b/third_party/blink/renderer/core/paint/scoped_svg_paint_state.h
@@ -27,7 +27,6 @@
 
 #include <memory>
 #include "base/macros.h"
-#include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
 #include "third_party/blink/renderer/core/paint/object_paint_properties.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
 #include "third_party/blink/renderer/core/paint/svg_mask_painter.h"
@@ -40,6 +39,7 @@
 class FilterData;
 class GraphicsContext;
 class LayoutObject;
+class ObjectPaintProperties;
 class PaintController;
 class SVGResources;
 
@@ -123,7 +123,7 @@
   bool ApplyEffects();
 
  private:
-  void ApplyPaintPropertyState();
+  void ApplyPaintPropertyState(const ObjectPaintProperties&);
   void ApplyClipIfNecessary();
   void ApplyMaskIfNecessary(SVGResources*);
 
@@ -135,12 +135,12 @@
   PaintInfo paint_info_;
   const DisplayItemClient& display_item_client_;
   FilterData* filter_data_;
-  base::Optional<ClipPathClipper> clip_path_clipper_;
   std::unique_ptr<SVGFilterRecordingContext> filter_recording_context_;
   base::Optional<ScopedPaintChunkProperties> scoped_paint_chunk_properties_;
   base::Optional<SVGMaskPainter> mask_painter_;
+  bool should_paint_clip_path_as_mask_image_ = false;
 #if DCHECK_IS_ON()
-  bool apply_clip_mask_and_filter_if_necessary_called_ = false;
+  bool apply_effects_called_ = false;
 #endif
 };
 
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index d18859ca..82b2dc0 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -2270,6 +2270,13 @@
                unvisited_color.Alpha());
 }
 
+Color ComputedStyle::ResolvedColor(const StyleColor& color) const {
+  bool visited_link = (InsideLink() == EInsideLink::kInsideVisitedLink);
+  Color current_color =
+      visited_link ? GetInternalVisitedCurrentColor() : GetCurrentColor();
+  return color.Resolve(current_color);
+}
+
 void ComputedStyle::SetMarginStart(const Length& margin) {
   if (IsHorizontalWritingMode()) {
     if (IsLeftToRightDirection())
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 8927e67..a9ff4df 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2534,6 +2534,13 @@
   CORE_EXPORT Color
   VisitedDependentColor(const CSSProperty& color_property) const;
 
+  // Helper for resolving a StyleColor which may contain currentColor or a
+  // system color keyword. This is intended for cases such as SVG <paint> where
+  // a given property consists of a StyleColor plus additional information. For
+  // <color> properties, prefer VisitedDependentColor() or
+  // Longhand::ColorIncludingFallback() instead.
+  Color ResolvedColor(const StyleColor& color) const;
+
   // -webkit-appearance utility functions.
   bool HasEffectiveAppearance() const {
     return EffectiveAppearance() != kNoControlPart;
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index 63dec850..592a480 100644
--- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -960,6 +960,12 @@
       custom_compare: true,
     },
     {
+      name: "IsFlexOrGridItem",
+      field_template: "monotonic_flag",
+      default_value: "false",
+      custom_compare: true,
+    },
+    {
       name: "ListStyleType",
       inherited: true,
       field_template: "keyword",
diff --git a/third_party/blink/renderer/core/style/svg_computed_style_defs.cc b/third_party/blink/renderer/core/style/svg_computed_style_defs.cc
index b578cb8b..9b1daa50 100644
--- a/third_party/blink/renderer/core/style/svg_computed_style_defs.cc
+++ b/third_party/blink/renderer/core/style/svg_computed_style_defs.cc
@@ -33,8 +33,8 @@
 
 namespace blink {
 
-SVGPaint::SVGPaint() : type(SVG_PAINTTYPE_NONE) {}
-SVGPaint::SVGPaint(Color color) : color(color), type(SVG_PAINTTYPE_RGBCOLOR) {}
+SVGPaint::SVGPaint() = default;
+SVGPaint::SVGPaint(Color color) : color(color), type(SVG_PAINTTYPE_COLOR) {}
 SVGPaint::SVGPaint(const SVGPaint& paint) = default;
 
 SVGPaint::~SVGPaint() = default;
diff --git a/third_party/blink/renderer/core/style/svg_computed_style_defs.h b/third_party/blink/renderer/core/style/svg_computed_style_defs.h
index 217720b..85e444a 100644
--- a/third_party/blink/renderer/core/style/svg_computed_style_defs.h
+++ b/third_party/blink/renderer/core/style/svg_computed_style_defs.h
@@ -33,7 +33,6 @@
 #include "third_party/blink/renderer/core/css/style_color.h"
 #include "third_party/blink/renderer/core/style/style_path.h"
 #include "third_party/blink/renderer/platform/geometry/length.h"
-#include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -45,12 +44,10 @@
 typedef base::RefCountedData<WTF::Vector<Length>> SVGDashArray;
 
 enum SVGPaintType {
-  SVG_PAINTTYPE_RGBCOLOR,
+  SVG_PAINTTYPE_COLOR,
   SVG_PAINTTYPE_NONE,
-  SVG_PAINTTYPE_CURRENTCOLOR,
   SVG_PAINTTYPE_URI_NONE,
-  SVG_PAINTTYPE_URI_CURRENTCOLOR,
-  SVG_PAINTTYPE_URI_RGBCOLOR,
+  SVG_PAINTTYPE_URI_COLOR,
   SVG_PAINTTYPE_URI
 };
 
@@ -132,32 +129,24 @@
   bool operator!=(const SVGPaint& other) const { return !(*this == other); }
 
   bool IsNone() const { return type == SVG_PAINTTYPE_NONE; }
-  bool IsColor() const {
-    return type == SVG_PAINTTYPE_RGBCOLOR || type == SVG_PAINTTYPE_CURRENTCOLOR;
-  }
+  bool IsColor() const { return type == SVG_PAINTTYPE_COLOR; }
   // Used by CSSPropertyEquality::PropertiesEqual.
   bool EqualTypeOrColor(const SVGPaint& other) const {
     return type == other.type &&
-           (type != SVG_PAINTTYPE_RGBCOLOR || color == other.color);
+           (type != SVG_PAINTTYPE_COLOR || color == other.color);
   }
-  bool HasFallbackColor() const {
-    return type == SVG_PAINTTYPE_URI_CURRENTCOLOR ||
-           type == SVG_PAINTTYPE_URI_RGBCOLOR;
-  }
+  bool HasFallbackColor() const { return type == SVG_PAINTTYPE_URI_COLOR; }
   bool HasColor() const { return IsColor() || HasFallbackColor(); }
   bool HasUrl() const { return type >= SVG_PAINTTYPE_URI_NONE; }
-  bool HasCurrentColor() const {
-    return type == SVG_PAINTTYPE_CURRENTCOLOR ||
-           type == SVG_PAINTTYPE_URI_CURRENTCOLOR;
-  }
+  bool HasCurrentColor() const { return HasColor() && color.IsCurrentColor(); }
   StyleSVGResource* Resource() const { return resource.get(); }
 
-  const Color& GetColor() const { return color; }
+  const StyleColor& GetColor() const { return color; }
   const AtomicString& GetUrl() const;
 
   scoped_refptr<StyleSVGResource> resource;
-  Color color;
-  SVGPaintType type;
+  StyleColor color;
+  SVGPaintType type{SVG_PAINTTYPE_NONE};
 };
 
 // Inherited/Non-Inherited Style Datastructures
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.cc b/third_party/blink/renderer/core/svg/svg_animate_element.cc
index 4d33399..aa3a502 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_element.cc
@@ -494,7 +494,8 @@
     auto& document = target_element->GetDocument();
     auto set_result = properties->SetProperty(
         css_property_id_, animated_value_string, false,
-        document.GetSecureContextMode(), document.ElementSheet().Contents());
+        document.GetExecutionContext()->GetSecureContextMode(),
+        document.ElementSheet().Contents());
     if (set_result.did_change) {
       target_element->SetNeedsStyleRecalc(
           kLocalStyleChange,
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
index 4032799..a22c1e91 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
@@ -165,8 +165,7 @@
     prefix = "Function";
   }
   bool allow =
-      execution_context->GetSecurityContext()
-          .GetContentSecurityPolicy()
+      execution_context->GetContentSecurityPolicy()
           ->AllowTrustedTypeAssignmentFailure(
               GetMessage(kind),
               prefix == "Function" ? value.Substring(strlen(kAnonymousPrefix))
@@ -181,9 +180,8 @@
     DCHECK(kind == kTrustedScriptAssignment ||
            kind == kTrustedScriptAssignmentAndDefaultPolicyFailed ||
            kind == kTrustedScriptAssignmentAndNoDefaultPolicyExisted);
-    execution_context->GetSecurityContext()
-        .GetContentSecurityPolicy()
-        ->LogToConsole(MakeGarbageCollected<ConsoleMessage>(
+    execution_context->GetContentSecurityPolicy()->LogToConsole(
+        MakeGarbageCollected<ConsoleMessage>(
             mojom::blink::ConsoleMessageSource::kRecommendation,
             mojom::blink::ConsoleMessageLevel::kInfo,
             kFunctionConstructorFailureConsoleMessage));
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
index a87d83d..7e157dd 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container_test.cc
@@ -107,8 +107,10 @@
   CredentialManagerTestingContext(
       MockCredentialManager* mock_credential_manager)
       : dummy_context_(KURL("https://example.test")) {
-    dummy_context_.GetDocument().SetSecureContextModeForTesting(
-        SecureContextMode::kSecureContext);
+    dummy_context_.GetFrame()
+        .DomWindow()
+        ->GetSecurityContext()
+        .SetSecureContextModeForTesting(SecureContextMode::kSecureContext);
 
     dummy_context_.GetFrame().GetBrowserInterfaceBroker().SetBinderForTesting(
         ::blink::mojom::blink::CredentialManager::Name_,
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_source_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_source_test.cc
index d6ae942f..7bcd16c 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_source_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_source_test.cc
@@ -21,6 +21,7 @@
 #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h"
 #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_source.h"
 #include "third_party/blink/renderer/modules/mediastream/video_track_adapter_settings.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
 #include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
@@ -40,44 +41,37 @@
         number_of_failed_constraints_applied_(0),
         result_(mojom::MediaStreamRequestResult::OK),
         result_name_(""),
-        mock_source_(new MockMediaStreamVideoSource(
+        mock_stream_video_source_(new MockMediaStreamVideoSource(
             media::VideoCaptureFormat(gfx::Size(1280, 720),
                                       1000.0,
                                       media::PIXEL_FORMAT_I420),
             false)) {
-    mock_source_->DisableStopForRestart();
-    media::VideoCaptureFormats formats;
-    formats.push_back(media::VideoCaptureFormat(gfx::Size(1280, 720), 30,
-                                                media::PIXEL_FORMAT_I420));
-    formats.push_back(media::VideoCaptureFormat(gfx::Size(640, 480), 30,
-                                                media::PIXEL_FORMAT_I420));
-    formats.push_back(media::VideoCaptureFormat(gfx::Size(352, 288), 30,
-                                                media::PIXEL_FORMAT_I420));
-    formats.push_back(media::VideoCaptureFormat(gfx::Size(320, 240), 30,
-                                                media::PIXEL_FORMAT_I420));
-    web_source_.Initialize(WebString::FromASCII("dummy_source_id"),
-                           WebMediaStreamSource::kTypeVideo,
-                           WebString::FromASCII("dummy_source_name"),
-                           false /* remote */);
-    web_source_.SetPlatformSource(base::WrapUnique(mock_source_));
-    ON_CALL(*mock_source_, SupportsEncodedOutput).WillByDefault(Return(true));
+    mock_stream_video_source_->DisableStopForRestart();
+    stream_source_ = MakeGarbageCollected<MediaStreamSource>(
+        String::FromUTF8("dummy_source_id"), MediaStreamSource::kTypeVideo,
+        String::FromUTF8("dummy_source_name"), false /* remote */);
+    mock_stream_video_source_->SetOwner(stream_source_);
+    stream_source_->SetPlatformSource(
+        base::WrapUnique(mock_stream_video_source_));
+    ON_CALL(*mock_stream_video_source_, SupportsEncodedOutput)
+        .WillByDefault(Return(true));
   }
 
   void TearDown() override {
-    web_source_.Reset();
+    stream_source_ = nullptr;
     WebHeap::CollectAllGarbageForTesting();
   }
 
   MOCK_METHOD0(MockNotification, void());
 
  protected:
-  MediaStreamVideoSource* source() { return mock_source_; }
+  MediaStreamVideoSource* source() { return mock_stream_video_source_; }
 
-  // Create a track that's associated with |web_source_|.
+  // Create a track that's associated with |stream_source_|.
   WebMediaStreamTrack CreateTrack(const std::string& id) {
     bool enabled = true;
     return MediaStreamVideoTrack::CreateVideoTrack(
-        mock_source_,
+        mock_stream_video_source_,
         WTF::Bind(&MediaStreamVideoSourceTest::OnConstraintsApplied,
                   base::Unretained(this)),
         enabled);
@@ -91,8 +85,9 @@
       double min_frame_rate) {
     bool enabled = true;
     return MediaStreamVideoTrack::CreateVideoTrack(
-        mock_source_, adapter_settings, noise_reduction, is_screencast,
-        min_frame_rate, base::nullopt, base::nullopt, base::nullopt, false,
+        mock_stream_video_source_, adapter_settings, noise_reduction,
+        is_screencast, min_frame_rate, base::nullopt, base::nullopt,
+        base::nullopt, false,
         WTF::Bind(&MediaStreamVideoSourceTest::OnConstraintsApplied,
                   base::Unretained(this)),
         enabled);
@@ -113,7 +108,7 @@
         base::Optional<bool>(), false, 0.0);
 
     EXPECT_EQ(0, NumberOfSuccessConstraintsCallbacks());
-    mock_source_->StartMockedSource();
+    mock_stream_video_source_->StartMockedSource();
     // Once the source has started successfully we expect that the
     // ConstraintsOnceCallback in WebPlatformMediaStreamSource::AddTrack
     // completes.
@@ -132,9 +127,11 @@
   mojom::MediaStreamRequestResult error_type() const { return result_; }
   WebString error_name() const { return result_name_; }
 
-  MockMediaStreamVideoSource* mock_source() { return mock_source_; }
+  MockMediaStreamVideoSource* mock_source() {
+    return mock_stream_video_source_;
+  }
 
-  const WebMediaStreamSource& web_source() { return web_source_; }
+  MediaStreamSource* stream_source() { return stream_source_.Get(); }
 
   void TestSourceCropFrame(int capture_width,
                            int capture_height,
@@ -242,7 +239,7 @@
   void OnConstraintsApplied(WebPlatformMediaStreamSource* source,
                             mojom::MediaStreamRequestResult result,
                             const WebString& result_name) {
-    ASSERT_EQ(source, web_source().GetPlatformSource());
+    ASSERT_EQ(source, stream_source()->GetPlatformSource());
 
     if (result == mojom::MediaStreamRequestResult::OK) {
       ++number_of_successful_constraints_applied_;
@@ -253,8 +250,8 @@
     }
 
     if (!track_to_release_.IsNull()) {
-      mock_source_ = nullptr;
-      web_source_.Reset();
+      mock_stream_video_source_ = nullptr;
+      stream_source_ = nullptr;
       track_to_release_.Reset();
     }
   }
@@ -264,9 +261,9 @@
   int number_of_failed_constraints_applied_;
   mojom::MediaStreamRequestResult result_;
   WebString result_name_;
-  WebMediaStreamSource web_source_;
-  // |mock_source_| is owned by |web_source_|.
-  MockMediaStreamVideoSource* mock_source_;
+  Persistent<MediaStreamSource> stream_source_;
+  // |mock_stream_video_source_| is owned by |stream_source_|.
+  MockMediaStreamVideoSource* mock_stream_video_source_;
 };
 
 TEST_F(MediaStreamVideoSourceTest, AddTrackAndStartSource) {
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index fe0d21eb..f53f6726 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -220,21 +220,20 @@
          device.session_id() == other_device.session_id();
 }
 
-bool IsSameSource(const blink::WebMediaStreamSource& source,
-                  const blink::WebMediaStreamSource& other_source) {
-  blink::WebPlatformMediaStreamSource* const source_extra_data =
-      source.GetPlatformSource();
+bool IsSameSource(MediaStreamSource* source, MediaStreamSource* other_source) {
+  WebPlatformMediaStreamSource* const source_extra_data =
+      source->GetPlatformSource();
   const MediaStreamDevice& device = source_extra_data->device();
 
-  blink::WebPlatformMediaStreamSource* const other_source_extra_data =
-      other_source.GetPlatformSource();
+  WebPlatformMediaStreamSource* const other_source_extra_data =
+      other_source->GetPlatformSource();
   const MediaStreamDevice& other_device = other_source_extra_data->device();
 
   return IsSameDevice(device, other_device);
 }
 
-void SurfaceAudioProcessingSettings(blink::WebMediaStreamSource* source) {
-  blink::MediaStreamAudioSource* source_impl =
+void SurfaceAudioProcessingSettings(MediaStreamSource* source) {
+  auto* source_impl =
       static_cast<blink::MediaStreamAudioSource*>(source->GetPlatformSource());
 
   // If the source is a processed source, get the properties from it.
@@ -242,20 +241,20 @@
           blink::ProcessedLocalAudioSource::From(source_impl)) {
     blink::AudioProcessingProperties properties =
         processed_source->audio_processing_properties();
-    WebMediaStreamSource::EchoCancellationMode echo_cancellation_mode;
+    MediaStreamSource::EchoCancellationMode echo_cancellation_mode;
 
     switch (properties.echo_cancellation_type) {
       case EchoCancellationType::kEchoCancellationDisabled:
         echo_cancellation_mode =
-            WebMediaStreamSource::EchoCancellationMode::kDisabled;
+            MediaStreamSource::EchoCancellationMode::kDisabled;
         break;
       case EchoCancellationType::kEchoCancellationAec3:
         echo_cancellation_mode =
-            WebMediaStreamSource::EchoCancellationMode::kBrowser;
+            MediaStreamSource::EchoCancellationMode::kBrowser;
         break;
       case EchoCancellationType::kEchoCancellationSystem:
         echo_cancellation_mode =
-            WebMediaStreamSource::EchoCancellationMode::kSystem;
+            MediaStreamSource::EchoCancellationMode::kSystem;
         break;
     }
 
@@ -266,11 +265,11 @@
     // If the source is not a processed source, it could still support system
     // echo cancellation. Surface that if it does.
     media::AudioParameters params = source_impl->GetAudioParameters();
-    const WebMediaStreamSource::EchoCancellationMode echo_cancellation_mode =
+    const MediaStreamSource::EchoCancellationMode echo_cancellation_mode =
         params.IsValid() &&
                 (params.effects() & media::AudioParameters::ECHO_CANCELLER)
-            ? WebMediaStreamSource::EchoCancellationMode::kSystem
-            : WebMediaStreamSource::EchoCancellationMode::kDisabled;
+            ? MediaStreamSource::EchoCancellationMode::kSystem
+            : MediaStreamSource::EchoCancellationMode::kDisabled;
 
     source->SetAudioProcessingProperties(echo_cancellation_mode, false, false);
   }
@@ -319,8 +318,7 @@
   explicit RequestInfo(UserMediaRequest* request);
 
   void StartAudioTrack(MediaStreamComponent* component, bool is_pending);
-  MediaStreamComponent* CreateAndStartVideoTrack(
-      const WebMediaStreamSource& source);
+  MediaStreamComponent* CreateAndStartVideoTrack(MediaStreamSource* source);
 
   // Triggers |callback| when all sources used in this request have either
   // successfully started, or a source has failed to start.
@@ -418,6 +416,7 @@
   void Trace(Visitor* visitor) const {
     visitor->Trace(request_);
     visitor->Trace(descriptor_);
+    visitor->Trace(sources_);
   }
 
  private:
@@ -442,7 +441,7 @@
   MediaStreamRequestResult request_result_ = MediaStreamRequestResult::OK;
   String request_result_name_;
   // Sources used in this request.
-  Vector<blink::WebMediaStreamSource> sources_;
+  HeapVector<Member<MediaStreamSource>> sources_;
   Vector<blink::WebPlatformMediaStreamSource*> sources_waiting_for_callback_;
   HashMap<String, Vector<media::VideoCaptureFormat>> video_formats_map_;
   Vector<MediaStreamDevice> audio_devices_;
@@ -481,8 +480,8 @@
 }
 
 MediaStreamComponent* UserMediaProcessor::RequestInfo::CreateAndStartVideoTrack(
-    const WebMediaStreamSource& source) {
-  DCHECK(source.GetType() == WebMediaStreamSource::kTypeVideo);
+    MediaStreamSource* source) {
+  DCHECK(source->GetType() == MediaStreamSource::kTypeVideo);
   DCHECK(request()->Video());
   DCHECK(video_capture_settings_.HasValue());
   SendLogMessage(base::StringPrintf(
@@ -648,17 +647,15 @@
     // will contain the same non-reconfigurable settings that limit the
     // associated capabilities.
     blink::MediaStreamAudioSource* audio_source = nullptr;
-    auto* it =
-        std::find_if(local_sources_.begin(), local_sources_.end(),
-                     [&device](const blink::WebMediaStreamSource& web_source) {
-                       DCHECK(!web_source.IsNull());
-                       return WTF::String(web_source.Id()) == device->device_id;
-                     });
+    auto* it = std::find_if(local_sources_.begin(), local_sources_.end(),
+                            [&device](MediaStreamSource* source) {
+                              DCHECK(source);
+                              return source->Id() == device->device_id;
+                            });
     if (it != local_sources_.end()) {
-      blink::WebPlatformMediaStreamSource* const source =
-          it->GetPlatformSource();
+      WebPlatformMediaStreamSource* const source = (*it)->GetPlatformSource();
       if (source->device().type == MediaStreamType::DEVICE_AUDIO_CAPTURE)
-        audio_source = static_cast<blink::MediaStreamAudioSource*>(source);
+        audio_source = static_cast<MediaStreamAudioSource*>(source);
     }
     if (audio_source) {
       capabilities.emplace_back(audio_source);
@@ -720,25 +717,23 @@
   auto settings = current_request_info_->audio_capture_settings();
   auto device_id = settings.device_id();
 
-  // Create a copy of the blink::WebMediaStreamSource objects that are
+  // Create a copy of the MediaStreamSource objects that are
   // associated to the same audio device capture based on its device ID.
-  Vector<blink::WebMediaStreamSource> matching_sources;
+  HeapVector<Member<MediaStreamSource>> matching_sources;
   std::copy_if(local_sources_.begin(), local_sources_.end(),
                std::back_inserter(matching_sources),
-               [&device_id](const blink::WebMediaStreamSource& web_source) {
-                 DCHECK(!web_source.IsNull());
-                 return web_source.GetType() ==
-                            WebMediaStreamSource::kTypeAudio &&
-                        web_source.Id().Utf8() == device_id;
+               [&device_id](MediaStreamSource* source) {
+                 DCHECK(source);
+                 return source->GetType() == MediaStreamSource::kTypeAudio &&
+                        source->Id().Utf8() == device_id;
                });
 
   // Return the session ID associated to the source that has the same settings
   // that have been previously selected, if one exists.
   if (!matching_sources.IsEmpty()) {
     for (auto& matching_source : matching_sources) {
-      blink::MediaStreamAudioSource* audio_source =
-          static_cast<blink::MediaStreamAudioSource*>(
-              matching_source.GetPlatformSource());
+      auto* audio_source = static_cast<MediaStreamAudioSource*>(
+          matching_source->GetPlatformSource());
       if (audio_source->HasSameReconfigurableSettings(
               settings.audio_processing_properties())) {
         return audio_source->device().session_id();
@@ -1104,7 +1099,7 @@
   for (auto* it = pending_local_sources_.begin();
        it != pending_local_sources_.end(); ++it) {
     blink::WebPlatformMediaStreamSource* const source_extra_data =
-        it->GetPlatformSource();
+        (*it)->GetPlatformSource();
     if (source_extra_data != source)
       continue;
     if (result == MediaStreamRequestResult::OK)
@@ -1147,16 +1142,14 @@
       "OnDeviceStopped({session_id=%s}, {device_id=%s})",
       device.session_id().ToString().c_str(), device.id.c_str()));
 
-  const blink::WebMediaStreamSource* source_ptr = FindLocalSource(device);
-  if (!source_ptr) {
+  MediaStreamSource* source = FindLocalSource(device);
+  if (!source) {
     // This happens if the same device is used in several guM requests or
     // if a user happens to stop a track from JS at the same time
     // as the underlying media device is unplugged from the system.
     return;
   }
-  // By creating |source| it is guaranteed that the blink::WebMediaStreamSource
-  // object is valid during the cleanup.
-  blink::WebMediaStreamSource source(*source_ptr);
+
   StopLocalSource(source, false);
   RemoveLocalSource(source);
 }
@@ -1173,8 +1166,8 @@
            << ", session id = " << new_device.session_id()
            << ", type = " << new_device.type << "})";
 
-  const blink::WebMediaStreamSource* source_ptr = FindLocalSource(old_device);
-  if (!source_ptr) {
+  MediaStreamSource* source = FindLocalSource(old_device);
+  if (!source) {
     // This happens if the same device is used in several guM requests or
     // if a user happens to stop a track from JS at the same time
     // as the underlying media device is unplugged from the system.
@@ -1192,8 +1185,7 @@
     return;
   }
 
-  blink::WebPlatformMediaStreamSource* const source_impl =
-      source_ptr->GetPlatformSource();
+  WebPlatformMediaStreamSource* const source_impl = source->GetPlatformSource();
   source_impl->ChangeSource(new_device);
 }
 
@@ -1201,9 +1193,11 @@
   visitor->Trace(dispatcher_host_);
   visitor->Trace(frame_);
   visitor->Trace(current_request_info_);
+  visitor->Trace(local_sources_);
+  visitor->Trace(pending_local_sources_);
 }
 
-blink::WebMediaStreamSource UserMediaProcessor::InitializeVideoSourceObject(
+MediaStreamSource* UserMediaProcessor::InitializeVideoSourceObject(
     const MediaStreamDevice& device) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(current_request_info_);
@@ -1212,13 +1206,16 @@
       "name: %s]})",
       current_request_info_->request_id(), device.id.c_str(),
       device.name.c_str()));
-  blink::WebMediaStreamSource source = FindOrInitializeSourceObject(device);
-  if (!source.GetPlatformSource()) {
-    source.SetPlatformSource(CreateVideoSource(
+  MediaStreamSource* source = FindOrInitializeSourceObject(device);
+  if (!source->GetPlatformSource()) {
+    auto video_source = CreateVideoSource(
         device, WTF::Bind(&UserMediaProcessor::OnLocalSourceStopped,
-                          WrapWeakPersistent(this))));
+                          WrapWeakPersistent(this)));
+    video_source->SetOwner(source);
+    source->SetPlatformSource(std::move(video_source));
+
     String device_id(device.id.data());
-    source.SetCapabilities(ComputeCapabilitiesForVideoSource(
+    source->SetCapabilities(ComputeCapabilitiesForVideoSource(
         // TODO(crbug.com/704136): Change ComputeCapabilitiesForVideoSource to
         // operate over WTF::Vector and WTF::String.
         blink::WebString::FromUTF8(device.id),
@@ -1230,7 +1227,7 @@
   return source;
 }
 
-blink::WebMediaStreamSource UserMediaProcessor::InitializeAudioSourceObject(
+MediaStreamSource* UserMediaProcessor::InitializeAudioSourceObject(
     const MediaStreamDevice& device,
     bool* is_pending) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -1244,10 +1241,10 @@
   // See if the source is already being initialized.
   auto* pending = FindPendingLocalSource(device);
   if (pending)
-    return *pending;
+    return pending;
 
-  blink::WebMediaStreamSource source = FindOrInitializeSourceObject(device);
-  if (source.GetPlatformSource()) {
+  MediaStreamSource* source = FindOrInitializeSourceObject(device);
+  if (source->GetPlatformSource()) {
     // The only return point for non-pending sources.
     *is_pending = false;
     return source;
@@ -1269,14 +1266,13 @@
       &UserMediaProcessor::OnLocalSourceStopped, WrapWeakPersistent(this)));
 
 #if DCHECK_IS_ON()
-  for (const auto& local_source : local_sources_) {
-    blink::WebPlatformMediaStreamSource* platform_source =
-        static_cast<blink::WebPlatformMediaStreamSource*>(
-            local_source.GetPlatformSource());
+  for (auto local_source : local_sources_) {
+    auto* platform_source = static_cast<WebPlatformMediaStreamSource*>(
+        local_source->GetPlatformSource());
     DCHECK(platform_source);
     if (platform_source->device().id == audio_source->device().id) {
-      blink::MediaStreamAudioSource* audio_platform_source =
-          static_cast<blink::MediaStreamAudioSource*>(platform_source);
+      auto* audio_platform_source =
+          static_cast<MediaStreamAudioSource*>(platform_source);
       DCHECK(audio_source->HasSameNonReconfigurableSettings(
           audio_platform_source));
     }
@@ -1322,8 +1318,9 @@
   if (device.group_id)
     capabilities.group_id = blink::WebString::FromUTF8(*device.group_id);
 
-  source.SetPlatformSource(std::move(audio_source));  // Takes ownership.
-  source.SetCapabilities(capabilities);
+  audio_source->SetOwner(source);
+  source->SetPlatformSource(std::move(audio_source));
+  source->SetCapabilities(capabilities);
   return source;
 }
 
@@ -1420,8 +1417,7 @@
                                     current_request_info_->request_id()));
 
   for (WTF::wtf_size_t i = 0; i < devices.size(); ++i) {
-    blink::WebMediaStreamSource source =
-        InitializeVideoSourceObject(devices[i]);
+    MediaStreamSource* source = InitializeVideoSourceObject(devices[i]);
     (*components)[i] = current_request_info_->CreateAndStartVideoTrack(source);
   }
 }
@@ -1451,14 +1447,14 @@
 
   for (WTF::wtf_size_t i = 0; i < overridden_audio_devices.size(); ++i) {
     bool is_pending = false;
-    WebMediaStreamSource source =
+    MediaStreamSource* source =
         InitializeAudioSourceObject(overridden_audio_devices[i], &is_pending);
     (*components)[i] = MakeGarbageCollected<MediaStreamComponent>(source);
     current_request_info_->StartAudioTrack((*components)[i], is_pending);
     // At this point the source has started, and its audio parameters have been
     // set. Thus, all audio processing properties are known and can be surfaced
     // to |source|.
-    SurfaceAudioProcessingSettings(&source);
+    SurfaceAudioProcessingSettings(source);
   }
 }
 
@@ -1631,49 +1627,46 @@
   user_media_request->Fail(UserMediaRequest::Error::kPermissionDenied, "");
 }
 
-const blink::WebMediaStreamSource* UserMediaProcessor::FindLocalSource(
+MediaStreamSource* UserMediaProcessor::FindLocalSource(
     const LocalStreamSources& sources,
     const MediaStreamDevice& device) const {
-  for (const auto& local_source : sources) {
-    blink::WebPlatformMediaStreamSource* const source =
-        local_source.GetPlatformSource();
+  for (auto local_source : sources) {
+    WebPlatformMediaStreamSource* const source =
+        local_source->GetPlatformSource();
     const MediaStreamDevice& active_device = source->device();
     if (IsSameDevice(active_device, device))
-      return &local_source;
+      return local_source;
   }
   return nullptr;
 }
 
-blink::WebMediaStreamSource UserMediaProcessor::FindOrInitializeSourceObject(
+MediaStreamSource* UserMediaProcessor::FindOrInitializeSourceObject(
     const MediaStreamDevice& device) {
-  const blink::WebMediaStreamSource* existing_source = FindLocalSource(device);
+  MediaStreamSource* existing_source = FindLocalSource(device);
   if (existing_source) {
     DVLOG(1) << "Source already exists. Reusing source with id "
              << existing_source->Id().Utf8();
-    return *existing_source;
+    return existing_source;
   }
 
-  blink::WebMediaStreamSource::Type type =
-      blink::IsAudioInputMediaType(device.type)
-          ? blink::WebMediaStreamSource::kTypeAudio
-          : blink::WebMediaStreamSource::kTypeVideo;
+  MediaStreamSource::StreamType type = IsAudioInputMediaType(device.type)
+                                           ? MediaStreamSource::kTypeAudio
+                                           : MediaStreamSource::kTypeVideo;
 
-  blink::WebMediaStreamSource source;
-  source.Initialize(blink::WebString::FromUTF8(device.id), type,
-                    blink::WebString::FromUTF8(device.name),
-                    false /* remote */);
+  auto* source = MakeGarbageCollected<MediaStreamSource>(
+      String::FromUTF8(device.id), type, String::FromUTF8(device.name),
+      false /* remote */);
   if (device.group_id)
-    source.SetGroupId(blink::WebString::FromUTF8(*device.group_id));
+    source->SetGroupId(String::FromUTF8(*device.group_id));
   return source;
 }
 
-bool UserMediaProcessor::RemoveLocalSource(
-    const blink::WebMediaStreamSource& source) {
+bool UserMediaProcessor::RemoveLocalSource(MediaStreamSource* source) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   SendLogMessage(base::StringPrintf(
       "RemoveLocalSource({id=%s}, {name=%s}, {group_id=%s})",
-      source.Id().Utf8().c_str(), source.GetName().Utf8().c_str(),
-      source.GroupId().Utf8().c_str()));
+      source->Id().Utf8().c_str(), source->GetName().Utf8().c_str(),
+      source->GroupId().Utf8().c_str()));
 
   for (auto* device_it = local_sources_.begin();
        device_it != local_sources_.end(); ++device_it) {
@@ -1687,10 +1680,10 @@
   for (auto* device_it = pending_local_sources_.begin();
        device_it != pending_local_sources_.end(); ++device_it) {
     if (IsSameSource(*device_it, source)) {
-      blink::WebPlatformMediaStreamSource* const source_extra_data =
-          source.GetPlatformSource();
+      WebPlatformMediaStreamSource* const source_extra_data =
+          source->GetPlatformSource();
       const bool is_audio_source =
-          source.GetType() == blink::WebMediaStreamSource::kTypeAudio;
+          source->GetType() == MediaStreamSource::kTypeAudio;
       NotifyCurrentRequestInfoOfAudioSourceStarted(
           source_extra_data,
           is_audio_source ? MediaStreamRequestResult::TRACK_START_FAILURE_AUDIO
@@ -1782,10 +1775,9 @@
       device_id, source_impl->device().serializable_session_id());
 }
 
-void UserMediaProcessor::StopLocalSource(
-    const blink::WebMediaStreamSource& source,
-    bool notify_dispatcher) {
-  blink::WebPlatformMediaStreamSource* source_impl = source.GetPlatformSource();
+void UserMediaProcessor::StopLocalSource(MediaStreamSource* source,
+                                         bool notify_dispatcher) {
+  WebPlatformMediaStreamSource* source_impl = source->GetPlatformSource();
   SendLogMessage(base::StringPrintf(
       "StopLocalSource({session_id=%s})",
       source_impl->device().session_id().ToString().c_str()));
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.h b/third_party/blink/renderer/modules/mediastream/user_media_processor.h
index 41b4804..ca0d8709 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.h
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.h
@@ -131,7 +131,7 @@
   FRIEND_TEST_ALL_PREFIXES(UserMediaClientTest,
                            ZoomConstraintRequestPanTiltZoomPermission);
   class RequestInfo;
-  using LocalStreamSources = Vector<blink::WebMediaStreamSource>;
+  using LocalStreamSources = HeapVector<Member<MediaStreamSource>>;
 
   void OnStreamGenerated(int request_id,
                          blink::mojom::blink::MediaStreamRequestResult result,
@@ -169,10 +169,10 @@
 
   // Creates a WebKit representation of a stream source based on
   // |device| from the MediaStreamDispatcherHost.
-  blink::WebMediaStreamSource InitializeVideoSourceObject(
+  MediaStreamSource* InitializeVideoSourceObject(
       const blink::MediaStreamDevice& device);
 
-  blink::WebMediaStreamSource InitializeAudioSourceObject(
+  MediaStreamSource* InitializeAudioSourceObject(
       const blink::MediaStreamDevice& device,
       bool* is_pending);
 
@@ -217,29 +217,27 @@
 
   // Returns the source that use a device with |device.session_id|
   // and |device.device.id|. nullptr if such source doesn't exist.
-  const blink::WebMediaStreamSource* FindLocalSource(
-      const blink::MediaStreamDevice& device) const {
+  MediaStreamSource* FindLocalSource(const MediaStreamDevice& device) const {
     return FindLocalSource(local_sources_, device);
   }
-  const blink::WebMediaStreamSource* FindPendingLocalSource(
-      const blink::MediaStreamDevice& device) const {
+  MediaStreamSource* FindPendingLocalSource(
+      const MediaStreamDevice& device) const {
     return FindLocalSource(pending_local_sources_, device);
   }
-  const blink::WebMediaStreamSource* FindLocalSource(
+  MediaStreamSource* FindLocalSource(
       const LocalStreamSources& sources,
       const blink::MediaStreamDevice& device) const;
 
   // Looks up a local source and returns it if found. If not found, prepares
-  // a new WebMediaStreamSource with a nullptr extraData pointer.
-  blink::WebMediaStreamSource FindOrInitializeSourceObject(
-      const blink::MediaStreamDevice& device);
+  // a new MediaStreamSource with a nullptr extraData pointer.
+  MediaStreamSource* FindOrInitializeSourceObject(
+      const MediaStreamDevice& device);
 
   // Returns true if we do find and remove the |source|.
   // Otherwise returns false.
-  bool RemoveLocalSource(const blink::WebMediaStreamSource& source);
+  bool RemoveLocalSource(MediaStreamSource* source);
 
-  void StopLocalSource(const blink::WebMediaStreamSource& source,
-                       bool notify_dispatcher);
+  void StopLocalSource(MediaStreamSource* source, bool notify_dispatcher);
 
   blink::mojom::blink::MediaStreamDispatcherHost*
   GetMediaStreamDispatcherHost();
diff --git a/third_party/blink/renderer/modules/payments/payment_test_helper.cc b/third_party/blink/renderer/modules/payments/payment_test_helper.cc
index b79e0eb..09aaffa9 100644
--- a/third_party/blink/renderer/modules/payments/payment_test_helper.cc
+++ b/third_party/blink/renderer/modules/payments/payment_test_helper.cc
@@ -7,7 +7,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_currency_amount.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_details_modifier.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_payment_method_data.h"
-#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
@@ -215,7 +215,7 @@
 
 PaymentRequestV8TestingScope::PaymentRequestV8TestingScope()
     : V8TestingScope(KURL("https://www.example.com/")) {
-  GetDocument().SetSecureContextModeForTesting(
+  GetWindow().GetSecurityContext().SetSecureContextModeForTesting(
       SecureContextMode::kSecureContext);
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index f87dcc5..a0faa39 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -649,8 +649,7 @@
   }
 
   // Count number of PeerConnections that could potentially be impacted by CSP
-  auto& security_context = context->GetSecurityContext();
-  auto* content_security_policy = security_context.GetContentSecurityPolicy();
+  auto* content_security_policy = context->GetContentSecurityPolicy();
   if (content_security_policy &&
       content_security_policy->IsActiveForConnections()) {
     UseCounter::Count(context, WebFeature::kRTCPeerConnectionWithActiveCsp);
diff --git a/third_party/blink/renderer/modules/sensor/sensor_test_utils.cc b/third_party/blink/renderer/modules/sensor/sensor_test_utils.cc
index fc23d82..49e8cea 100644
--- a/third_party/blink/renderer/modules/sensor/sensor_test_utils.cc
+++ b/third_party/blink/renderer/modules/sensor/sensor_test_utils.cc
@@ -7,9 +7,9 @@
 #include "base/callback.h"
 #include "base/run_loop.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/modules/sensor/sensor_test_utils.h"
@@ -42,8 +42,9 @@
 SensorTestContext::SensorTestContext() {
   // Sensor's constructor has a check for this that could be removed in the
   // future.
-  testing_scope_.GetDocument().SetSecureContextModeForTesting(
-      SecureContextMode::kSecureContext);
+  testing_scope_.GetWindow()
+      .GetSecurityContext()
+      .SetSecureContextModeForTesting(SecureContextMode::kSecureContext);
   // Necessary for SensorProxy::ShouldSuspendUpdates() to work correctly.
   testing_scope_.GetPage().GetFocusController().SetFocused(true);
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
index 3fedb24..f0f91e3 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_container_test.cc
@@ -19,6 +19,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/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
 #include "third_party/blink/renderer/modules/service_worker/navigator_service_worker.h"
@@ -193,8 +194,10 @@
     NavigateTo(KURL(NullURL(), url));
 
     if (url.StartsWith("https://") || url.StartsWith("http://localhost/")) {
-      GetDocument().SetSecureContextModeForTesting(
-          SecureContextMode::kSecureContext);
+      GetFrame()
+          .DomWindow()
+          ->GetSecurityContext()
+          .SetSecureContextModeForTesting(SecureContextMode::kSecureContext);
     }
   }
 
diff --git a/third_party/blink/renderer/modules/virtualkeyboard/virtual_keyboard.cc b/third_party/blink/renderer/modules/virtualkeyboard/virtual_keyboard.cc
index 585fe1f..1d29353 100644
--- a/third_party/blink/renderer/modules/virtualkeyboard/virtual_keyboard.cc
+++ b/third_party/blink/renderer/modules/virtualkeyboard/virtual_keyboard.cc
@@ -19,14 +19,6 @@
 
 namespace blink {
 
-namespace {
-
-String FormatPx(int value) {
-  return String::Format("%dpx", value);
-}
-
-}  // namespace
-
 VirtualKeyboard::VirtualKeyboard(LocalFrame* frame)
     : ExecutionContextClient(frame ? frame->DomWindow()->GetExecutionContext()
                                    : nullptr),
@@ -76,13 +68,15 @@
     DocumentStyleEnvironmentVariables& vars =
         frame->GetDocument()->GetStyleEngine().EnsureEnvironmentVariables();
     vars.SetVariable(UADefinedVariable::kKeyboardInsetTop,
-                     FormatPx(keyboard_rect.y()));
+                     StyleEnvironmentVariables::FormatPx(keyboard_rect.y()));
     vars.SetVariable(UADefinedVariable::kKeyboardInsetLeft,
-                     FormatPx(keyboard_rect.x()));
-    vars.SetVariable(UADefinedVariable::kKeyboardInsetBottom,
-                     FormatPx(keyboard_rect.bottom()));
-    vars.SetVariable(UADefinedVariable::kKeyboardInsetRight,
-                     FormatPx(keyboard_rect.right()));
+                     StyleEnvironmentVariables::FormatPx(keyboard_rect.x()));
+    vars.SetVariable(
+        UADefinedVariable::kKeyboardInsetBottom,
+        StyleEnvironmentVariables::FormatPx(keyboard_rect.bottom()));
+    vars.SetVariable(
+        UADefinedVariable::kKeyboardInsetRight,
+        StyleEnvironmentVariables::FormatPx(keyboard_rect.right()));
   }
   DispatchEvent(*(MakeGarbageCollected<VirtualKeyboardGeometryChangeEvent>(
       event_type_names::kGeometrychange, bounding_rect_)));
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h
index 416dfdf1..47d11ff 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "media/base/limits.h"
-#include "third_party/blink/public/platform/modules/mediastream/web_media_stream_source.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_source.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_deliverer.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_processor_options.h"
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 935f490..9515adc7 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -427,6 +427,7 @@
     },
     {
       name: "CSSFoldables",
+      status: "experimental",
     },
     {
       name: "CSSFontSizeAdjust",
@@ -1535,10 +1536,6 @@
       status: "stable",
     },
     {
-      name: "RestrictAppCacheToSecureContexts",
-      status: "stable",
-    },
-    {
       name: "RestrictAutomaticLazyFrameLoadingToDataSaver",
       depends_on: ["AutomaticLazyFrameLoading"],
       status: "stable",
@@ -2078,7 +2075,7 @@
     },
     {
       name: "WindowSegments",
-      status: "test"
+      status: "experimental",
     },
     {
       name: "XSLT",
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index f08655fa..cfd805f7 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -381,7 +381,7 @@
   switch (type) {
     case TaskType::kInternalContentCapture:
       return ThrottleableTaskQueueTraits().SetPrioritisationType(
-            QueueTraits::PrioritisationType::kBestEffort);
+          QueueTraits::PrioritisationType::kBestEffort);
     case TaskType::kJavascriptTimer:
       return ThrottleableTaskQueueTraits().SetPrioritisationType(
           QueueTraits::PrioritisationType::kJavaScriptTimer);
@@ -436,9 +436,12 @@
       return PausableTaskQueueTraits();
     case TaskType::kInternalFindInPage:
       return FindInPageTaskQueueTraits();
+    case TaskType::kInternalHighPriorityLocalFrame:
+      return QueueTraits().SetPrioritisationType(
+          QueueTraits::PrioritisationType::kHighPriorityLocalFrame);
     case TaskType::kInternalContinueScriptLoading:
       return PausableTaskQueueTraits().SetPrioritisationType(
-            QueueTraits::PrioritisationType::kVeryHigh);
+          QueueTraits::PrioritisationType::kVeryHigh);
     case TaskType::kDatabaseAccess:
       if (base::FeatureList::IsEnabled(kHighPriorityDatabaseTaskType)) {
         return PausableTaskQueueTraits().SetPrioritisationType(
@@ -530,8 +533,8 @@
     return ResourceLoadingTaskRunnerHandleImpl::WrapTaskRunner(task_queue);
   }
 
-  return ResourceLoadingTaskRunnerHandleImpl::WrapTaskRunner(GetTaskQueue
-      (TaskType::kNetworkingWithURLLoaderAnnotation));
+  return ResourceLoadingTaskRunnerHandleImpl::WrapTaskRunner(
+      GetTaskQueue(TaskType::kNetworkingWithURLLoaderAnnotation));
 }
 
 void FrameSchedulerImpl::DidChangeResourceLoadingPriority(
@@ -1075,14 +1078,13 @@
 
   if (task_queue->GetPrioritisationType() ==
       MainThreadTaskQueue::QueueTraits::PrioritisationType::kLoadingControl) {
-    return main_thread_scheduler_
-                   ->should_prioritize_loading_with_compositing()
+    return main_thread_scheduler_->should_prioritize_loading_with_compositing()
                ? TaskQueue::QueuePriority::kVeryHighPriority
                : TaskQueue::QueuePriority::kHighPriority;
   }
 
   if (task_queue->GetPrioritisationType() ==
-      MainThreadTaskQueue::QueueTraits::PrioritisationType::kLoading &&
+          MainThreadTaskQueue::QueueTraits::PrioritisationType::kLoading &&
       main_thread_scheduler_->should_prioritize_loading_with_compositing()) {
     return main_thread_scheduler_->compositor_priority();
   }
@@ -1094,6 +1096,12 @@
 
   if (task_queue->GetPrioritisationType() ==
       MainThreadTaskQueue::QueueTraits::PrioritisationType::
+          kHighPriorityLocalFrame) {
+    return TaskQueue::QueuePriority::kHighestPriority;
+  }
+
+  if (task_queue->GetPrioritisationType() ==
+      MainThreadTaskQueue::QueueTraits::PrioritisationType::
           kExperimentalDatabase) {
     // TODO(shaseley): This decision should probably be based on Agent
     // visibility. Consider changing this before shipping anything.
@@ -1242,8 +1250,7 @@
 }
 
 // static
-MainThreadTaskQueue::QueueTraits
-FrameSchedulerImpl::PausableTaskQueueTraits() {
+MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::PausableTaskQueueTraits() {
   return QueueTraits()
       .SetCanBeFrozen(base::FeatureList::IsEnabled(
           blink::features::kStopNonTimersInBackground))
@@ -1284,14 +1291,12 @@
   UpdatePolicy();
 }
 
-MainThreadTaskQueue::QueueTraits
-FrameSchedulerImpl::LoadingTaskQueueTraits() {
+MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::LoadingTaskQueueTraits() {
   return QueueTraits()
       .SetCanBePaused(true)
       .SetCanBeFrozen(true)
       .SetCanBeDeferred(true)
-      .SetPrioritisationType(
-          QueueTraits::PrioritisationType::kLoading);
+      .SetPrioritisationType(QueueTraits::PrioritisationType::kLoading);
 }
 
 MainThreadTaskQueue::QueueTraits
@@ -1300,8 +1305,7 @@
       .SetCanBePaused(true)
       .SetCanBeFrozen(true)
       .SetCanBeDeferred(true)
-      .SetPrioritisationType(
-          QueueTraits::PrioritisationType::kLoadingControl);
+      .SetPrioritisationType(QueueTraits::PrioritisationType::kLoadingControl);
 }
 
 MainThreadTaskQueue::QueueTraits
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
index 708a6b5..91aff3c 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -126,10 +126,11 @@
     TaskType::kInternalFrameLifecycleControl,
     TaskType::kInternalTranslation,
     TaskType::kInternalInspector,
-    TaskType::kInternalNavigationAssociatedUnfreezable};
+    TaskType::kInternalNavigationAssociatedUnfreezable,
+    TaskType::kInternalHighPriorityLocalFrame};
 
 static_assert(
-    static_cast<int>(TaskType::kCount) == 71,
+    static_cast<int>(TaskType::kCount) == 72,
     "When adding a TaskType, make sure that kAllFrameTaskTypes is updated.");
 
 void AppendToVectorTestTask(Vector<String>* vector, String value) {
@@ -301,13 +302,12 @@
 
   scoped_refptr<MainThreadTaskQueue> GetTaskQueue(
       MainThreadTaskQueue::QueueTraits queue_traits) {
-    return frame_scheduler_->FrameTaskQueueControllerForTest()
-        ->GetTaskQueue(queue_traits);
+    return frame_scheduler_->FrameTaskQueueControllerForTest()->GetTaskQueue(
+        queue_traits);
   }
 
   scoped_refptr<TaskQueue> ThrottleableTaskQueue() {
-    return GetTaskQueue(
-        FrameSchedulerImpl::ThrottleableTaskQueueTraits());
+    return GetTaskQueue(FrameSchedulerImpl::ThrottleableTaskQueueTraits());
   }
 
   scoped_refptr<TaskQueue> JavaScriptTimerTaskQueue() {
@@ -317,13 +317,11 @@
   }
 
   scoped_refptr<TaskQueue> LoadingTaskQueue() {
-    return GetTaskQueue(
-        FrameSchedulerImpl::LoadingTaskQueueTraits());
+    return GetTaskQueue(FrameSchedulerImpl::LoadingTaskQueueTraits());
   }
 
   scoped_refptr<TaskQueue> LoadingControlTaskQueue() {
-    return GetTaskQueue(
-        FrameSchedulerImpl::LoadingControlTaskQueueTraits());
+    return GetTaskQueue(FrameSchedulerImpl::LoadingControlTaskQueueTraits());
   }
 
   scoped_refptr<TaskQueue> DeferrableTaskQueue() {
@@ -339,8 +337,7 @@
   }
 
   scoped_refptr<TaskQueue> ForegroundOnlyTaskQueue() {
-    return GetTaskQueue(
-        FrameSchedulerImpl::ForegroundOnlyTaskQueueTraits());
+    return GetTaskQueue(FrameSchedulerImpl::ForegroundOnlyTaskQueueTraits());
   }
 
   scoped_refptr<MainThreadTaskQueue> GetTaskQueue(TaskType type) {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc
index 62467a7..66e16e55 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc
@@ -323,14 +323,16 @@
 INSTANTIATE_TEST_SUITE_P(
     All,
     TaskQueueCreationFromQueueTraitsTest,
-    ::testing::Values(QueueTraits::PrioritisationType::kVeryHigh,
-                      QueueTraits::PrioritisationType::kBestEffort,
-                      QueueTraits::PrioritisationType::kRegular,
-                      QueueTraits::PrioritisationType::kLoading,
-                      QueueTraits::PrioritisationType::kLoadingControl,
-                      QueueTraits::PrioritisationType::kFindInPage,
-                      QueueTraits::PrioritisationType::kExperimentalDatabase,
-                      QueueTraits::PrioritisationType::kJavaScriptTimer));
+    ::testing::Values(
+        QueueTraits::PrioritisationType::kVeryHigh,
+        QueueTraits::PrioritisationType::kBestEffort,
+        QueueTraits::PrioritisationType::kRegular,
+        QueueTraits::PrioritisationType::kLoading,
+        QueueTraits::PrioritisationType::kLoadingControl,
+        QueueTraits::PrioritisationType::kFindInPage,
+        QueueTraits::PrioritisationType::kExperimentalDatabase,
+        QueueTraits::PrioritisationType::kJavaScriptTimer,
+        QueueTraits::PrioritisationType::kHighPriorityLocalFrame));
 
 TEST_P(TaskQueueCreationFromQueueTraitsTest,
         AddAndRetrieveAllTaskQueues) {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index 302815a..faf1443 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -459,6 +459,8 @@
     timer_task_runner_ = timer_task_queue()->task_runner();
     find_in_page_task_runner_ = main_frame_scheduler_->GetTaskRunner(
         blink::TaskType::kInternalFindInPage);
+    prioritised_local_frame_task_runner_ = main_frame_scheduler_->GetTaskRunner(
+        blink::TaskType::kInternalHighPriorityLocalFrame);
   }
 
   TaskQueue* loading_task_queue() {
@@ -786,6 +788,8 @@
   // - 'I': Idle task
   // - 'T': Timer task
   // - 'V': kV8 task
+  // - 'F': FindInPage task
+  // - 'U': Prioritised local frame task
   void PostTestTasks(Vector<String>* run_order, const String& task_descriptor) {
     std::istringstream stream(task_descriptor.Utf8());
     while (!stream.eof()) {
@@ -837,6 +841,11 @@
               FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order,
                                         String::FromUTF8(task)));
           break;
+        case 'U':
+          prioritised_local_frame_task_runner_->PostTask(
+              FROM_HERE, base::BindOnce(&AppendToVectorTestTask, run_order,
+                                        String::FromUTF8(task)));
+          break;
         default:
           NOTREACHED();
       }
@@ -937,6 +946,8 @@
   scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> v8_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> find_in_page_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner>
+      prioritised_local_frame_task_runner_;
   bool simulate_timer_task_ran_;
   bool initially_ensure_usecase_none_ = true;
   uint64_t next_begin_frame_number_ = viz::BeginFrameArgs::kStartingFrameNumber;
@@ -1099,15 +1110,15 @@
   EnsureUseCaseNone();
 
   Vector<String> run_order;
-  PostTestTasks(&run_order, "L1 I1 D1 P1 C1 D2 P2 C2");
+  PostTestTasks(&run_order, "L1 I1 D1 P1 C1 D2 P2 C2 U1");
 
   EnableIdleTasks();
   base::RunLoop().RunUntilIdle();
   // High-priority input is enabled and input tasks are processed first.
   // One compositing event is prioritized after an input event but still
   // has lower priority than input event.
-  EXPECT_THAT(run_order, testing::ElementsAre("P1", "P2", "L1", "D1", "C1",
-                                              "D2", "C2", "I1"));
+  EXPECT_THAT(run_order, testing::ElementsAre("P1", "P2", "U1", "L1", "D1",
+                                              "C1", "D2", "C2", "I1"));
   EXPECT_EQ(UseCase::kNone, CurrentUseCase());
 }
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
index faf7bea..bce7544 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -131,8 +131,9 @@
       kFindInPage = 5,
       kExperimentalDatabase = 6,
       kJavaScriptTimer = 7,
+      kHighPriorityLocalFrame = 8,
 
-      kCount = 8
+      kCount = 9
     };
 
     // kPrioritisationTypeWidthBits is the number of bits required
@@ -141,10 +142,10 @@
     // We need to update it whenever there is a change in
     // PrioritisationType::kCount.
     // TODO(sreejakshetty) make the number of bits calculation automated.
-    static constexpr int kPrioritisationTypeWidthBits = 3;
+    static constexpr int kPrioritisationTypeWidthBits = 4;
     static_assert(static_cast<int>(PrioritisationType::kCount) <=
-                    (1 << kPrioritisationTypeWidthBits),
-                    "Wrong Instanstiation for kPrioritisationTypeWidthBits");
+                      (1 << kPrioritisationTypeWidthBits),
+                  "Wrong Instanstiation for kPrioritisationTypeWidthBits");
 
     QueueTraits(const QueueTraits&) = default;
 
@@ -189,7 +190,8 @@
              can_be_paused == other.can_be_paused &&
              can_be_frozen == other.can_be_frozen &&
              can_run_in_background == other.can_run_in_background &&
-             can_run_when_virtual_time_paused == other.can_run_when_virtual_time_paused &&
+             can_run_when_virtual_time_paused ==
+                 other.can_run_when_virtual_time_paused &&
              prioritisation_type == other.prioritisation_type;
     }
 
@@ -357,7 +359,8 @@
   QueueTraits GetQueueTraits() const { return queue_traits_; }
 
   QueueTraits::PrioritisationType GetPrioritisationType() const {
-      return queue_traits_.prioritisation_type;}
+    return queue_traits_.prioritisation_type;
+  }
 
   void OnTaskReady(const void* frame_scheduler,
                    const base::sequence_manager::Task& task,
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc b/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
index 8cba2d6..07d10cf1 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.cc
@@ -139,6 +139,8 @@
       return "InternalFrameLifecycleControl";
     case TaskType::kInternalFindInPage:
       return "InternalFindInPage";
+    case TaskType::kInternalHighPriorityLocalFrame:
+      return "InternalHighPriorityLocalFrame";
     case TaskType::kCount:
       return "Count";
   }
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
index d6348549..5d2f6746 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
@@ -209,6 +209,7 @@
     case TaskType::kExperimentalWebScheduling:
     case TaskType::kInternalFrameLifecycleControl:
     case TaskType::kInternalFindInPage:
+    case TaskType::kInternalHighPriorityLocalFrame:
     case TaskType::kCount:
       NOTREACHED();
       break;
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
index 43f047ee..41430c3 100644
--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
+++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
@@ -407,8 +407,6 @@
     settings.enable_early_damage_check =
         cmd.HasSwitch(cc::switches::kCheckDamageEarly);
   }
-  // Android WebView handles root layer flings itself.
-  settings.ignore_root_layer_flings = using_synchronous_compositor;
   // Memory policy on Android WebView does not depend on whether device is
   // low end, so always use default policy.
   if (using_low_memory_policy && !using_synchronous_compositor) {
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
index e366ca1e..e888d65 100644
--- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
+++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy.cc
@@ -45,6 +45,8 @@
 using perfetto::protos::pbzero::ChromeLatencyInfo;
 using perfetto::protos::pbzero::TrackEvent;
 
+using ScrollThread = cc::InputHandler::ScrollThread;
+
 namespace blink {
 namespace {
 
@@ -177,6 +179,9 @@
     UMA_HISTOGRAM_ENUMERATION(kTouchHistogramName, status);
   } else if (device == WebGestureDevice::kTouchpad) {
     UMA_HISTOGRAM_ENUMERATION(kWheelHistogramName, status);
+  } else if (device == WebGestureDevice::kScrollbar) {
+    // TODO(crbug.com/1101502): Add support for
+    // Renderer4.ScrollingThread.Scrollbar
   } else {
     NOTREACHED();
   }
@@ -831,6 +836,7 @@
       "Renderer4.MainThreadWheelScrollReason";
 
   if (device != WebGestureDevice::kTouchpad &&
+      device != WebGestureDevice::kScrollbar &&
       device != WebGestureDevice::kTouchscreen) {
     return;
   }
@@ -1020,7 +1026,7 @@
   scroll_sequence_ignored_ = false;
   in_inertial_scrolling_ = false;
   switch (scroll_status.thread) {
-    case cc::InputHandler::SCROLL_ON_IMPL_THREAD:
+    case ScrollThread::SCROLL_ON_IMPL_THREAD:
       TRACE_EVENT_INSTANT0("input", "Handle On Impl", TRACE_EVENT_SCOPE_THREAD);
       handling_gesture_on_impl_thread_ = true;
       if (input_handler_->IsCurrentlyScrollingViewport())
@@ -1031,12 +1037,12 @@
       else
         result = DID_HANDLE;
       break;
-    case cc::InputHandler::SCROLL_UNKNOWN:
-    case cc::InputHandler::SCROLL_ON_MAIN_THREAD:
+    case ScrollThread::SCROLL_UNKNOWN:
+    case ScrollThread::SCROLL_ON_MAIN_THREAD:
       TRACE_EVENT_INSTANT0("input", "Handle On Main", TRACE_EVENT_SCOPE_THREAD);
       result = DID_NOT_HANDLE;
       break;
-    case cc::InputHandler::SCROLL_IGNORED:
+    case ScrollThread::SCROLL_IGNORED:
       TRACE_EVENT_INSTANT0("input", "Ignore Scroll", TRACE_EVENT_SCOPE_THREAD);
       scroll_sequence_ignored_ = true;
       result = DROP_EVENT;
diff --git a/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc b/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
index b1a59a50..bafe141 100644
--- a/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
+++ b/third_party/blink/renderer/platform/widget/input/input_handler_proxy_unittest.cc
@@ -135,7 +135,7 @@
   cc::InputHandlerPointerResult MouseDown(const gfx::PointF& mouse_position,
                                           const bool shift_modifier) override {
     cc::InputHandlerPointerResult pointer_result;
-    pointer_result.type = cc::kScrollbarScroll;
+    pointer_result.type = cc::PointerResultType::kScrollbarScroll;
     pointer_result.scroll_offset = gfx::ScrollOffset(0, 1);
     return pointer_result;
   }
@@ -143,7 +143,7 @@
   cc::InputHandlerPointerResult MouseUp(
       const gfx::PointF& mouse_position) override {
     cc::InputHandlerPointerResult pointer_result;
-    pointer_result.type = cc::kScrollbarScroll;
+    pointer_result.type = cc::PointerResultType::kScrollbarScroll;
     return pointer_result;
   }
 
@@ -260,20 +260,20 @@
 }
 
 const cc::InputHandler::ScrollStatus kImplThreadScrollState(
-    cc::InputHandler::SCROLL_ON_IMPL_THREAD,
+    cc::InputHandler::ScrollThread::SCROLL_ON_IMPL_THREAD,
     cc::MainThreadScrollingReason::kNotScrollingOnMain);
 
 const cc::InputHandler::ScrollStatus kRequiresMainThreadHitTestState(
-    cc::InputHandler::SCROLL_ON_IMPL_THREAD,
+    cc::InputHandler::ScrollThread::SCROLL_ON_IMPL_THREAD,
     cc::MainThreadScrollingReason::kNotScrollingOnMain,
     /*needs_main_thread_hit_test=*/true);
 
 const cc::InputHandler::ScrollStatus kMainThreadScrollState(
-    cc::InputHandler::SCROLL_ON_MAIN_THREAD,
+    cc::InputHandler::ScrollThread::SCROLL_ON_MAIN_THREAD,
     cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
 
 const cc::InputHandler::ScrollStatus kScrollIgnoredScrollState(
-    cc::InputHandler::SCROLL_IGNORED,
+    cc::InputHandler::ScrollThread::SCROLL_IGNORED,
     cc::MainThreadScrollingReason::kNotScrollable);
 
 }  // namespace
@@ -594,12 +594,11 @@
   EXPECT_CALL(mock_input_handler_, ScrollEnd(true)).Times(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
       .WillOnce(testing::Return(kImplThreadScrollState));
-  // TODO(crbug.com/1060708): This should be called once.
   EXPECT_CALL(
       mock_input_handler_,
       RecordScrollBegin(ui::ScrollInputType::kScrollbar,
                         cc::ScrollBeginThreadState::kScrollingOnCompositor))
-      .Times(0);
+      .Times(1);
   EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(1);
   if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
     EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
@@ -761,7 +760,7 @@
       mock_input_handler_,
       RecordScrollBegin(ui::ScrollInputType::kScrollbar,
                         cc::ScrollBeginThreadState::kScrollingOnCompositor))
-      .Times(0);
+      .Times(1);
   EXPECT_CALL(mock_input_handler_, ScrollUpdate(_, _)).Times(1);
   if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
     EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
@@ -1449,6 +1448,7 @@
 
   EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
       .WillOnce(Return(kImplThreadScrollState));
+  EXPECT_CALL(mock_input_handler_, RecordScrollBegin(_, _)).Times(1);
   if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
     EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
         .WillOnce(Return(false));
@@ -1488,6 +1488,7 @@
   EXPECT_CALL(mock_input_handler_, RecordScrollEnd(_)).Times(1);
   EXPECT_CALL(mock_input_handler_, ScrollBegin(_, _))
       .WillOnce(Return(kImplThreadScrollState));
+  EXPECT_CALL(mock_input_handler_, RecordScrollBegin(_, _)).Times(1);
   if (!base::FeatureList::IsEnabled(features::kScrollUnification)) {
     EXPECT_CALL(mock_input_handler_, ScrollingShouldSwitchtoMainThread())
         .WillOnce(Return(false));
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 1ebc09d..5ca270b 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1203,7 +1203,7 @@
 crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/css/css-contain/contain-size-multicol-001.html [ Failure ]
 crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-multicol-002.html [ Crash Failure ]
 crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/contain/contain-size-multicol-003.html [ Failure ]
-crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html [ Failure ]
+crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html [ Pass ]
 crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-grid.html [ Crash Pass ]
 crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-multicol.html [ Failure ]
 crbug.com/875235 virtual/layout_ng_fieldset/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-percentage-block-size.html [ Failure ]
@@ -3239,6 +3239,7 @@
 crbug.com/367760 external/wpt/svg/pservers/reftests/meshgradient-basic-005.svg [ Failure ]
 crbug.com/367760 external/wpt/svg/pservers/reftests/meshgradient-basic-002.svg [ Failure ]
 crbug.com/367760 external/wpt/svg/pservers/reftests/meshgradient-basic-003.svg [ Failure ]
+crbug.com/875235 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-margins.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-rendering.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-tall.html [ Failure ]
@@ -3387,7 +3388,6 @@
 crbug.com/432153 external/wpt/css/css-masking/test-mask.html [ Failure ]
 crbug.com/843084 external/wpt/css/css-masking/clip-path/clip-path-polygon-006.html [ Failure ]
 crbug.com/843084 external/wpt/css/css-masking/clip-path-svg-content/clip-path-shape-circle-004.svg [ Failure ]
-crbug.com/843084 external/wpt/css/css-masking/clip-path-svg-content/clip-path-recursion-002.svg [ Failure ]
 crbug.com/843084 external/wpt/css/css-masking/clip-path/clip-path-polygon-008.html [ Failure ]
 crbug.com/843084 external/wpt/css/css-masking/clip-path-svg-content/mask-objectboundingbox-content-clip-transform.svg [ Failure ]
 crbug.com/843084 external/wpt/css/css-masking/clip-path/clip-path-ellipse-008.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 5804ebe..3538fb31 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -4135,7 +4135,7 @@
       ]
      ],
      "cursor-auto-007.html": [
-      "6cf1495a02c42c49b1407fef0a22eb363cdf7d2b",
+      "0d355ad0d953dce9be2f42340d331f442af8fac2",
       [
        null,
        {}
@@ -195341,6 +195341,16 @@
      ]
     }
    },
+   "deprecation-reporting": {
+    "idlharness.any-expected.txt": [
+     "3dbd47f9045602410f957505b875fe2d5f215ee2",
+     []
+    ],
+    "idlharness.any.worker-expected.txt": [
+     "3dbd47f9045602410f957505b875fe2d5f215ee2",
+     []
+    ]
+   },
    "device-memory": {
     "META.yml": [
      "b8dd4761adff3e18b6552d4a8f02abdcd30a3ea6",
@@ -215255,7 +215265,7 @@
      []
     ],
     "appmanifest.idl": [
-     "cf30b6127682f7f7f6a380cd1abafc1b2ad2c770",
+     "926a4fc2022e71c28aa4a2ae3d1adc12104ee1ab",
      []
     ],
     "audio-output.idl": [
@@ -215398,6 +215408,10 @@
      "b7d9c33d596c3882e14ffa2fa1dee99e087ecedf",
      []
     ],
+    "deprecation-reporting.idl": [
+     "e62711936b5ec9e6ee93e85c3e52e07462406957",
+     []
+    ],
     "device-memory.idl": [
      "f664013ddefea7bc8950f7604c06f53c1c1aac48",
      []
@@ -216588,6 +216602,10 @@
        "1bffae30b78bbb160e98de85f5629e594612bd50",
        []
       ],
+      "default-properties-on-the-math-root-expected.txt": [
+       "d0fae2e56ed9d66417a278ddd2814c72e6ea13e4",
+       []
+      ],
       "display-1-ref.html": [
        "ce65aba18c9483274765cde6f62bdf5fdeea001e",
        []
@@ -264879,6 +264897,13 @@
         {}
        ]
       ],
+      "needs-layout-transform.html": [
+       "8a307b3b68d216521f87698417360a5657b92d79",
+       [
+        null,
+        {}
+       ]
+      ],
       "vertical-align-top-bottom-001.html": [
        "2e03bc0d2fbed51589545b0b62d0ccb3d161556d",
        [
@@ -286583,6 +286608,13 @@
        {}
       ]
      ],
+     "rem-unit-root-element.html": [
+      "cfd7af17c4f0463e3df02b8d91a1f96c70511408",
+      [
+       null,
+       {}
+      ]
+     ],
      "rgba-011.html": [
       "84c317033063b72716e36cfd15466780e010ba11",
       [
@@ -291237,6 +291269,41 @@
      ]
     ]
    },
+   "deprecation-reporting": {
+    "idlharness.any.js": [
+     "720bacfa3ff3f00e2b8dcc4e061924d2dc48e876",
+     [
+      "deprecation-reporting/idlharness.any.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/resources/WebIDLParser.js"
+        ],
+        [
+         "script",
+         "/resources/idlharness.js"
+        ]
+       ]
+      }
+     ],
+     [
+      "deprecation-reporting/idlharness.any.worker.html",
+      {
+       "script_metadata": [
+        [
+         "script",
+         "/resources/WebIDLParser.js"
+        ],
+        [
+         "script",
+         "/resources/idlharness.js"
+        ]
+       ]
+      }
+     ]
+    ]
+   },
    "device-memory": {
     "device-memory.https.any.js": [
      "4fe6f04ebc959e6468af5296ebc677c70a7cf170",
@@ -312109,7 +312176,7 @@
        }
       ]
      ],
-     "split-cache.tentative.html": [
+     "split-cache.html": [
       "4b04c9ff79bf951cce993c6dbcc556dc1e505c41",
       [
        null,
@@ -353626,6 +353693,13 @@
         {}
        ]
       ],
+      "default-properties-on-the-math-root.html": [
+       "80a09774a7777fa104c861086e0f5ac971f07f05",
+       [
+        null,
+        {}
+       ]
+      ],
       "display-contents.html": [
        "aeaa28da908816ad39619d9a47bbb43a3116bbe9",
        [
@@ -391370,7 +391444,7 @@
      ]
     ],
     "request-video-frame-callback-webrtc.https.html": [
-     "b6131d6a808759346aa54b9e400e535b6c3ca29c",
+     "ce5b5ad6be699a917b3dce5559cdbfa8e334127d",
      [
       null,
       {}
@@ -396192,6 +396266,13 @@
         {}
        ]
       ],
+      "audiobuffersource-duration-loop.html": [
+       "faa70e11c4774991061e1d85a4a4b774e7368f5a",
+       [
+        null,
+        {}
+       ]
+      ],
       "audiobuffersource-ended.html": [
        "b9922f61ef399bf558a2f6d3c61154b9f14a512f",
        [
@@ -399098,10 +399179,12 @@
      ]
     ],
     "RTCPeerConnection-createDataChannel.html": [
-     "3d2169dffac65ffbc81355b33c4c904bf5e3f067",
+     "87867664b58a6787bd96cfb85559b4f1171e263f",
      [
       null,
-      {}
+      {
+       "timeout": "long"
+      }
      ]
     ],
     "RTCPeerConnection-createOffer.html": [
@@ -399149,7 +399232,7 @@
      ]
     ],
     "RTCPeerConnection-iceConnectionState.https.html": [
-     "851ce884d6ea12bf60761ef23f78cf197d594372",
+     "d3126065b99778f32b5e313211085d55c064fe1e",
      [
       null,
       {
@@ -399353,10 +399436,12 @@
      ]
     ],
     "RTCPeerConnection-setRemoteDescription-tracks.https.html": [
-     "59761c4c4bdca57141272b092fe56a917b612c7b",
+     "d2ee646e2c17c7d0aa1d632882838a07a6d5a685",
      [
       null,
-      {}
+      {
+       "timeout": "long"
+      }
      ]
     ],
     "RTCPeerConnection-setRemoteDescription.html": [
@@ -399598,14 +399683,14 @@
      ]
     ],
     "datachannel-emptystring.html": [
-     "6af436a1d1bd4fb0c3bb8065f48475582c87e33a",
+     "456bac7367e6f9034f83bbee6998313b789b8c0d",
      [
       null,
       {}
      ]
     ],
     "getstats.html": [
-     "979e99c0b27cc39af3f3a050df16a70b8f1221e8",
+     "0950a374c3cd8a44cbb8bffc2991fc6dc95417c8",
      [
       null,
       {}
@@ -399678,14 +399763,14 @@
      ]
     },
     "no-media-call.html": [
-     "dbe6a0dd4c210b2fe930e574fe5d638968805dca",
+     "b1eba08d0b433c60c6332199cd35294847028a0c",
      [
       null,
       {}
      ]
     ],
     "promises-call.html": [
-     "ceb6ab258ccbaaebb39b63742a48a379db35bc46",
+     "8b9a27554973531e8528406a52d38b7c55932f3c",
      [
       null,
       {}
@@ -399805,14 +399890,14 @@
      ]
     ],
     "simplecall-no-ssrcs.https.html": [
-     "87f8d939a5a2f80fa9fae137cf34d6e99ecf391a",
+     "5160451f012e642dd5697e034a19a7f8895421ea",
      [
       null,
       {}
      ]
     ],
     "simplecall.https.html": [
-     "291437a526582d13db6e04fa39c152ce9ed5859a",
+     "ffe043b6a237fae1a4f70e2cfac495a2a6132c28",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/common/get-host-info.sub.js b/third_party/blink/web_tests/external/wpt/common/get-host-info.sub.js
index 1c28a7f4..8f37d55 100644
--- a/third_party/blink/web_tests/external/wpt/common/get-host-info.sub.js
+++ b/third_party/blink/web_tests/external/wpt/common/get-host-info.sub.js
@@ -7,6 +7,7 @@
   var HTTP_PORT = '{{ports[http][0]}}';
   var HTTP_PORT2 = '{{ports[http][1]}}';
   var HTTPS_PORT = '{{ports[https][0]}}';
+  var HTTPS_PORT2 = '{{ports[https][1]}}';
   var PROTOCOL = self.location.protocol;
   var IS_HTTPS = (PROTOCOL == "https:");
   var HTTP_PORT_ELIDED = HTTP_PORT == "80" ? "" : (":" + HTTP_PORT);
@@ -22,6 +23,7 @@
     HTTP_PORT: HTTP_PORT,
     HTTP_PORT2: HTTP_PORT2,
     HTTPS_PORT: HTTPS_PORT,
+    HTTPS_PORT2: HTTPS_PORT2,
     ORIGINAL_HOST: ORIGINAL_HOST,
     REMOTE_HOST: REMOTE_HOST,
 
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/detach-abspos-before-layout.html b/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/detach-abspos-before-layout.html
new file mode 100644
index 0000000..27ee59c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/positioning/detach-abspos-before-layout.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>Detaching positioned object before it is laid out should not crash</title>
+<link rel="author" href="mailto:kojii@chromium.org">
+<link rel="help" href="https://crbug.com/1101986">
+<meta name="assert" content="Detaching positioned object before it is laid out should not crash">
+<style>
+.float {
+  float: left;
+}
+.abs {
+  position: absolute;
+}
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+  <div id="container">text<span id="target" class="float"></span></div>
+</body>
+<script>
+test(() => {
+  document.body.offsetTop;
+  let target = document.getElementById('target');
+
+  // Change `#target` from floating object to positioned object.
+  target.classList.add('abs');
+
+  // Style recalc without layout, and detach.
+  getComputedStyle(target).display;
+  container.style.display = "none";
+}, 'No crash or DCHECK failure');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/display-first-line-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-display/display-first-line-002-ref.html
new file mode 100644
index 0000000..e82f615
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/display-first-line-002-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<div contenteditable></div>
+<p>The word "PASS" should be seen below. There should be no DCHECK
+  failure.</p>
+<p style="color: blue;">PASS</p>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/display-first-line-002.html b/third_party/blink/web_tests/external/wpt/css/css-display/display-first-line-002.html
new file mode 100644
index 0000000..fef1d0b0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/display-first-line-002.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Display flex first line with floated first letter</title>
+<link rel="help" href="https://crbug.com/1097595">
+<link rel="match" href="display-first-line-002-ref.html">
+<style id="styleElm">
+  #victim::first-line { display:flex;  }
+  #victim::first-letter { float:right; }
+</style>
+
+<!-- The contenteditable DIV is just here to trigger legacy layout
+     fallback, and a DCHECK failure identical to the one in the bug
+     report. If we remove it, we'll get NG layout, and then it will
+     actually DCHECK-fail inside NG inline layout code instead. -->
+<div contenteditable></div>
+
+<p>The word "PASS" should be seen below. There should be no DCHECK
+  failure.</p>
+<div id="child" style="display:none;"></div>
+<div id="victim" style="width:fit-content;">
+  SPAS
+</div>
+<script>
+  document.body.offsetTop;
+  styleElm.appendChild(child);
+  document.body.offsetTop;
+  victim.style.color = "blue";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/display-with-float-dynamic.html b/third_party/blink/web_tests/external/wpt/css/css-display/display-with-float-dynamic.html
new file mode 100644
index 0000000..7cc2fef
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/display-with-float-dynamic.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Computed float value of flex/grid items</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#flex-containers">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-containers">
+<meta name="assert" content="computed float value of flex/grid items should be as specified">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="flex" style="display:flex;">
+  <div id="flex-item"></div>
+</div>
+<div id="grid" style="display:grid;">
+  <div id="grid-item">
+</div>
+<script>
+  function setFloatFor(id, float) {
+    document.getElementById(id).style.cssFloat = float;
+  }
+  function getFloatFor(id) {
+    return window.getComputedStyle(document.getElementById(id)).getPropertyValue("float");
+  }
+  function setDisplayBlock(id) {
+    document.getElementById(id).style.display = "block";
+  }
+  test(function() {
+    assert_equals(getFloatFor("flex-item"), "none");
+    assert_equals(getFloatFor("grid-item"), "none");
+
+    setFloatFor("flex-item", "left");
+    setFloatFor("grid-item", "right");
+    assert_equals(getFloatFor("flex-item"), "left");
+    assert_equals(getFloatFor("grid-item"), "right");
+
+    setDisplayBlock("grid");
+    setDisplayBlock("flex");
+    assert_equals(getFloatFor("flex-item"), "left");
+    assert_equals(getFloatFor("grid-item"), "right");
+  }, "computed style for float");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/display-with-float.html b/third_party/blink/web_tests/external/wpt/css/css-display/display-with-float.html
new file mode 100644
index 0000000..49f9479
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/display-with-float.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Computed float value of flex/grid items</title>
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#flex-containers">
+<link rel="help" href="https://drafts.csswg.org/css-grid-1/#grid-containers">
+<meta name="assert" content="computed float value of flex/grid items should be as specified">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div style="display:flex;">
+  <div id="flex-item" style="float:left;"></div>
+</div>
+<div style="display:grid;">
+  <div id="grid-item" style="float:right;"></div>
+</div>
+<script>
+  function getFloatFor(id) {
+    return window.getComputedStyle(document.getElementById(id)).getPropertyValue("float");
+  }
+  test(function() {
+    assert_equals(getFloatFor("flex-item"), "left");
+    assert_equals(getFloatFor("grid-item"), "right");
+  }, "computed style for float");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-document-element-will-change.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-document-element-will-change.html
new file mode 100644
index 0000000..977eaca
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-document-element-will-change.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<style>
+html {
+  background: red;
+  /* an "L" shape */
+  clip-path: polygon(50px 50px, 100px 50px, 100px 100px, 150px 100px, 150px 150px, 50px 150px);
+  will-change: transform;
+}
+div {
+  width: 500px;
+  height: 500px;
+  background: green;
+}
+</style>
+<link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path">
+<link rel="help" href="https://drafts.fxtf.org/compositing/#rootgroup">
+<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
+<link rel="match" href="reference/clip-path-document-element-ref.html">
+<meta name="assert" content="Clip-path on the document element applies to the root background.
+    The test passes if there is a green 'L' shape without red.">
+<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-document-element.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-document-element.html
new file mode 100644
index 0000000..56f2d5c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-document-element.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<style>
+html {
+  background: red;
+  /* an "L" shape */
+  clip-path: polygon(50px 50px, 100px 50px, 100px 100px, 150px 100px, 150px 150px, 50px 150px);
+}
+div {
+  width: 500px;
+  height: 500px;
+  background: green;
+}
+</style>
+<link rel="help" href="http://www.w3.org/TR/css-masking-1/#the-clip-path">
+<link rel="help" href="https://drafts.fxtf.org/compositing/#rootgroup">
+<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
+<link rel="match" href="reference/clip-path-document-element-ref.html">
+<meta name="assert" content="Clip-path on the document element applies to the root background.
+    The test passes if there is a green 'L' shape without red.">
+<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-document-element-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-document-element-ref.html
new file mode 100644
index 0000000..4608e54
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-document-element-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<style>
+div {
+  position: absolute;
+  width: 50px;
+  height: 50px;
+  background: green;
+}
+</style>
+<div style="top: 50px; left: 50px"></div>
+<div style="top: 100px; left: 50px"></div>
+<div style="top: 100px; left: 100px"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/cursor-auto-007.html b/third_party/blink/web_tests/external/wpt/css/css-ui/cursor-auto-007.html
index 6cf1495..0d355ad 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/cursor-auto-007.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/cursor-auto-007.html
@@ -36,7 +36,7 @@
   .unselectable {
     display: block;
     user-select: none;
-    -webkit-user-select: none; /* Yes, vendor prefixes are ugly. But this one was grandfathered in and support is required by spec. */
+    -webkit-user-select: none;
   }
 }
 
diff --git a/third_party/blink/web_tests/external/wpt/deprecation-reporting/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/deprecation-reporting/idlharness.any-expected.txt
new file mode 100644
index 0000000..3dbd47f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/deprecation-reporting/idlharness.any-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS idl_test setup
+PASS idl_test validation
+FAIL DeprecationReportBody interface: existence and properties of interface object assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface object length assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface object name assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: operation toJSON() assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute id assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute anticipatedRemoval assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute message assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute sourceFile assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute lineNumber assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute columnNumber assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/deprecation-reporting/idlharness.any.js b/third_party/blink/web_tests/external/wpt/deprecation-reporting/idlharness.any.js
new file mode 100644
index 0000000..720bacf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/deprecation-reporting/idlharness.any.js
@@ -0,0 +1,14 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+'use strict';
+
+idl_test(
+  ['deprecation-reporting'],
+  ['reporting'],
+  idl_array => {
+    idl_array.add_objects({
+      // TODO: objects
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/deprecation-reporting/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/deprecation-reporting/idlharness.any.worker-expected.txt
new file mode 100644
index 0000000..3dbd47f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/deprecation-reporting/idlharness.any.worker-expected.txt
@@ -0,0 +1,18 @@
+This is a testharness.js-based test.
+PASS idl_test setup
+PASS idl_test validation
+FAIL DeprecationReportBody interface: existence and properties of interface object assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface object length assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface object name assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: existence and properties of interface prototype object assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: operation toJSON() assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute id assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute anticipatedRemoval assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute message assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute sourceFile assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute lineNumber assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+FAIL DeprecationReportBody interface: attribute columnNumber assert_own_property: self does not have own property "DeprecationReportBody" expected property "DeprecationReportBody" missing
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/redirect-navigate/preserve-fragment.html b/third_party/blink/web_tests/external/wpt/fetch/redirect-navigate/preserve-fragment.html
index 72ed24c..682539a 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/redirect-navigate/preserve-fragment.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/redirect-navigate/preserve-fragment.html
@@ -3,6 +3,11 @@
   <head>
     <meta charset="UTF-8">
     <title>Ensure fragment is kept across redirects</title>
+    <meta name="timeout" content="long">
+    <link rel=help href="https://www.w3.org/TR/cuap/#uri">
+    <link rel=help href="https://tools.ietf.org/html/rfc7231#section-7.1.2">
+    <link rel=help href="https://bugs.webkit.org/show_bug.cgi?id=158420">
+    <link rel=help href="https://bugs.webkit.org/show_bug.cgi?id=24175">
     <script src="/common/get-host-info.sub.js"></script>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/flex-legend-float-abspos.html b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/flex-legend-float-abspos.html
new file mode 100644
index 0000000..f6eead47
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/flex-legend-float-abspos.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<title>
+  legend and float and position: absolute/fixed when the display type of
+  the fieldset is flex.
+</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<style>
+ body { margin: 0; }
+ fieldset {
+   border: 10px solid;
+   display: flex;
+   margin: 0;
+   padding: 20px;
+   width: 300px;
+ }
+ legend { height: 10px; }
+ #legend1 { float: left; }
+ #legend2 { float: right; }
+ #legend3 { position: absolute; }
+ #legend4 { position: fixed; }
+</style>
+<fieldset id=fieldset>
+  <div>div</div>
+  <legend id=legend1>legend1</legend>
+  <legend id=legend2>legend2</legend>
+  <legend id=legend3>legend3</legend>
+  <legend id=legend4>legend4</legend>
+  <legend id=legend5>legend5</legend>
+</fieldset>
+<script>
+ const fieldset = document.getElementById('fieldset');
+ const legends = document.getElementsByTagName('legend');
+ const [legend1, legend2, legend3, legend4, legend5] = legends;
+ const expectedTop = 0;
+ const expectedLeft = 10 + 20;
+
+ function assert_rendered_legend(legend) {
+   assert_equals(legend.offsetTop, expectedTop, `${legend.id}.offsetTop`);
+   assert_equals(legend.offsetLeft, expectedLeft, `${legend.id}.offsetLeft`);
+   for (const other of legends) {
+     if (other === legend) {
+       continue;
+     }
+     if (other.offsetTop === expectedTop && other.offsetLeft === expectedLeft) {
+       assert_unreached(`${other.id} should not be the "rendered legend"`);
+     }
+   }
+ }
+
+ test(t => {
+   assert_rendered_legend(legend5);
+ }, 'no dynamic changes');
+
+ test(t => {
+   const legend = document.createElement('legend');
+   t.add_cleanup(() => {
+     legend.remove();
+   });
+   legend.id = 'script-inserted';
+   legend.textContent = 'script-inserted legend';
+   fieldset.insertBefore(legend, legend1);
+   assert_rendered_legend(legend);
+   legend.remove();
+   assert_rendered_legend(legend5);
+ }, 'inserting a new legend and removing it again');
+
+ test(t => {
+   t.add_cleanup(() => {
+     legend1.id = 'legend1';
+     legend2.id = 'legend2';
+   });
+   legend2.id = '';
+   assert_rendered_legend(legend2);
+   legend1.id = '';
+   assert_rendered_legend(legend1);
+   legend1.id = 'legend1';
+   assert_rendered_legend(legend2);
+   legend2.id = 'legend2';
+   assert_rendered_legend(legend5);
+ }, 'dynamic changes to float');
+
+ test(t => {
+   t.add_cleanup(() => {
+     legend3.id = 'legend3';
+     legend4.id = 'legend4';
+   });
+   legend4.id = '';
+   assert_rendered_legend(legend4);
+   legend3.id = '';
+   assert_rendered_legend(legend3);
+   legend3.id = 'legend3';
+   assert_rendered_legend(legend4);
+   legend4.id = 'legend4';
+   assert_rendered_legend(legend5);
+ }, 'dynamic changes to position');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl b/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl
index cf30b612..926a4fc2 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/appmanifest.idl
@@ -34,7 +34,6 @@
 };
 
 dictionary ManifestImageResource : ImageResource {
-  USVString platform;
   USVString purpose;
 };
 
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/deprecation-reporting.idl b/third_party/blink/web_tests/external/wpt/interfaces/deprecation-reporting.idl
new file mode 100644
index 0000000..e627119
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/interfaces/deprecation-reporting.idl
@@ -0,0 +1,15 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content was automatically extracted by Reffy into reffy-reports
+// (https://github.com/tidoust/reffy-reports)
+// Source: Deprecation Reporting (https://wicg.github.io/deprecation-reporting/)
+
+[Exposed=(Window,Worker)]
+interface DeprecationReportBody : ReportBody {
+  [Default] object toJSON();
+  readonly attribute DOMString id;
+  readonly attribute Date? anticipatedRemoval;
+  readonly attribute DOMString message;
+  readonly attribute DOMString? sourceFile;
+  readonly attribute unsigned long? lineNumber;
+  readonly attribute unsigned long? columnNumber;
+};
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-2-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-2-expected.txt
deleted file mode 100644
index ec0e5ce..0000000
--- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-2-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-FAIL Respective horizontal positions assert_less_than_equal: 1 expected a number less than or equal to 38 but got 68
-PASS Alignment of the base on the baseline
-FAIL Vertical position of scripts assert_approx_equals: script is placed at the bottom of the base expected 46 +/- 3 but got 51
-FAIL Width of scripted elements assert_approx_equals: width is determined by the left/right sides of base/script (+ some space after script) expected 10 +/- 3 but got 30
-FAIL Height of scripted elements assert_approx_equals: msup height is determined by the top/bottom sides of base/scripts expected 30 +/- 3 but got 40
-PASS Size of empty elements
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-3-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-3-expected.txt
deleted file mode 100644
index dc82b64..0000000
--- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-3-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Alignment of the base on the baseline
-FAIL Dimensions of the scripted elements assert_approx_equals: height of multiscript2 expected 20 +/- 5 but got 70
-FAIL Vertical positions of scripts assert_approx_equals: multi2 1 presup script expected 81 +/- 3 but got 16
-PASS Horizontal alignment of scripts
-FAIL Horizontal positions of scripts assert_less_than_equal: 1 expected a number less than or equal to 98 but got 128
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt
deleted file mode 100644
index 6f018c0..0000000
--- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS Alignment on the baseline with different and large script heights
-FAIL Tall subscripts/superscripts are not placed too high/low assert_less_than: mmultiscripts: postsupscript is above the bottom of the base expected a number less than 184.671875 but got 434.671875
-FAIL No collisions for tall subscripts and superscripts assert_greater_than: mmultiscripts: presubscript is below the presuperscript expected a number greater than 684.671875 but got 434.671875
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-1-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-1-expected.txt
deleted file mode 100644
index 12898fbb..0000000
--- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-1-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a testharness.js-based test.
-FAIL SpaceAfterScript assert_approx_equals: mmultiscripts: Space after first superscript expected 30 +/- 1 but got -10
-FAIL SuperscriptShiftUp assert_approx_equals: mmultiscripts: First superscript shift expected 70 +/- 1 but got -10
-FAIL SuperscriptShiftUpCramped assert_approx_equals: mmultiscripts: First superscript shift expected 50 +/- 1 but got -10
-FAIL SubscriptShiftDown assert_approx_equals: mmultiscripts: First subscript shift expected 60 +/- 1 but got 10
-FAIL SubSuperscriptGapMin assert_approx_equals: mmultiscripts: SubSuperscript gap expected 110 +/- 1 but got -20
-FAIL SuperscriptBottomMaxWithSubscript assert_approx_equals: mmultiscripts: SubSuperscript gap expected 110 +/- 1 but got -20
-PASS SubscriptTopMax
-PASS SuperscriptBottomMin
-PASS SubscriptBaselineDrop
-PASS SuperscriptBaselineDrop
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/default-properties-on-the-math-root-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/default-properties-on-the-math-root-expected.txt
new file mode 100644
index 0000000..d0fae2e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/default-properties-on-the-math-root-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL Value of direction on the <math> root assert_equals: when specified from the UA sheet expected "ltr" but got "rtl"
+PASS Value of writing-mode on the <math> root
+FAIL Value of text-indent on the <math> root assert_equals: when specified from the UA sheet expected "0px" but got "8px"
+FAIL Value of letter-spacing on the <math> root assert_equals: when specified from the UA sheet expected "normal" but got "8px"
+FAIL Value of line-height on the <math> root assert_equals: when specified from the UA sheet expected "normal" but got "8px"
+FAIL Value of word-spacing on the <math> root assert_equals: when specified from the UA sheet expected "0px" but got "8px"
+FAIL Value of font-style on the <math> root assert_equals: when specified from the UA sheet expected "normal" but got "italic"
+FAIL Value of font-weight on the <math> root assert_equals: when specified from the UA sheet expected "400" but got "700"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/default-properties-on-the-math-root.html b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/default-properties-on-the-math-root.html
new file mode 100644
index 0000000..80a0977
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/default-properties-on-the-math-root.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Default properties on the &lt;math&gt; root</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#the-top-level-math-element">
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#user-agent-stylesheet">
+<meta name="assert" content="Test properties on the math root set by the UA stylesheet.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  math {
+      font-size: 100px;
+  }
+  .styled {
+      direction: rtl;
+      writing-mode: vertical-lr;
+      text-indent: .5em;
+      letter-spacing: .5em;
+      line-height: .5em;
+      word-spacing: .5em;
+      font-style: italic;
+      font-weight: bold;
+  }
+</style>
+
+</head>
+<body>
+  <div id="log"></div>
+  <div class="styled">
+    <math id="ua"></math>
+    <math id="author" class="styled"></math>
+  </div>
+
+  <script>
+    function getProperty(id, property) {
+        return window.getComputedStyle(document.getElementById(id))[property];
+    }
+    [
+        // Property name, value when specified from the UA, from the author.
+        ["direction", "ltr", "rtl"],
+        ["writing-mode", "horizontal-tb", "horizontal-tb"], // MathML Core level 1 only supports horizontal mode.
+        ["text-indent", "0px", "50px"],
+        ["letter-spacing", "normal", "50px"],
+        ["line-height", "normal", "50px"],
+        ["word-spacing", "0px", "50px"],
+        ["font-style", "normal", "italic"],
+        ["font-weight", "400", "700"]
+    ].forEach(([name, ua_value, author_value]) => {
+        test(function () {
+            assert_equals(getProperty("ua", name), ua_value, "when specified from the UA sheet");
+            assert_equals(getProperty("author", name), author_value, "when specified by the author");
+        }, `Value of ${name} on the <math> root`);
+    });
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/padding-border-margin/margin-003-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/padding-border-margin/margin-003-expected.txt
deleted file mode 100644
index 78a9299..0000000
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/padding-border-margin/margin-003-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-PASS Margin properties on the children of menclose
-PASS Margin properties on the children of merror
-PASS Margin properties on the children of mfrac
-FAIL Margin properties on the children of mmultiscripts assert_approx_equals: block size expected 345 +/- 1 but got 305
-PASS Margin properties on the children of mover
-PASS Margin properties on the children of mpadded
-PASS Margin properties on the children of mphantom
-PASS Margin properties on the children of mroot
-PASS Margin properties on the children of mrow
-PASS Margin properties on the children of msqrt
-PASS Margin properties on the children of mstyle
-PASS Margin properties on the children of msub
-PASS Margin properties on the children of msubsup
-PASS Margin properties on the children of msup
-PASS Margin properties on the children of munder
-PASS Margin properties on the children of munderover
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/video-rvfc/request-video-frame-callback-webrtc.https.html b/third_party/blink/web_tests/external/wpt/video-rvfc/request-video-frame-callback-webrtc.https.html
index b6131d6..ce5b5ad 100644
--- a/third_party/blink/web_tests/external/wpt/video-rvfc/request-video-frame-callback-webrtc.https.html
+++ b/third_party/blink/web_tests/external/wpt/video-rvfc/request-video-frame-callback-webrtc.https.html
@@ -64,9 +64,11 @@
 
   function getNoiseStreamOkCallback(localStream) {
     gFirstConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gFirstConnection.close());
     gFirstConnection.onicecandidate = onIceCandidateToFirst;
 
     gSecondConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gSecondConnection.close());
     gSecondConnection.onicecandidate = onIceCandidateToSecond;
     gSecondConnection.ontrack = onRemoteTrack;
 
@@ -146,4 +148,4 @@
 </script>
 
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-duration-loop.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-duration-loop.html
new file mode 100644
index 0000000..faa70e1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-duration-loop.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>
+      Test AudioBufferSourceNode With Looping And Duration
+    </title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src="/webaudio/resources/audit-util.js"></script>
+    <script src="/webaudio/resources/audit.js"></script>
+  </head>
+  <body>
+    <script id="layout-test-code">
+      let audit = Audit.createTaskRunner();
+      audit.define('loop with duration', (task, should) => {
+        // Create the context
+        let context = new OfflineAudioContext(1, 4096, 48000);
+
+        // Create the sample buffer and fill the second half with 1
+        let buffer = context.createBuffer(1, 2048, context.sampleRate);
+        for(let i = 1024; i < 2048; i++) {
+          buffer.getChannelData(0)[i] = 1;
+        }
+
+        // Create the source and set its value
+        let source = context.createBufferSource();
+        source.loop = true;
+        source.loopStart = 1024 / context.sampleRate;
+        source.loopEnd = 2048 / context.sampleRate;
+        source.buffer = buffer;
+        source.connect(context.destination);
+        source.start(0, 1024 / context.sampleRate, 2048 / context.sampleRate);
+        // Render it!
+        context.startRendering()
+          .then(function(audioBuffer) {
+            for(let i = 0; i < 2048; i++) {
+              assert_equals(audioBuffer.getChannelData(0)[i], 1,
+                  "audioBuffer did not loop as intended");
+            }
+            for(let i = 2048; i < 4096; i++) {
+              assert_equals(audioBuffer.getChannelData(0)[i], 0,
+                  "audioBuffer did not respect duration");
+            }
+          })
+          .then(task.done());
+      });
+
+      audit.run();
+
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-createDataChannel.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-createDataChannel.html
index 3d2169d..87867664 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-createDataChannel.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-createDataChannel.html
@@ -1,5 +1,6 @@
 <!doctype html>
 <meta charset=utf-8>
+<meta name="timeout" content="long">
 <title>RTCPeerConnection.prototype.createDataChannel</title>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html
index 851ce88..d312606 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-iceConnectionState.https.html
@@ -122,6 +122,8 @@
         assert_true(had_checking, 'state should pass checking before' +
                                   ' reaching connected or completed');
         t.done();
+      } else if (iceConnectionState === 'failed') {
+        assert_unreached("ICE should not fail");
       }
     });
 
@@ -165,6 +167,8 @@
           'Expect ICE transport to be in connected state when' +
           ' iceConnectionState is completed');
         t.done();
+      } else if (iceConnectionState === 'failed') {
+        assert_unreached("ICE should not fail");
       }
     });
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html
index 59761c4..d2ee646 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html
@@ -1,5 +1,6 @@
 <!doctype html>
 <meta charset=utf-8>
+<meta name="timeout" content="long">
 <title>RTCPeerConnection.prototype.setRemoteDescription - add/remove remote tracks</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/datachannel-emptystring.html b/third_party/blink/web_tests/external/wpt/webrtc/datachannel-emptystring.html
index 6af436a..456bac7 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/datachannel-emptystring.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/datachannel-emptystring.html
@@ -76,8 +76,10 @@
 
   test.step(function() {
     gFirstConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gFirstConnection.close());
 
     gSecondConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gSecondConnection.close());
 
     gFirstConnection.onicecandidate = exchangeIce(gSecondConnection);
     gSecondConnection.onicecandidate = exchangeIce(gFirstConnection);
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/getstats.html b/third_party/blink/web_tests/external/wpt/webrtc/getstats.html
index 979e99c..0950a37 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/getstats.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/getstats.html
@@ -81,10 +81,12 @@
   // This function starts the test.
   test.step(function() {
     gFirstConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gFirstConnection.close());
     gFirstConnection.onicecandidate = onIceCandidateToFirst;
     gFirstConnection.oniceconnectionstatechange = onIceConnectionStateChange;
 
     gSecondConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gSecondConnection.close());
     gSecondConnection.onicecandidate = onIceCandidateToSecond;
 
     // The createDataChannel is necessary and sufficient to make
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/no-media-call.html b/third_party/blink/web_tests/external/wpt/webrtc/no-media-call.html
index dbe6a0d..b1eba08d 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/no-media-call.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/no-media-call.html
@@ -113,10 +113,12 @@
   // This function starts the test.
   test.step(function() {
     gFirstConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gFirstConnection.close());
     gFirstConnection.onicecandidate = onIceCandidateToFirst;
     gFirstConnection.oniceconnectionstatechange = onIceConnectionStateChange;
 
     gSecondConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gSecondConnection.close());
     gSecondConnection.onicecandidate = onIceCandidateToSecond;
     gSecondConnection.oniceconnectionstatechange = onIceConnectionStateChange;
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/promises-call.html b/third_party/blink/web_tests/external/wpt/webrtc/promises-call.html
index ceb6ab25..8b9a275 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/promises-call.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/promises-call.html
@@ -66,10 +66,12 @@
   // This function starts the test.
   test.step(function() {
     gFirstConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gFirstConnection.close());
     gFirstConnection.onicecandidate = onIceCandidateToFirst;
     gFirstConnection.oniceconnectionstatechange = onIceConnectionStateChange;
 
     gSecondConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gSecondConnection.close());
     gSecondConnection.onicecandidate = onIceCandidateToSecond;
     gSecondConnection.oniceconnectionstatechange = onIceConnectionStateChange;
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/simplecall-no-ssrcs.https.html b/third_party/blink/web_tests/external/wpt/webrtc/simplecall-no-ssrcs.https.html
index 87f8d939..5160451 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/simplecall-no-ssrcs.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/simplecall-no-ssrcs.https.html
@@ -32,6 +32,7 @@
 
   function getNoiseStreamOkCallback(localStream) {
     gFirstConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gFirstConnection.close());
     gFirstConnection.onicecandidate = onIceCandidateToFirst;
     localStream.getTracks().forEach(function(track) {
       gFirstConnection.addTrack(track, localStream);
@@ -56,6 +57,7 @@
 
   function receiveCall(offerSdp) {
     gSecondConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gSecondConnection.close());
     gSecondConnection.onicecandidate = onIceCandidateToSecond;
     gSecondConnection.ontrack = onRemoteTrack;
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/simplecall.https.html b/third_party/blink/web_tests/external/wpt/webrtc/simplecall.https.html
index 291437a5..ffe043b 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/simplecall.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/simplecall.https.html
@@ -32,6 +32,7 @@
 
   function getNoiseStreamOkCallback(localStream) {
     gFirstConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gFirstConnection.close());
     gFirstConnection.onicecandidate = onIceCandidateToFirst;
     localStream.getTracks().forEach(function(track) {
       gFirstConnection.addTrack(track, localStream);
@@ -52,6 +53,7 @@
 
   function receiveCall(offerSdp) {
     gSecondConnection = new RTCPeerConnection(null);
+    test.add_cleanup(() => gSecondConnection.close());
     gSecondConnection.onicecandidate = onIceCandidateToSecond;
     gSecondConnection.ontrack = onRemoteTrack;
 
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/clip/clip-path-constant-repaint-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/clip/clip-path-constant-repaint-expected.txt
index 9892e76..9d3ba03 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/clip/clip-path-constant-repaint-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/clip/clip-path-constant-repaint-expected.txt
@@ -11,11 +11,6 @@
       "bounds": [800, 300],
       "backgroundColor": "#FF0000E6",
       "transform": 2
-    },
-    {
-      "name": "Mask Layer",
-      "bounds": [800, 300],
-      "transform": 2
     }
   ],
   "transforms": [
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt
index 583e2ee..2c896bb 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt
@@ -14,14 +14,6 @@
         [0, 0, 200, 200]
       ],
       "transform": 1
-    },
-    {
-      "name": "Mask Layer",
-      "bounds": [200, 200],
-      "invalidations": [
-        [0, 0, 200, 200]
-      ],
-      "transform": 1
     }
   ],
   "transforms": [
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/abspos-non-replaced-width-margin-000-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/abspos-non-replaced-width-margin-000-expected.png
new file mode 100644
index 0000000..0764a77
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/abspos-non-replaced-width-margin-000-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/abspos-replaced-width-margin-000-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/abspos-replaced-width-margin-000-expected.png
new file mode 100644
index 0000000..bd469122
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/abspos-replaced-width-margin-000-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-001-expected.png
new file mode 100644
index 0000000..12354f2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-002-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-002-expected.png
new file mode 100644
index 0000000..12354f2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-002-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-003-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-003-expected.png
new file mode 100644
index 0000000..12354f2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-003-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-004-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-004-expected.png
new file mode 100644
index 0000000..b5ace1609
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-004-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-005-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-005-expected.png
new file mode 100644
index 0000000..4c0e90d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-005-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-006-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-006-expected.png
new file mode 100644
index 0000000..598d228
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-006-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-007-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-007-expected.png
new file mode 100644
index 0000000..12354f2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-007-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-008-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-008-expected.png
new file mode 100644
index 0000000..12354f2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-008-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-009-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-009-expected.png
new file mode 100644
index 0000000..12354f2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/background-intrinsic-009-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-collapse-offset-002-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-collapse-offset-002-expected.png
new file mode 100644
index 0000000..ce314d008
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-collapse-offset-002-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-conflict-style-079-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-conflict-style-079-expected.png
new file mode 100644
index 0000000..27db7b9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-conflict-style-079-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-conflict-style-088-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-conflict-style-088-expected.png
new file mode 100644
index 0000000..12d8f0f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-conflict-style-088-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-spacing-applies-to-015-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-spacing-applies-to-015-expected.png
new file mode 100644
index 0000000..26fa96a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/border-spacing-applies-to-015-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/c543-txt-decor-000-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/c543-txt-decor-000-expected.png
new file mode 100644
index 0000000..8c68684a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/c543-txt-decor-000-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/height-width-inline-table-001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/height-width-inline-table-001-expected.png
new file mode 100644
index 0000000..b9f2150
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/height-width-inline-table-001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/height-width-table-001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/height-width-table-001-expected.png
new file mode 100644
index 0000000..b9f2150
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/height-width-table-001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/inline-table-001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/inline-table-001-expected.png
new file mode 100644
index 0000000..c8ddd6a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/inline-table-001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/list-style-position-005-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/list-style-position-005-expected.png
new file mode 100644
index 0000000..0736977
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/list-style-position-005-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-001-expected.png
new file mode 100644
index 0000000..dc5a388
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-002-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-002-expected.png
new file mode 100644
index 0000000..dc5a388
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-002-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-003-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-003-expected.png
new file mode 100644
index 0000000..dc5a388
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-003-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-004-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-004-expected.png
new file mode 100644
index 0000000..dc5a388
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-004-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-005-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-005-expected.png
new file mode 100644
index 0000000..dc5a388
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-005-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-006-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-006-expected.png
new file mode 100644
index 0000000..dc5a388
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-006-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-007-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-007-expected.png
new file mode 100644
index 0000000..dc5a388
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-007-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-008-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-008-expected.png
new file mode 100644
index 0000000..81edcc4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-008-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-009-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-009-expected.png
new file mode 100644
index 0000000..55a939e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-009-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-010-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-010-expected.png
new file mode 100644
index 0000000..5155451
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-010-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-012-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-012-expected.png
new file mode 100644
index 0000000..d46d866c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-012-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-013-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-013-expected.png
new file mode 100644
index 0000000..55a939e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-013-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-015-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-015-expected.png
new file mode 100644
index 0000000..55a939e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/margin-applies-to-015-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/outline-color-applies-to-008-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/outline-color-applies-to-008-expected.png
new file mode 100644
index 0000000..f04ad1c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/outline-color-applies-to-008-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/outline-color-applies-to-014-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/outline-color-applies-to-014-expected.png
new file mode 100644
index 0000000..56aeef3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/outline-color-applies-to-014-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-001-expected.png
new file mode 100644
index 0000000..6113a4981
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-002-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-002-expected.png
new file mode 100644
index 0000000..8dc5d67
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-002-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-horizontal-alignment-001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-horizontal-alignment-001-expected.png
new file mode 100644
index 0000000..9e46e62d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-horizontal-alignment-001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-margins-001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-margins-001-expected.png
new file mode 100644
index 0000000..2f807cf4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-margins-001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-optional-001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-optional-001-expected.png
new file mode 100644
index 0000000..43e813e8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-optional-001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-optional-002-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-optional-002-expected.png
new file mode 100644
index 0000000..2b640a6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-caption-optional-002-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-height-algorithm-023-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-height-algorithm-023-expected.png
new file mode 100644
index 0000000..9ae4f5f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-height-algorithm-023-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-height-algorithm-024-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-height-algorithm-024-expected.png
new file mode 100644
index 0000000..9ae4f5f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/20110323/table-height-algorithm-024-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-00-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-00-f-expected.png
new file mode 100644
index 0000000..4cc66d8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-00-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-01-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-01-f-expected.png
new file mode 100644
index 0000000..ad8e8d99
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-01-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-02-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-02-f-expected.png
new file mode 100644
index 0000000..5db0ddcc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-02-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-03-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-03-f-expected.png
new file mode 100644
index 0000000..ae597c02aa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-03-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-04-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-04-f-expected.png
new file mode 100644
index 0000000..d19301c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-c71-fwd-parsing-04-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-01-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-01-f-expected.png
new file mode 100644
index 0000000..4a166cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-01-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-02-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-02-f-expected.png
new file mode 100644
index 0000000..4a166cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-02-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-03-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-03-f-expected.png
new file mode 100644
index 0000000..4a166cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-03-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-04-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-04-f-expected.png
new file mode 100644
index 0000000..4a166cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-04-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-05-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-05-f-expected.png
new file mode 100644
index 0000000..4a166cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-05-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-06-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-06-f-expected.png
new file mode 100644
index 0000000..4a166cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0402-syntax-06-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0505-c16-descendant-00-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0505-c16-descendant-00-e-expected.png
new file mode 100644
index 0000000..65d0393
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0505-c16-descendant-00-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0505-c16-descendant-01-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0505-c16-descendant-01-e-expected.png
new file mode 100644
index 0000000..3c806d3c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0505-c16-descendant-01-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0505-c16-descendant-02-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0505-c16-descendant-02-e-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0505-c16-descendant-02-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-c15-ids-00-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-c15-ids-00-a-expected.png
new file mode 100644
index 0000000..eff9119e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-c15-ids-00-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-c15-ids-01-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-c15-ids-01-e-expected.png
new file mode 100644
index 0000000..7717f13
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-c15-ids-01-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-id-sel-syntax-01-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-id-sel-syntax-01-f-expected.png
new file mode 100644
index 0000000..4a166cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-id-sel-syntax-01-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-id-sel-syntax-02-b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-id-sel-syntax-02-b-expected.png
new file mode 100644
index 0000000..4a166cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0509-id-sel-syntax-02-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0510-c25-pseudo-elmnt-00-c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0510-c25-pseudo-elmnt-00-c-expected.png
new file mode 100644
index 0000000..14baf070
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0510-c25-pseudo-elmnt-00-c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-anch-00-e-i-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-anch-00-e-i-expected.png
new file mode 100644
index 0000000..0b66930
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-anch-00-e-i-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-00-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-00-e-expected.png
new file mode 100644
index 0000000..2086ad5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-00-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-01-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-01-e-expected.png
new file mode 100644
index 0000000..2086ad5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-01-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-02-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-02-e-expected.png
new file mode 100644
index 0000000..2086ad5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-02-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-03-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-03-e-expected.png
new file mode 100644
index 0000000..2086ad5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0511-c21-pseud-link-03-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0602-c13-inh-underlin-00-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0602-c13-inh-underlin-00-e-expected.png
new file mode 100644
index 0000000..526fa17
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0602-c13-inh-underlin-00-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0602-c13-inheritance-00-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0602-c13-inheritance-00-e-expected.png
new file mode 100644
index 0000000..a28c1d1cd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0602-c13-inheritance-00-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0602-inherit-bdr-pad-b-00-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0602-inherit-bdr-pad-b-00-expected.png
new file mode 100644
index 0000000..6e222ff
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0602-inherit-bdr-pad-b-00-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0603-c11-import-00-b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0603-c11-import-00-b-expected.png
new file mode 100644
index 0000000..7d16ce7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0603-c11-import-00-b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0801-c412-hz-box-00-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0801-c412-hz-box-00-b-a-expected.png
new file mode 100644
index 0000000..7e46807
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0801-c412-hz-box-00-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5501-imrgn-t-00-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5501-imrgn-t-00-b-ag-expected.png
new file mode 100644
index 0000000..0a375fa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5501-imrgn-t-00-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5501-mrgn-t-00-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5501-mrgn-t-00-b-a-expected.png
new file mode 100644
index 0000000..04663b7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5501-mrgn-t-00-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-00-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-00-b-ag-expected.png
new file mode 100644
index 0000000..c8425721
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-00-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-01-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-01-b-ag-expected.png
new file mode 100644
index 0000000..dadee81
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-01-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-02-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-02-b-a-expected.png
new file mode 100644
index 0000000..6567a613
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-02-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-03-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-03-b-a-expected.png
new file mode 100644
index 0000000..ce02d22
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-03-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-04-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-04-b-ag-expected.png
new file mode 100644
index 0000000..09a0203
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-04-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-05-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-05-b-ag-expected.png
new file mode 100644
index 0000000..6fb7b2c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-05-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-06-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-06-b-ag-expected.png
new file mode 100644
index 0000000..373fa8bf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-imrgn-r-06-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-00-c-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-00-c-ag-expected.png
new file mode 100644
index 0000000..aa7f467
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-00-c-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-01-c-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-01-c-a-expected.png
new file mode 100644
index 0000000..9d33f0a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-01-c-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-02-c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-02-c-expected.png
new file mode 100644
index 0000000..debe752
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-02-c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-03-c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-03-c-expected.png
new file mode 100644
index 0000000..bf028a6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5502-mrgn-r-03-c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5503-imrgn-b-00-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5503-imrgn-b-00-b-a-expected.png
new file mode 100644
index 0000000..0a375fa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5503-imrgn-b-00-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5503-mrgn-b-00-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5503-mrgn-b-00-b-a-expected.png
new file mode 100644
index 0000000..0df47b4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5503-mrgn-b-00-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-00-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-00-b-ag-expected.png
new file mode 100644
index 0000000..c8425721
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-00-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-01-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-01-b-ag-expected.png
new file mode 100644
index 0000000..27f53f77
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-01-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-02-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-02-b-ag-expected.png
new file mode 100644
index 0000000..ed46f0b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-02-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-03-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-03-b-a-expected.png
new file mode 100644
index 0000000..ae41d789
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-03-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-04-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-04-b-ag-expected.png
new file mode 100644
index 0000000..703b6e3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-04-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-05-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-05-b-ag-expected.png
new file mode 100644
index 0000000..32ec85aa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-05-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-06-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-06-b-ag-expected.png
new file mode 100644
index 0000000..7d94dda
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-imrgn-l-06-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-00-c-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-00-c-ag-expected.png
new file mode 100644
index 0000000..053d011
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-00-c-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-01-c-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-01-c-a-expected.png
new file mode 100644
index 0000000..176ca9c1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-01-c-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-02-c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-02-c-expected.png
new file mode 100644
index 0000000..6aa9f54c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-02-c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-03-c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-03-c-expected.png
new file mode 100644
index 0000000..7a5e901
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5504-mrgn-l-03-c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-imrgn-00-a-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-imrgn-00-a-ag-expected.png
new file mode 100644
index 0000000..e49226f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-imrgn-00-a-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-00-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-00-b-ag-expected.png
new file mode 100644
index 0000000..65617e00
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-00-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-01-e-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-01-e-a-expected.png
new file mode 100644
index 0000000..e1aa931
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-01-e-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-02-c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-02-c-expected.png
new file mode 100644
index 0000000..46eb8c1e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-02-c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-03-c-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-03-c-ag-expected.png
new file mode 100644
index 0000000..dcc881b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0803-c5505-mrgn-03-c-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-ipadn-t-00-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-ipadn-t-00-b-a-expected.png
new file mode 100644
index 0000000..111829a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-ipadn-t-00-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-ipadn-t-01-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-ipadn-t-01-b-a-expected.png
new file mode 100644
index 0000000..111829a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-ipadn-t-01-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-ipadn-t-02-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-ipadn-t-02-b-a-expected.png
new file mode 100644
index 0000000..487dac8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-ipadn-t-02-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-padn-t-00-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-padn-t-00-b-a-expected.png
new file mode 100644
index 0000000..570404b8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5506-padn-t-00-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-00-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-00-b-ag-expected.png
new file mode 100644
index 0000000..c8425721
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-00-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-01-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-01-b-ag-expected.png
new file mode 100644
index 0000000..3f882ce
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-01-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-02-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-02-b-ag-expected.png
new file mode 100644
index 0000000..cc21f59
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-02-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-03-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-03-b-a-expected.png
new file mode 100644
index 0000000..ce02d22
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-03-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-04-b-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-04-b-ag-expected.png
new file mode 100644
index 0000000..fe03e5a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-ipadn-r-04-b-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-00-c-ag-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-00-c-ag-expected.png
new file mode 100644
index 0000000..8db1ed0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-00-c-ag-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-01-c-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-01-c-a-expected.png
new file mode 100644
index 0000000..a51537a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-01-c-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-02-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-02-f-expected.png
new file mode 100644
index 0000000..183e523
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-02-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-03-f-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-03-f-expected.png
new file mode 100644
index 0000000..799dd91
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5507-padn-r-03-f-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5508-ipadn-b-00-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5508-ipadn-b-00-b-a-expected.png
new file mode 100644
index 0000000..adcd0f61
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5508-ipadn-b-00-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5508-ipadn-b-01-f-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5508-ipadn-b-01-f-a-expected.png
new file mode 100644
index 0000000..adcd0f61
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5508-ipadn-b-01-f-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5508-ipadn-b-02-b-a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5508-ipadn-b-02-b-a-expected.png
new file mode 100644
index 0000000..6b2a178b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t0804-c5508-ipadn-b-02-b-a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t09-c5526c-display-00-e-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t09-c5526c-display-00-e-expected.png
new file mode 100644
index 0000000..cf7f2d2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css2.1/t09-c5526c-display-00-e-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-color-gradient-alignment-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-color-gradient-alignment-expected.png
new file mode 100644
index 0000000..e7b67aa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-color-gradient-alignment-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-large-position-and-size-remains-stable-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-large-position-and-size-remains-stable-expected.png
new file mode 100644
index 0000000..4272c25b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-large-position-and-size-remains-stable-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-percent-position-sprite-zoomed-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-percent-position-sprite-zoomed-expected.png
new file mode 100644
index 0000000..26a9267
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-percent-position-sprite-zoomed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-auto1-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-auto1-expected.png
new file mode 100644
index 0000000..dd933bb8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-auto1-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-border-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-border-expected.png
new file mode 100644
index 0000000..6c22f9d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-content-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-content-expected.png
new file mode 100644
index 0000000..ffb66b2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-content-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-padding-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-padding-expected.png
new file mode 100644
index 0000000..4076f3a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-repeat-round-padding-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-size-scaled-subset-of-small-image-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-size-scaled-subset-of-small-image-expected.png
new file mode 100644
index 0000000..9b5a2af1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/background-size-scaled-subset-of-small-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/zoomed-background-position-accuracy-2-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/zoomed-background-position-accuracy-2-expected.png
new file mode 100644
index 0000000..26a9267
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/zoomed-background-position-accuracy-2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/zoomed-background-position-accuracy-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/zoomed-background-position-accuracy-expected.png
new file mode 100644
index 0000000..d3e784e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/background/zoomed-background-position-accuracy-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
new file mode 100644
index 0000000..61ea1ac
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-data-uri-svg-image-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-data-uri-svg-image-expected.png
new file mode 100644
index 0000000..bba9f40
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-data-uri-svg-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-default-value-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-default-value-expected.png
new file mode 100644
index 0000000..eff1cf85
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-default-value-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-different-image-formats-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-different-image-formats-expected.png
new file mode 100644
index 0000000..21754d9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-different-image-formats-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-gif-color-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-gif-color-expected.png
new file mode 100644
index 0000000..1278c2d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-gif-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-gradient-color-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-gradient-color-expected.png
new file mode 100644
index 0000000..c423f52
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-gradient-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-gradient-image-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-gradient-image-expected.png
new file mode 100644
index 0000000..d9afaf33
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-gradient-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-image-color-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-image-color-expected.png
new file mode 100644
index 0000000..a7fb9a2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-image-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-image-image-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-image-image-expected.png
new file mode 100644
index 0000000..8f01f056
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-image-image-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-image-svg-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-image-svg-expected.png
new file mode 100644
index 0000000..8f8898b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-image-svg-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-multiple-background-layers-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-multiple-background-layers-expected.png
new file mode 100644
index 0000000..2028154
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-multiple-background-layers-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-opaque-layer-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-opaque-layer-expected.png
new file mode 100644
index 0000000..f2f2e1e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-opaque-layer-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-overlapping-accelerated-elements-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-overlapping-accelerated-elements-expected.png
new file mode 100644
index 0000000..df77014
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-overlapping-accelerated-elements-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-separate-layer-declaration-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-separate-layer-declaration-expected.png
new file mode 100644
index 0000000..b168402
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-separate-layer-declaration-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-single-layer-no-blending-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-single-layer-no-blending-expected.png
new file mode 100644
index 0000000..26ef680
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-single-layer-no-blending-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-svg-color-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-svg-color-expected.png
new file mode 100644
index 0000000..5d3d69976
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-svg-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-tiled-gradient-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-tiled-gradient-expected.png
new file mode 100644
index 0000000..11e3788
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/background-blend-mode-tiled-gradient-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/effect-background-blend-mode-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/effect-background-blend-mode-expected.png
new file mode 100644
index 0000000..b6b2693
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/effect-background-blend-mode-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/effect-background-blend-mode-stacking-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/effect-background-blend-mode-stacking-expected.png
new file mode 100644
index 0000000..374da50
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/effect-background-blend-mode-stacking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/effect-background-blend-mode-tiled-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/effect-background-blend-mode-tiled-expected.png
new file mode 100644
index 0000000..b07b3cf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/effect-background-blend-mode-tiled-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-isolated-group-1-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-isolated-group-1-expected.png
new file mode 100644
index 0000000..20e5adf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-isolated-group-1-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-isolated-group-2-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-isolated-group-2-expected.png
new file mode 100644
index 0000000..f050d34
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-isolated-group-2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-isolated-group-3-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-isolated-group-3-expected.png
new file mode 100644
index 0000000..a48c2b20
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-isolated-group-3-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-simple-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-simple-expected.png
new file mode 100644
index 0000000..8110a39
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-simple-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-simple-text-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-simple-text-expected.png
new file mode 100644
index 0000000..26383424
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-simple-text-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-with-masking-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-with-masking-expected.png
new file mode 100644
index 0000000..2648cad
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/mix-blend-mode-with-masking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-color-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-color-expected.png
new file mode 100644
index 0000000..b8f6b0a9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-hue-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-hue-expected.png
new file mode 100644
index 0000000..5877690f7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-hue-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-luminosity-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-luminosity-expected.png
new file mode 100644
index 0000000..711eecd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-luminosity-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-multiply-alpha-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-multiply-alpha-expected.png
new file mode 100644
index 0000000..ac74c22
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-multiply-alpha-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-saturation-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-saturation-expected.png
new file mode 100644
index 0000000..4b2b6ec
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/blending/svg-blend-saturation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-33-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-33-expected.png
new file mode 100644
index 0000000..f4307d7e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-33-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-35-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-35-expected.png
new file mode 100644
index 0000000..044ec311
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-35-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-36-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-36-expected.png
new file mode 100644
index 0000000..9df5a1e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-36-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-37-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-37-expected.png
new file mode 100644
index 0000000..e355174
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/css3-modsel-37-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/add-filter-rendering-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/add-filter-rendering-expected.png
new file mode 100644
index 0000000..4062f3b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/add-filter-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-basic-blur-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-basic-blur-expected.png
new file mode 100644
index 0000000..261ec2b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-basic-blur-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-border-radius-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-border-radius-expected.png
new file mode 100644
index 0000000..27846d5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-border-radius-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-boundary-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-boundary-expected.png
new file mode 100644
index 0000000..b3312fb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-boundary-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-browser-zoom-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-browser-zoom-expected.png
new file mode 100644
index 0000000..77011920
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-browser-zoom-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-clip-radius-zoom-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-clip-radius-zoom-expected.png
new file mode 100644
index 0000000..ee083fa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-clip-radius-zoom-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-clip-rect-zoom-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-clip-rect-zoom-expected.png
new file mode 100644
index 0000000..10f4d24
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-clip-rect-zoom-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-edge-clipping-2-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-edge-clipping-2-expected.png
new file mode 100644
index 0000000..ebe97c2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-edge-clipping-2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-edge-pixels-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-edge-pixels-expected.png
new file mode 100644
index 0000000..89e9677
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-edge-pixels-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-plus-mask-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-plus-mask-expected.png
new file mode 100644
index 0000000..81b801f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-plus-mask-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-plus-mask-large-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-plus-mask-large-expected.png
new file mode 100644
index 0000000..8e8c2a6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-plus-mask-large-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-transform-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-transform-expected.png
new file mode 100644
index 0000000..d76e5f59
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/backdrop-filter-transform-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/blur-filter-page-scroll-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/blur-filter-page-scroll-expected.png
new file mode 100644
index 0000000..9f84b6c7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/blur-filter-page-scroll-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/blur-filter-page-scroll-parents-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/blur-filter-page-scroll-parents-expected.png
new file mode 100644
index 0000000..6eea530
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/blur-filter-page-scroll-parents-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/blur-filter-page-scroll-self-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/blur-filter-page-scroll-self-expected.png
new file mode 100644
index 0000000..b1ddb30
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/blur-filter-page-scroll-self-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/buffer-offset-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/buffer-offset-expected.png
new file mode 100644
index 0000000..3120e26
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/buffer-offset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/composited-reflected-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/composited-reflected-expected.png
new file mode 100644
index 0000000..da44421a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/composited-reflected-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/crash-filter-change-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/crash-filter-change-expected.png
new file mode 100644
index 0000000..be5e56c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/crash-filter-change-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/css-opacity-with-drop-shadow-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/css-opacity-with-drop-shadow-expected.png
new file mode 100644
index 0000000..0cf0c89
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/css-opacity-with-drop-shadow-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-all-on-background-hw-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-all-on-background-hw-expected.png
new file mode 100644
index 0000000..19fbfb3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-all-on-background-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-blur-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-blur-expected.png
new file mode 100644
index 0000000..03537fc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-blur-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-blur-hw-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-blur-hw-expected.png
new file mode 100644
index 0000000..564459b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-blur-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-clamping-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-clamping-expected.png
new file mode 100644
index 0000000..98466182
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-clamping-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-clamping-hw-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-clamping-hw-expected.png
new file mode 100644
index 0000000..2dc1d85
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-clamping-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-expected.png
new file mode 100644
index 0000000..c3f4f523
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-hw-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-hw-expected.png
new file mode 100644
index 0000000..17b00c33
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-brightness-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-combined-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-combined-expected.png
new file mode 100644
index 0000000..9a2da23
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-combined-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-combined-hw-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-combined-hw-expected.png
new file mode 100644
index 0000000..7ca01af
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-combined-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-contrast-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-contrast-expected.png
new file mode 100644
index 0000000..36f2604
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-contrast-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-contrast-hw-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-contrast-hw-expected.png
new file mode 100644
index 0000000..5b87d24
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-contrast-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-drop-shadow-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-drop-shadow-expected.png
new file mode 100644
index 0000000..414e986
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-drop-shadow-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-drop-shadow-hw-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-drop-shadow-hw-expected.png
new file mode 100644
index 0000000..1b162fb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-drop-shadow-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-grayscale-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-grayscale-expected.png
new file mode 100644
index 0000000..1a2bd81
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-grayscale-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-grayscale-hw-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-grayscale-hw-expected.png
new file mode 100644
index 0000000..6137a35
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-grayscale-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-hue-rotate-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-hue-rotate-expected.png
new file mode 100644
index 0000000..8f162ae
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-hue-rotate-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-hue-rotate-hw-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-hue-rotate-hw-expected.png
new file mode 100644
index 0000000..a26478b4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/css3/filters/effect-hue-rotate-hw-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/fieldset-display-row-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/fieldset-display-row-expected.png
new file mode 100644
index 0000000..d097655
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/fieldset-display-row-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/find-next-layer-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/find-next-layer-expected.png
new file mode 100644
index 0000000..ab39a7e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/find-next-layer-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-child-pseudo-class-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-child-pseudo-class-expected.png
new file mode 100644
index 0000000..8881cae
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-child-pseudo-class-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-capitalized-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-capitalized-expected.png
new file mode 100644
index 0000000..c09ff51b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-capitalized-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-detach-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-detach-expected.png
new file mode 100644
index 0000000..9d6f822
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-detach-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-float-after-float-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-float-after-float-expected.png
new file mode 100644
index 0000000..e2a318d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-float-after-float-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-float-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-float-expected.png
new file mode 100644
index 0000000..fae3ad09
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-float-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-hover-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-hover-expected.png
new file mode 100644
index 0000000..7f1ec4a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-hover-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-recalculation-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-recalculation-expected.png
new file mode 100644
index 0000000..be310e6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-recalculation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-set-text-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-set-text-expected.png
new file mode 100644
index 0000000..673d7079
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-set-text-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-visibility-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-visibility-expected.png
new file mode 100644
index 0000000..26ddb8b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-letter-visibility-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-line-text-decoration-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-line-text-decoration-expected.png
new file mode 100644
index 0000000..61839c0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-line-text-decoration-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-line-text-decoration-inherited-from-parent-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-line-text-decoration-inherited-from-parent-expected.png
new file mode 100644
index 0000000..43a1ec32d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-line-text-decoration-inherited-from-parent-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-of-type-pseudo-class-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-of-type-pseudo-class-expected.png
new file mode 100644
index 0000000..19ef63bb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/first-of-type-pseudo-class-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-continuations-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-continuations-expected.png
new file mode 100644
index 0000000..f6dd7428
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-continuations-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-detached-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-detached-expected.png
new file mode 100644
index 0000000..069707d96
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-detached-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-multiline-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-multiline-expected.png
new file mode 100644
index 0000000..192357a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-multiline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-multiline-writingmode-vertical-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-multiline-writingmode-vertical-expected.png
new file mode 100644
index 0000000..8530f0d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-multiline-writingmode-vertical-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-outline-color-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-outline-color-expected.png
new file mode 100644
index 0000000..a302855
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-outline-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-outline-offset-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-outline-offset-expected.png
new file mode 100644
index 0000000..cc32ea7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-outline-offset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-outline-width-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-outline-width-expected.png
new file mode 100644
index 0000000..4f0255295d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/focus-ring-outline-width-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-opentype-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-opentype-expected.png
new file mode 100644
index 0000000..5bab969
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-opentype-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-synthetic-bold-italic-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-synthetic-bold-italic-expected.png
new file mode 100644
index 0000000..256c568
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-synthetic-bold-italic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-synthetic-bold-italic-for-locally-installed-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-synthetic-bold-italic-for-locally-installed-expected.png
new file mode 100644
index 0000000..dc9c0ee
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-synthetic-bold-italic-for-locally-installed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-weight-matching-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-weight-matching-expected.png
new file mode 100644
index 0000000..d993110
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-face-weight-matching-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-family-pictograph-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-family-pictograph-expected.png
new file mode 100644
index 0000000..e63fe76
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-family-pictograph-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-shorthand-weight-only-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-shorthand-weight-only-expected.png
new file mode 100644
index 0000000..04bd792
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-shorthand-weight-only-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-size-negative-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-size-negative-expected.png
new file mode 100644
index 0000000..70f98ec5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-size-negative-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-smoothing-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-smoothing-expected.png
new file mode 100644
index 0000000..eceb951
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-smoothing-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-weight-1-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-weight-1-expected.png
new file mode 100644
index 0000000..77290435
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font-weight-1-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font_property_normal-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font_property_normal-expected.png
new file mode 100644
index 0000000..99ab6b3
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/font_property_normal-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/h1-in-section-elements-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/h1-in-section-elements-expected.png
new file mode 100644
index 0000000..5bb14e1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/h1-in-section-elements-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/hover-subselector-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/hover-subselector-expected.png
new file mode 100644
index 0000000..063abee1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/hover-subselector-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/hsl-color-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/hsl-color-expected.png
new file mode 100644
index 0000000..1663b5f9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/hsl-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/hsla-color-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/hsla-color-expected.png
new file mode 100644
index 0000000..83ce1f9
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/hsla-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/ignore-empty-focus-ring-rects-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/ignore-empty-focus-ring-rects-expected.png
new file mode 100644
index 0000000..9e96fb7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/ignore-empty-focus-ring-rects-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/import-rule-regression-11590-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/import-rule-regression-11590-expected.png
new file mode 100644
index 0000000..edaef3a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/import-rule-regression-11590-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/import_with_baseurl-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/import_with_baseurl-expected.png
new file mode 100644
index 0000000..aafd448
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/import_with_baseurl-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/inline-element-line-break-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/inline-element-line-break-expected.png
new file mode 100644
index 0000000..bf0a135
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/inline-element-line-break-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/inline-properties-important-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/inline-properties-important-expected.png
new file mode 100644
index 0000000..718206e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/inline-properties-important-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/input-search-padding-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/input-search-padding-expected.png
new file mode 100644
index 0000000..f1ddefd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/input-search-padding-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalid-percentage-property-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalid-percentage-property-expected.png
new file mode 100644
index 0000000..94c2d274
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalid-percentage-property-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalid-pseudo-classes-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalid-pseudo-classes-expected.png
new file mode 100644
index 0000000..e41a5e4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalid-pseudo-classes-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalidation-errors-2-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalidation-errors-2-expected.png
new file mode 100644
index 0000000..301a2ba
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalidation-errors-2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalidation-errors-3-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalidation-errors-3-expected.png
new file mode 100644
index 0000000..7d47d688
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalidation-errors-3-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalidation-errors-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalidation-errors-expected.png
new file mode 100644
index 0000000..301a2ba
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/invalidation-errors-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/last-child-pseudo-class-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/last-child-pseudo-class-expected.png
new file mode 100644
index 0000000..7566244
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/last-child-pseudo-class-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/last-child-style-sharing-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/last-child-style-sharing-expected.png
new file mode 100644
index 0000000..626a5c7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/last-child-style-sharing-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/last-of-type-pseudo-class-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/last-of-type-pseudo-class-expected.png
new file mode 100644
index 0000000..572a63b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/last-of-type-pseudo-class-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/layerZOrderCrash-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/layerZOrderCrash-expected.png
new file mode 100644
index 0000000..e68629fb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/layerZOrderCrash-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-after-floating-div-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-after-floating-div-expected.png
new file mode 100644
index 0000000..b9aebfa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-after-floating-div-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-determined-by-primary-font-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-determined-by-primary-font-expected.png
new file mode 100644
index 0000000..5bcae5c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-determined-by-primary-font-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-expected.png
new file mode 100644
index 0000000..fc21068
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-font-order-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-font-order-expected.png
new file mode 100644
index 0000000..d36d543
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-font-order-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-negative-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-negative-expected.png
new file mode 100644
index 0000000..60ddfba
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-negative-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-overflow-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-overflow-expected.png
new file mode 100644
index 0000000..ffc5636
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-height-overflow-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-thickness-underline-strikethrough-overline-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-thickness-underline-strikethrough-overline-expected.png
new file mode 100644
index 0000000..efbf067
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/line-thickness-underline-strikethrough-overline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/linear-gradient-currentcolor-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/linear-gradient-currentcolor-expected.png
new file mode 100644
index 0000000..6b2ac06
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/linear-gradient-currentcolor-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/link-outside-head-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/link-outside-head-expected.png
new file mode 100644
index 0000000..44bac92
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/link-outside-head-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/list-outline-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/list-outline-expected.png
new file mode 100644
index 0000000..909d439
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/list-outline-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/live-cssrules-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/live-cssrules-expected.png
new file mode 100644
index 0000000..28c8c3a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/live-cssrules-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/margin-bottom-form-element-quirk-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/margin-bottom-form-element-quirk-expected.png
new file mode 100644
index 0000000..d5ba426
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/margin-bottom-form-element-quirk-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/margin-bottom-form-element-strict-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/margin-bottom-form-element-strict-expected.png
new file mode 100644
index 0000000..29346c6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/margin-bottom-form-element-strict-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/margin-top-bottom-dynamic-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/margin-top-bottom-dynamic-expected.png
new file mode 100644
index 0000000..9e82cf5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/margin-top-bottom-dynamic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/max-height-none-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/max-height-none-expected.png
new file mode 100644
index 0000000..c648c3f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/max-height-none-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/min-width-with-spanned-cell-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/min-width-with-spanned-cell-expected.png
new file mode 100644
index 0000000..a7050e6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/min-width-with-spanned-cell-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/min-width-with-spanned-cell-fixed-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/min-width-with-spanned-cell-fixed-expected.png
new file mode 100644
index 0000000..8a00acc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/min-width-with-spanned-cell-fixed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/001-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/001-expected.png
new file mode 100644
index 0000000..5896f167
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/001-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/002-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/002-expected.png
new file mode 100644
index 0000000..5896f167
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/002-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/003-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/003-expected.png
new file mode 100644
index 0000000..2b930e3b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/003-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/004-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/004-expected.png
new file mode 100644
index 0000000..97a6319
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/004-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/005-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/005-expected.png
new file mode 100644
index 0000000..9a497721b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/005-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/006-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/006-expected.png
new file mode 100644
index 0000000..ed1687b0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/006-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/007-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/007-expected.png
new file mode 100644
index 0000000..2b930e3b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/007-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-comments-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-comments-expected.png
new file mode 100644
index 0000000..559ee3a22
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-comments-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-empty-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-empty-expected.png
new file mode 100644
index 0000000..14ce7d53
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-empty-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-escapes-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-escapes-expected.png
new file mode 100644
index 0000000..a1791fa
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-escapes-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-invalid-at-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-invalid-at-expected.png
new file mode 100644
index 0000000..559ee3a22
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/namespaces/namespaces-invalid-at-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/negative-leading-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/negative-leading-expected.png
new file mode 100644
index 0000000..7ad0dc7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/negative-leading-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/negative-nth-child-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/negative-nth-child-expected.png
new file mode 100644
index 0000000..8e34e7c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/negative-nth-child-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/nested-floating-relative-position-percentages-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/nested-floating-relative-position-percentages-expected.png
new file mode 100644
index 0000000..03d3d8d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/nested-floating-relative-position-percentages-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/nested-rounded-corners-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/nested-rounded-corners-expected.png
new file mode 100644
index 0000000..0bd72527d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/nested-rounded-corners-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/non-empty-span-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/non-empty-span-expected.png
new file mode 100644
index 0000000..023c3a1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/non-empty-span-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/non-standard-checkbox-size-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/non-standard-checkbox-size-expected.png
new file mode 100644
index 0000000..6c216e7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/non-standard-checkbox-size-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/nth-child-dynamic-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/nth-child-dynamic-expected.png
new file mode 100644
index 0000000..a98d503
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/nth-child-dynamic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/object-fit-grow-landscape-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/object-fit-grow-landscape-expected.png
new file mode 100644
index 0000000..483fc6a0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/object-fit-grow-landscape-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/object-fit-grow-portrait-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/object-fit-grow-portrait-expected.png
new file mode 100644
index 0000000..45bc91e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/object-fit-grow-portrait-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/only-child-pseudo-class-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/only-child-pseudo-class-expected.png
new file mode 100644
index 0000000..14e5217
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/only-child-pseudo-class-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/only-of-type-pseudo-class-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/only-of-type-pseudo-class-expected.png
new file mode 100644
index 0000000..160b4583
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/only-of-type-pseudo-class-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/outline-auto-empty-rects-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/outline-auto-empty-rects-expected.png
new file mode 100644
index 0000000..2eaf6690
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/outline-auto-empty-rects-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/outline-auto-location-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/outline-auto-location-expected.png
new file mode 100644
index 0000000..8383674989
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/outline-auto-location-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pending-stylesheet-repaint-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pending-stylesheet-repaint-expected.png
new file mode 100644
index 0000000..2443ee6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pending-stylesheet-repaint-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pendingStylesheetFontSize-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pendingStylesheetFontSize-expected.png
new file mode 100644
index 0000000..4a1ce61
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pendingStylesheetFontSize-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/percent-top-relative-container-height-unspecified-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/percent-top-relative-container-height-unspecified-expected.png
new file mode 100644
index 0000000..aaac8d1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/percent-top-relative-container-height-unspecified-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/percent-top-value-with-relative-position-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/percent-top-value-with-relative-position-expected.png
new file mode 100644
index 0000000..8b693fd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/percent-top-value-with-relative-position-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/percentage-non-integer-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/percentage-non-integer-expected.png
new file mode 100644
index 0000000..1271e11
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/percentage-non-integer-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/position-negative-top-margin-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/position-negative-top-margin-expected.png
new file mode 100644
index 0000000..8bf9bc6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/position-negative-top-margin-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pseudo-element-line-break-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pseudo-element-line-break-expected.png
new file mode 100644
index 0000000..bf0a135
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pseudo-element-line-break-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pseudo-first-line-border-width-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pseudo-first-line-border-width-expected.png
new file mode 100644
index 0000000..944c62a8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/pseudo-first-line-border-width-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-dynamic-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-dynamic-expected.png
new file mode 100644
index 0000000..88c18c33
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-dynamic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-dynamic-removed-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-dynamic-removed-expected.png
new file mode 100644
index 0000000..a19a174
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-dynamic-removed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-expected.png
new file mode 100644
index 0000000..dea3616c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-multiple-descendant-blocks-dynamic-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-multiple-descendant-blocks-dynamic-expected.png
new file mode 100644
index 0000000..647ec9c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-nested-with-inline-parent-multiple-descendant-blocks-dynamic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-and-parent-dynamic-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-and-parent-dynamic-expected.png
new file mode 100644
index 0000000..4a2fd3cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-and-parent-dynamic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-dynamic-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-dynamic-expected.png
new file mode 100644
index 0000000..4a2fd3cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-dynamic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-dynamic-removed-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-dynamic-removed-expected.png
new file mode 100644
index 0000000..69009bf
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-dynamic-removed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-expected.png
new file mode 100644
index 0000000..4a2fd3cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-ancestor-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-parent-dynamic-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-parent-dynamic-expected.png
new file mode 100644
index 0000000..4a2fd3cb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-parent-dynamic-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-parent-dynamic-removed-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-parent-dynamic-removed-expected.png
new file mode 100644
index 0000000..869ef05
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-parent-dynamic-removed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-parent-keeps-style-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-parent-keeps-style-expected.png
new file mode 100644
index 0000000..185f3ce
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/relative-positioned-block-with-inline-parent-keeps-style-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rem-calc-dynamic-scaling-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rem-calc-dynamic-scaling-expected.png
new file mode 100644
index 0000000..40ce523d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rem-calc-dynamic-scaling-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rem-dynamic-scaling-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rem-dynamic-scaling-expected.png
new file mode 100644
index 0000000..40ce523d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rem-dynamic-scaling-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rem-units-on-root-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rem-units-on-root-expected.png
new file mode 100644
index 0000000..ad6e5bc
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rem-units-on-root-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/replaced-element-implicit-size-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/replaced-element-implicit-size-expected.png
new file mode 100644
index 0000000..05bc5a1
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/replaced-element-implicit-size-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/resize-corner-tracking-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/resize-corner-tracking-expected.png
new file mode 100644
index 0000000..670f086
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/resize-corner-tracking-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/resize-corner-tracking-transformed-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/resize-corner-tracking-transformed-expected.png
new file mode 100644
index 0000000..b881adb5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/resize-corner-tracking-transformed-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/resize-corner-tracking-transformed-iframe-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/resize-corner-tracking-transformed-iframe-expected.png
new file mode 100644
index 0000000..e387a5fb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/resize-corner-tracking-transformed-iframe-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rgb-float-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rgb-float-expected.png
new file mode 100644
index 0000000..6ed487f6
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rgb-float-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rtl-ordering-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rtl-ordering-expected.png
new file mode 100644
index 0000000..9e6232ce
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rtl-ordering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rtl-to-viewport-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rtl-to-viewport-expected.png
new file mode 100644
index 0000000..0e3eef8
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/rtl-to-viewport-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/selector-set-attribute-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/selector-set-attribute-expected.png
new file mode 100644
index 0000000..ca05e9e5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/selector-set-attribute-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/shadow-multiple-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/shadow-multiple-expected.png
new file mode 100644
index 0000000..5bcc19f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/shadow-multiple-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/simple-selector-chain-parsing-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/simple-selector-chain-parsing-expected.png
new file mode 100644
index 0000000..c80fad10
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/simple-selector-chain-parsing-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/style-outside-head-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/style-outside-head-expected.png
new file mode 100644
index 0000000..44bac92
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/style-outside-head-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/style-parsed-outside-head-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/style-parsed-outside-head-expected.png
new file mode 100644
index 0000000..a2c4413
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/style-parsed-outside-head-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/style-tag-display-none-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/style-tag-display-none-expected.png
new file mode 100644
index 0000000..0ad21d1d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/style-tag-display-none-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-rules-attribute-groups-with-frame-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-rules-attribute-groups-with-frame-expected.png
new file mode 100644
index 0000000..2966161f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-rules-attribute-groups-with-frame-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-rules-attribute-with-frame1-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-rules-attribute-with-frame1-expected.png
new file mode 100644
index 0000000..c2cd189
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-rules-attribute-with-frame1-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-rules-attribute-with-frame2-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-rules-attribute-with-frame2-expected.png
new file mode 100644
index 0000000..295b353
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-rules-attribute-with-frame2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-text-align-quirk-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-text-align-quirk-expected.png
new file mode 100644
index 0000000..ecf9768
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-text-align-quirk-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-text-align-strict-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-text-align-strict-expected.png
new file mode 100644
index 0000000..8f419b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/table-text-align-strict-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-align-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-align-expected.png
new file mode 100644
index 0000000..a2a48b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-align-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-bidi-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-bidi-expected.png
new file mode 100644
index 0000000..462ca370
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-bidi-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-block-with-border-and-padding-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-block-with-border-and-padding-expected.png
new file mode 100644
index 0000000..49458c2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-block-with-border-and-padding-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-expected.png
new file mode 100644
index 0000000..101c7f13
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-multiple-shadows-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-multiple-shadows-expected.png
new file mode 100644
index 0000000..b246d7d
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-multiple-shadows-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-shadow-alpha-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-shadow-alpha-expected.png
new file mode 100644
index 0000000..c10cdbe
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-shadow-alpha-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-strict-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-strict-expected.png
new file mode 100644
index 0000000..101c7f13
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-strict-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-center-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-center-expected.png
new file mode 100644
index 0000000..4b1a57c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-center-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-justify-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-justify-expected.png
new file mode 100644
index 0000000..deac1e2a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-justify-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-left-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-left-expected.png
new file mode 100644
index 0000000..f0e25d95
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-left-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-right-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-right-expected.png
new file mode 100644
index 0000000..e6916bda
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-ellipsis-text-align-right-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-input-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-input-expected.png
new file mode 100644
index 0000000..f11c88a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-overflow-input-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-rendering-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-rendering-expected.png
new file mode 100644
index 0000000..febfda03
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-rendering-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-security-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-security-expected.png
new file mode 100644
index 0000000..3cc4d1f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/text-security-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/textCapitalizeEdgeCases-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/textCapitalizeEdgeCases-expected.png
new file mode 100644
index 0000000..cf4a489
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/textCapitalizeEdgeCases-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/transform-default-parameter-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/transform-default-parameter-expected.png
new file mode 100644
index 0000000..c6e0c44
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/transform-default-parameter-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/transformed-mask-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/transformed-mask-expected.png
new file mode 100644
index 0000000..84147d07
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/transformed-mask-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/transition-color-unspecified-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/transition-color-unspecified-expected.png
new file mode 100644
index 0000000..626a5c7
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/transition-color-unspecified-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/universal-hover-quirk-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/universal-hover-quirk-expected.png
new file mode 100644
index 0000000..4463182
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/universal-hover-quirk-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-align-lengths-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-align-lengths-expected.png
new file mode 100644
index 0000000..34de7b6c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-align-lengths-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-center-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-center-expected.png
new file mode 100644
index 0000000..d8ca1f0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-center-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-justify-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-justify-expected.png
new file mode 100644
index 0000000..d8ca1f0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-justify-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-left-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-left-expected.png
new file mode 100644
index 0000000..d8ca1f0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-left-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-right-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-right-expected.png
new file mode 100644
index 0000000..d8ca1f0
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/vertical-text-overflow-ellipsis-text-align-right-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/visibility-hit-test-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/visibility-hit-test-expected.png
new file mode 100644
index 0000000..f9bda0e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/visibility-hit-test-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/word-space-extra-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/word-space-extra-expected.png
new file mode 100644
index 0000000..e28ba90
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/word-space-extra-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/zoom-font-size-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/zoom-font-size-expected.png
new file mode 100644
index 0000000..1e9d4b56
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/css/zoom-font-size-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/018-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/018-expected.png
new file mode 100644
index 0000000..52e9c21
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/018-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/018b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/018b-expected.png
new file mode 100644
index 0000000..03affcb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/018b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/019-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/019-expected.png
new file mode 100644
index 0000000..9fa3e97c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/019-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/020-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/020-expected.png
new file mode 100644
index 0000000..9c4e3351
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/020-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/021-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/021-expected.png
new file mode 100644
index 0000000..b5ef255b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/021-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/021b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/021b-expected.png
new file mode 100644
index 0000000..5f86f01
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/021b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/027-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/027-expected.png
new file mode 100644
index 0000000..af816348
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/027-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/032-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/032-expected.png
new file mode 100644
index 0000000..5ec9d225
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/032-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/034-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/034-expected.png
new file mode 100644
index 0000000..d6378f2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/034-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/038-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/038-expected.png
new file mode 100644
index 0000000..6a7745a2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/038-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/039-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/039-expected.png
new file mode 100644
index 0000000..980e5b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/039-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/039b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/039b-expected.png
new file mode 100644
index 0000000..980e5b5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/039b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/040-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/040-expected.png
new file mode 100644
index 0000000..bb1c8fb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/040-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/041-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/041-expected.png
new file mode 100644
index 0000000..9c484676
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/041-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/042-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/042-expected.png
new file mode 100644
index 0000000..0fd3b5e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/042-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/043-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/043-expected.png
new file mode 100644
index 0000000..f062c24
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/043-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/043b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/043b-expected.png
new file mode 100644
index 0000000..52fa444
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/043b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044-expected.png
new file mode 100644
index 0000000..86206a5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044b-expected.png
new file mode 100644
index 0000000..e14ec3c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044c-expected.png
new file mode 100644
index 0000000..ec51a19
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044d-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044d-expected.png
new file mode 100644
index 0000000..f84a65f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/044d-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/045-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/045-expected.png
new file mode 100644
index 0000000..2fa08dd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/045-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/045b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/045b-expected.png
new file mode 100644
index 0000000..4f884b2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/045b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/045c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/045c-expected.png
new file mode 100644
index 0000000..ec51a19
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/045c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/046-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/046-expected.png
new file mode 100644
index 0000000..91b59826
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/046-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/054-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/054-expected.png
new file mode 100644
index 0000000..3491b818
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/054-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/056-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/056-expected.png
new file mode 100644
index 0000000..3491b818
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/056-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/058-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/058-expected.png
new file mode 100644
index 0000000..1af6bbb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/058-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/059-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/059-expected.png
new file mode 100644
index 0000000..3491b818
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/059-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/060-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/060-expected.png
new file mode 100644
index 0000000..3491b818
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/060-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/061-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/061-expected.png
new file mode 100644
index 0000000..7f51d9b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/061-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/062-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/062-expected.png
new file mode 100644
index 0000000..90cfdd3c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/062-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/063-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/063-expected.png
new file mode 100644
index 0000000..9fa5e20
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/063-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/064-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/064-expected.png
new file mode 100644
index 0000000..8c2521ee
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/064-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/065-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/065-expected.png
new file mode 100644
index 0000000..d3ffca80
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/065-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/066-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/066-expected.png
new file mode 100644
index 0000000..b5ef255b
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/066-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/066b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/066b-expected.png
new file mode 100644
index 0000000..5f86f01
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/066b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/072-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/072-expected.png
new file mode 100644
index 0000000..f9e0df4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/072-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/072b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/072b-expected.png
new file mode 100644
index 0000000..f9e0df4
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/072b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/077-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/077-expected.png
new file mode 100644
index 0000000..078302f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/077-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/077b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/077b-expected.png
new file mode 100644
index 0000000..078302f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/077b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/078b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/078b-expected.png
new file mode 100644
index 0000000..ef6e7a5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/078b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/083-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/083-expected.png
new file mode 100644
index 0000000..59e1014
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/083-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/087b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/087b-expected.png
new file mode 100644
index 0000000..2e5b12e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/087b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/088b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/088b-expected.png
new file mode 100644
index 0000000..4618845
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/088b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/089-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/089-expected.png
new file mode 100644
index 0000000..60cf53dd
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/089-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/090b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/090b-expected.png
new file mode 100644
index 0000000..2e5b12e
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/090b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/154-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/154-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/154-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155a-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155b-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155c-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155d-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155d-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/155d-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/156b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/156b-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/156b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/157-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/157-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/157-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/158-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/158-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/158-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/159-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/159-expected.png
new file mode 100644
index 0000000..1399249
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/159-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/160-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/160-expected.png
new file mode 100644
index 0000000..d1b01f65
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/160-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/166-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/166-expected.png
new file mode 100644
index 0000000..f1c3721
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/166-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/166a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/166a-expected.png
new file mode 100644
index 0000000..9ad17a4f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/166a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/167-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/167-expected.png
new file mode 100644
index 0000000..663c421
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/167-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/167a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/167a-expected.png
new file mode 100644
index 0000000..663c421
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/167a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/168-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/168-expected.png
new file mode 100644
index 0000000..9e20210
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/168-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/168a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/168a-expected.png
new file mode 100644
index 0000000..9e20210
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/168a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/169-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/169-expected.png
new file mode 100644
index 0000000..9e20210
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/169-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/169a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/169a-expected.png
new file mode 100644
index 0000000..9e20210
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/169a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170a-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170b-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170c-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170d-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170d-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/170d-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/175a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/175a-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/175a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/175b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/175b-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/175b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/175c-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/175c-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/175c-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/177a-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/177a-expected.png
new file mode 100644
index 0000000..2c7ec18
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/177a-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/177b-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/177b-expected.png
new file mode 100644
index 0000000..abbef71
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/177b-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-inheritance-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-inheritance-expected.png
new file mode 100644
index 0000000..1f9ce8a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-inheritance-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-inheritance2-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-inheritance2-expected.png
new file mode 100644
index 0000000..1f9ce8a
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-inheritance2-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-vs-xml-lang-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-vs-xml-lang-expected.png
new file mode 100644
index 0000000..8d4f231
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-vs-xml-lang-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-vs-xml-lang-xhtml-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-vs-xml-lang-xhtml-expected.png
new file mode 100644
index 0000000..5a5c6e58
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/lang-vs-xml-lang-xhtml-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/nondeterministic-combinators-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/nondeterministic-combinators-expected.png
new file mode 100644
index 0000000..66fddc5
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/nondeterministic-combinators-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/unqualified-hover-quirks-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/unqualified-hover-quirks-expected.png
new file mode 100644
index 0000000..2e75be2
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/unqualified-hover-quirks-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/unqualified-hover-strict-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/unqualified-hover-strict-expected.png
new file mode 100644
index 0000000..e0b741c
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/unqualified-hover-strict-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/visited-descendant-expected.png b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/visited-descendant-expected.png
new file mode 100644
index 0000000..79c89962
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/force-device-scale-factor=1.5/fast/selectors/visited-descendant-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/html/infrastructure/fallback_base_url-expected.txt b/third_party/blink/web_tests/html/infrastructure/fallback_base_url-expected.txt
deleted file mode 100644
index 06c17e14..0000000
--- a/third_party/blink/web_tests/html/infrastructure/fallback_base_url-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL The fallback base URL of a srcdoc document should be the document base URL of the document's browsing context's browsing context container's document even after the srcdoc document lost its browsing context. assert_not_equals: after detaching got disallowed value "about:srcdoc"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin-expected.txt b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin-expected.txt
index 646aff2bc..6cde015 100644
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin-expected.txt
+++ b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin-expected.txt
@@ -1,10 +1,10 @@
 CONSOLE WARNING: line 2: Application Cache API manifest selection is deprecated and will be removed in M85, around August 2020. See https://www.chromestatus.com/features/6192449487634432 for more details.
-CONSOLE WARNING: line 2: Application Cache was previously restricted to secure origins only from M70 on but now secure origin use is deprecated and will be removed in M82.  Please shift your use case over to Service Workers.
-CONSOLE WARNING: line 21: getCurrentPosition() and watchPosition() no longer work on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.
+CONSOLE WARNING: line 20: getCurrentPosition() and watchPosition() no longer work on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.
 This is a testharness.js-based test.
 PASS getCurrentPosition
 PASS watchPosition
 PASS Media devices properties
 PASS requestMediaKeySystemAccess
+PASS applicationCache
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin.html b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin.html
index 18b2b1c..9bdc38a 100644
--- a/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin.html
+++ b/third_party/blink/web_tests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin.html
@@ -1,12 +1,11 @@
-<!DOCTYPE html>
+<!doctype html>
 <html manifest="/security/powerfulFeatureRestrictions/resources/simple.manifest">
 <head>
 <title>Old Powerful Features on an Insecure Origin</title>
-</head>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/resources/get-host-info.js"></script>
-
+</head>
 <body>
 <div id="target"></div>
 <script>
@@ -45,6 +44,10 @@
     test(function() {
       assert_false('requestMediaKeySystemAccess' in navigator);
     }, 'requestMediaKeySystemAccess');
+
+    test(function() {
+      assert_false('applicationCache' in window);
+    }, 'applicationCache');
 }
 </script>
 </body>
diff --git a/third_party/blink/web_tests/paint/invalidation/clip/clip-path-constant-repaint-expected.txt b/third_party/blink/web_tests/paint/invalidation/clip/clip-path-constant-repaint-expected.txt
index 2eae1a16..5c538824 100644
--- a/third_party/blink/web_tests/paint/invalidation/clip/clip-path-constant-repaint-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/clip/clip-path-constant-repaint-expected.txt
@@ -11,11 +11,6 @@
       "bounds": [800, 300],
       "backgroundColor": "#FF0000E6",
       "transform": 2
-    },
-    {
-      "name": "Mask Layer",
-      "bounds": [800, 300],
-      "transform": 2
     }
   ],
   "transforms": [
diff --git a/third_party/blink/web_tests/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt b/third_party/blink/web_tests/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt
index 1f1d520..a4c7817 100644
--- a/third_party/blink/web_tests/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/clip/clip-path-in-mask-layer-expected.txt
@@ -14,14 +14,6 @@
         [0, 0, 200, 200]
       ],
       "transform": 1
-    },
-    {
-      "name": "Mask Layer",
-      "bounds": [200, 200],
-      "invalidations": [
-        [0, 0, 200, 200]
-      ],
-      "transform": 1
     }
   ],
   "transforms": [
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt
deleted file mode 100644
index 6f018c0..0000000
--- a/third_party/blink/web_tests/platform/linux/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS Alignment on the baseline with different and large script heights
-FAIL Tall subscripts/superscripts are not placed too high/low assert_less_than: mmultiscripts: postsupscript is above the bottom of the base expected a number less than 184.671875 but got 434.671875
-FAIL No collisions for tall subscripts and superscripts assert_greater_than: mmultiscripts: presubscript is below the presuperscript expected a number greater than 684.671875 but got 434.671875
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox-expected.txt
deleted file mode 100644
index 4a8b751..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL Flex assert_equals: height expected "18px" but got "162px"
-FAIL Inline flex assert_equals: height expected "18px" but got "162px"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt
deleted file mode 100644
index 0ccacb1..0000000
--- a/third_party/blink/web_tests/platform/mac/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS Alignment on the baseline with different and large script heights
-FAIL Tall subscripts/superscripts are not placed too high/low assert_less_than: mmultiscripts: postsupscript is above the bottom of the base expected a number less than 184.578125 but got 434.578125
-FAIL No collisions for tall subscripts and superscripts assert_greater_than: mmultiscripts: presubscript is below the presuperscript expected a number greater than 684.578125 but got 434.578125
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox-expected.txt
deleted file mode 100644
index 357f0014..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-flexbox-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL Flex assert_equals: height expected "20px" but got "180px"
-FAIL Inline flex assert_equals: height expected "20px" but got "180px"
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt
deleted file mode 100644
index ddae4c1b..0000000
--- a/third_party/blink/web_tests/platform/win/external/wpt/mathml/presentation-markup/scripts/subsup-5-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS Alignment on the baseline with different and large script heights
-FAIL Tall subscripts/superscripts are not placed too high/low assert_less_than: mmultiscripts: postsupscript is above the bottom of the base expected a number less than 184.1875 but got 434.1875
-FAIL No collisions for tall subscripts and superscripts assert_greater_than: mmultiscripts: presubscript is below the presuperscript expected a number greater than 684.1875 but got 434.1875
-Harness: the test ran to completion.
-
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index c97b2b2..0aa6923 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-2-23-ga44347475
-Revision: a4434747558d872c55e55ce428019a8e15d222dc
+Version: VER-2-10-2-26-g3bb512bc9
+Revision: 3bb512bc9f621e1329927292d9ee7ba764549cae
 CPEPrefix: cpe:/a:freetype:freetype:2.10.1
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/r8/README.chromium b/third_party/r8/README.chromium
index 46a6963..fb574e0 100644
--- a/third_party/r8/README.chromium
+++ b/third_party/r8/README.chromium
@@ -1,7 +1,7 @@
 Name: R8
 URL: https://r8.googlesource.com/r8
 Revision: 924f28bdb1f32b7504d6813ee911ba1949be6130
-Version: 2.2.1-dev
+Version: 2.2.4-dev
 License: BSD 3-Clause
 License File: NOT_SHIPPED
 Security Critical: no
@@ -38,7 +38,7 @@
 
 # Create patches if conflicts / new patches. Change number if expecting
 # different amount of patches:
-git format-patch -6 -o $CHROMIUM_SRC/third_party/r8/patches
+git format-patch -3 -o $CHROMIUM_SRC/third_party/r8/patches
 
 # Copy over desugar config:
 cp src/library_desugar/desugar_jdk_libs.json $CHROMIUM_SRC/third_party/r8
diff --git a/third_party/r8/desugar_jdk_libs.json b/third_party/r8/desugar_jdk_libs.json
index 07765bb..049699a 100644
--- a/third_party/r8/desugar_jdk_libs.json
+++ b/third_party/r8/desugar_jdk_libs.json
@@ -1,10 +1,73 @@
 {
-  "configuration_format_version": 4,
+  "configuration_format_version": 3,
   "group_id" : "com.tools.android",
   "artifact_id" : "desugar_jdk_libs",
-  "version": "0.11.2",
+  "version": "1.0.10",
   "required_compilation_api_level": 26,
   "synthesized_library_classes_package_prefix": "j$.",
+  "common_flags": [
+    {
+      "api_level_below_or_equal": 25,
+      "wrapper_conversion": [
+        "java.time.Clock"
+      ]
+    },
+    {
+      "api_level_below_or_equal": 23,
+      "wrapper_conversion": [
+        "java.util.PrimitiveIterator$OfDouble",
+        "java.util.PrimitiveIterator$OfInt",
+        "java.util.PrimitiveIterator$OfLong",
+        "java.util.Spliterator",
+        "java.util.Spliterator$OfDouble",
+        "java.util.Spliterator$OfInt",
+        "java.util.Spliterator$OfLong",
+        "java.util.Spliterator$OfPrimitive",
+        "java.util.function.BiConsumer",
+        "java.util.function.BiFunction",
+        "java.util.function.BiPredicate",
+        "java.util.function.BinaryOperator",
+        "java.util.function.Consumer",
+        "java.util.function.DoubleBinaryOperator",
+        "java.util.function.DoubleConsumer",
+        "java.util.function.DoubleFunction",
+        "java.util.function.DoublePredicate",
+        "java.util.function.DoubleToIntFunction",
+        "java.util.function.DoubleToLongFunction",
+        "java.util.function.DoubleUnaryOperator",
+        "java.util.function.Function",
+        "java.util.function.IntBinaryOperator",
+        "java.util.function.IntConsumer",
+        "java.util.function.IntFunction",
+        "java.util.function.IntPredicate",
+        "java.util.function.IntToDoubleFunction",
+        "java.util.function.IntToLongFunction",
+        "java.util.function.IntUnaryOperator",
+        "java.util.function.LongBinaryOperator",
+        "java.util.function.LongConsumer",
+        "java.util.function.LongFunction",
+        "java.util.function.LongPredicate",
+        "java.util.function.LongToDoubleFunction",
+        "java.util.function.LongToIntFunction",
+        "java.util.function.LongUnaryOperator",
+        "java.util.function.ObjDoubleConsumer",
+        "java.util.function.ObjIntConsumer",
+        "java.util.function.ObjLongConsumer",
+        "java.util.function.Predicate",
+        "java.util.function.Supplier",
+        "java.util.function.ToDoubleFunction",
+        "java.util.function.ToIntFunction",
+        "java.util.function.ToLongFunction",
+        "java.util.function.UnaryOperator",
+        "java.util.stream.BaseStream",
+        "java.util.stream.Collector",
+        "java.util.stream.DoubleStream",
+        "java.util.stream.IntStream",
+        "java.util.stream.LongStream",
+        "java.util.stream.Stream"
+      ]
+    }
+  ],
   "library_flags": [
     {
       "api_level_below_or_equal": 25,
@@ -21,7 +84,16 @@
       },
       "retarget_lib_member": {
         "java.util.Date#toInstant": "java.util.DesugarDate",
-        "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar"
+        "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar",
+        "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone"
+      },
+      "custom_conversion": {
+        "java.time.ZonedDateTime": "java.time.TimeConversions",
+        "java.time.LocalDate": "java.time.TimeConversions",
+        "java.time.Duration": "java.time.TimeConversions",
+        "java.time.ZoneId": "java.time.TimeConversions",
+        "java.time.MonthDay": "java.time.TimeConversions",
+        "java.time.Instant": "java.time.TimeConversions"
       }
     },
     {
@@ -92,7 +164,9 @@
         "java.util.Date#from": "java.util.DesugarDate",
         "java.util.Date#toInstant": "java.util.DesugarDate",
         "java.util.GregorianCalendar#from": "java.util.DesugarGregorianCalendar",
-        "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar"
+        "java.util.GregorianCalendar#toZonedDateTime": "java.util.DesugarGregorianCalendar",
+        "java.util.TimeZone#getTimeZone": "java.util.DesugarTimeZone",
+        "java.util.TimeZone#toZoneId": "java.util.DesugarTimeZone"
       },
       "custom_conversion": {
         "java.time.ZonedDateTime": "java.time.TimeConversions",
diff --git a/third_party/r8/patches/0001-Desugaring-Make-all-lambdas-stateless-fix-naming-sch.patch b/third_party/r8/patches/0001-Desugaring-Make-all-lambdas-stateless-fix-naming-sch.patch
index 7014469..bb63e800 100644
--- a/third_party/r8/patches/0001-Desugaring-Make-all-lambdas-stateless-fix-naming-sch.patch
+++ b/third_party/r8/patches/0001-Desugaring-Make-all-lambdas-stateless-fix-naming-sch.patch
@@ -1,4 +1,4 @@
-From 5590ed46ec10f3f6a464c81b8f66367dbe43d0f3 Mon Sep 17 00:00:00 2001
+From 63bbf489cc29c153936a486d5e7eb382fc340ab0 Mon Sep 17 00:00:00 2001
 From: Sam Maier <smaier@chromium.org>
 Date: Tue, 19 May 2020 15:55:44 -0400
 Subject: [PATCH 1/3] Desugaring: Make all lambdas stateless & fix naming
@@ -35,5 +35,5 @@
  
    void addSynthesizedFrom(DexProgramClass clazz) {
 -- 
-2.27.0.278.ge193c7cf3a9-goog
+2.27.0.212.ge8ba1cc988-goog
 
diff --git a/third_party/r8/patches/0002-Make-class-merging-and-outlining-settable-via-comman.patch b/third_party/r8/patches/0002-Make-class-merging-and-outlining-settable-via-comman.patch
index a0a7ab8..bed94bb 100644
--- a/third_party/r8/patches/0002-Make-class-merging-and-outlining-settable-via-comman.patch
+++ b/third_party/r8/patches/0002-Make-class-merging-and-outlining-settable-via-comman.patch
@@ -1,4 +1,4 @@
-From 3986e3336101178e075d06640a888fa260b6bc87 Mon Sep 17 00:00:00 2001
+From 17b9115f5b074b3ed4869fadc90314ebb705bd25 Mon Sep 17 00:00:00 2001
 From: Sam Maier <smaier@chromium.org>
 Date: Tue, 19 May 2020 16:24:11 -0400
 Subject: [PATCH 2/3] Make class merging and outlining settable via
@@ -9,10 +9,10 @@
  1 file changed, 3 insertions(+), 3 deletions(-)
 
 diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
-index 00a213693..a831b6833 100644
+index f7353d93a..b6b35d326 100644
 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
 +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
-@@ -216,8 +216,8 @@ public class InternalOptions {
+@@ -217,8 +217,8 @@ public class InternalOptions implements GlobalKeepInfoConfiguration {
    public boolean enableFieldAssignmentTracker = true;
    public boolean enableFieldBitAccessAnalysis =
        System.getProperty("com.android.tools.r8.fieldBitAccessAnalysis") != null;
@@ -23,7 +23,7 @@
    public boolean enableArgumentRemoval = true;
    public boolean enableUnusedInterfaceRemoval = true;
    public boolean enableDevirtualization = true;
-@@ -1046,7 +1046,7 @@ public class InternalOptions {
+@@ -1067,7 +1067,7 @@ public class InternalOptions implements GlobalKeepInfoConfiguration {
      public static final String CLASS_NAME = "com.android.tools.r8.GeneratedOutlineSupport";
      public static final String METHOD_PREFIX = "outline";
  
@@ -33,5 +33,5 @@
      public int maxSize = 99;
      public int threshold = 20;
 -- 
-2.27.0.278.ge193c7cf3a9-goog
+2.27.0.212.ge8ba1cc988-goog
 
diff --git a/third_party/r8/patches/0003-Allow-access-modification-everywhere.patch b/third_party/r8/patches/0003-Allow-access-modification-everywhere.patch
index d0806db2..7a4239b 100644
--- a/third_party/r8/patches/0003-Allow-access-modification-everywhere.patch
+++ b/third_party/r8/patches/0003-Allow-access-modification-everywhere.patch
@@ -1,4 +1,4 @@
-From 445cc7889a6f470daba1a7056ea32bf9faf3e2d9 Mon Sep 17 00:00:00 2001
+From 44c33ec97d36034c0b8a85b66cc91ae87a382a11 Mon Sep 17 00:00:00 2001
 From: Andrew Grieve <agrieve@chromium.org>
 Date: Sun, 31 May 2020 22:09:27 -0400
 Subject: [PATCH 3/3] Allow access modification everywhere
@@ -7,24 +7,22 @@
 Loosening this constraint allows for better optimization, and is easier
 than adding ",allowaccessmodification" to every single -keep rule.
 ---
- .../com/android/tools/r8/shaking/AppInfoWithLiveness.java     | 4 +---
- 1 file changed, 1 insertion(+), 3 deletions(-)
+ .../java/com/android/tools/r8/shaking/AppInfoWithLiveness.java  | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
-index 87bfd9a2d..75bc46e33 100644
+index d3afad2e6..ab50f4c83 100644
 --- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
 +++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
-@@ -918,9 +918,7 @@ public class AppInfoWithLiveness extends AppInfoWithClassHierarchy
+@@ -924,7 +924,7 @@ public class AppInfoWithLiveness extends AppInfoWithClassHierarchy
  
    public boolean isAccessModificationAllowed(DexReference reference) {
      assert options().getProguardConfiguration().isAccessModificationAllowed();
--    return keepInfo
--        .getInfo(reference, this)
--        .isAccessModificationAllowed(options().getProguardConfiguration());
+-    return keepInfo.getInfo(reference, this).isAccessModificationAllowed(options());
 +    return true;
    }
  
    public boolean isPinned(DexReference reference) {
 -- 
-2.27.0.278.ge193c7cf3a9-goog
+2.27.0.212.ge8ba1cc988-goog
 
diff --git a/third_party/subresource-filter-ruleset/README.chromium b/third_party/subresource-filter-ruleset/README.chromium
index 48f6983..8290eb4e 100644
--- a/third_party/subresource-filter-ruleset/README.chromium
+++ b/third_party/subresource-filter-ruleset/README.chromium
@@ -1,6 +1,6 @@
 Name: EasyList
 URL: https://easylist.to/easylist/easylist.txt
-Version: 202004031720
+Version: 202006221619
 License: Creative Commons Attribution-ShareAlike 3.0 Unported
 License File: NOT_SHIPPED
 Security Critical: no
diff --git a/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1 b/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
index 91e6f1a..8b18c33 100644
--- a/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
+++ b/third_party/subresource-filter-ruleset/data/UnindexedRules.sha1
@@ -1 +1 @@
-108d49fc2d097b304b22e7bf620eb0be1ae20aa9
\ No newline at end of file
+9e1d963efc9c074940dbcf6199617c84df223dbb
\ No newline at end of file
diff --git a/tools/directory_metadata/directory_metadata.proto b/tools/directory_metadata/directory_metadata.proto
index 540fa3c..07be50b 100644
--- a/tools/directory_metadata/directory_metadata.proto
+++ b/tools/directory_metadata/directory_metadata.proto
@@ -14,6 +14,8 @@
   string team_email = 2;
   // The code in this directory is specific to this OS.
   OS os = 3;
+  // Whether wpt-importer should notify the team about new failures.
+  bool wpt_notify = 4;
   // Reserved for metadata information for third-party code. See
   // https://opensource.google/docs/thirdparty/metadata/
   reserved 13;
diff --git a/tools/directory_metadata/directory_metadata_pb2.py b/tools/directory_metadata/directory_metadata_pb2.py
index 1c34d077..3847d2d 100644
--- a/tools/directory_metadata/directory_metadata_pb2.py
+++ b/tools/directory_metadata/directory_metadata_pb2.py
@@ -20,7 +20,7 @@
   package='',
   syntax='proto3',
   serialized_options=None,
-  serialized_pb=_b('\n\x18\x64irectory_metadata.proto\"_\n\x08Metadata\x12\x1b\n\x08monorail\x18\x01 \x01(\x0b\x32\t.Monorail\x12\x12\n\nteam_email\x18\x02 \x01(\t\x12\x0f\n\x02os\x18\x03 \x01(\x0e\x32\x03.OSJ\x04\x08\r\x10\x0eR\x0bthird_party\".\n\x08Monorail\x12\x0f\n\x07project\x18\x01 \x01(\t\x12\x11\n\tcomponent\x18\x02 \x01(\t*h\n\x02OS\x12\x12\n\x0eOS_UNSPECIFIED\x10\x00\x12\t\n\x05LINUX\x10\x01\x12\x0b\n\x07WINDOWS\x10\x02\x12\x07\n\x03MAC\x10\x03\x12\x0b\n\x07\x41NDROID\x10\x04\x12\x07\n\x03IOS\x10\x05\x12\n\n\x06\x43HROME\x10\x06\x12\x0b\n\x07\x46UCHSIA\x10\x07\x62\x06proto3')
+  serialized_pb=_b('\n\x18\x64irectory_metadata.proto\"s\n\x08Metadata\x12\x1b\n\x08monorail\x18\x01 \x01(\x0b\x32\t.Monorail\x12\x12\n\nteam_email\x18\x02 \x01(\t\x12\x0f\n\x02os\x18\x03 \x01(\x0e\x32\x03.OS\x12\x12\n\nwpt_notify\x18\x04 \x01(\x08J\x04\x08\r\x10\x0eR\x0bthird_party\".\n\x08Monorail\x12\x0f\n\x07project\x18\x01 \x01(\t\x12\x11\n\tcomponent\x18\x02 \x01(\t*}\n\x02OS\x12\x12\n\x0eOS_UNSPECIFIED\x10\x00\x12\x0c\n\x08OS_LINUX\x10\x01\x12\x0e\n\nOS_WINDOWS\x10\x02\x12\n\n\x06OS_MAC\x10\x03\x12\x0e\n\nOS_ANDROID\x10\x04\x12\n\n\x06OS_IOS\x10\x05\x12\r\n\tOS_CHROME\x10\x06\x12\x0e\n\nOS_FUCHSIA\x10\x07\x62\x06proto3')
 )
 
 _OS = _descriptor.EnumDescriptor(
@@ -34,50 +34,50 @@
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='LINUX', index=1, number=1,
+      name='OS_LINUX', index=1, number=1,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='WINDOWS', index=2, number=2,
+      name='OS_WINDOWS', index=2, number=2,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='MAC', index=3, number=3,
+      name='OS_MAC', index=3, number=3,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='ANDROID', index=4, number=4,
+      name='OS_ANDROID', index=4, number=4,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='IOS', index=5, number=5,
+      name='OS_IOS', index=5, number=5,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='CHROME', index=6, number=6,
+      name='OS_CHROME', index=6, number=6,
       serialized_options=None,
       type=None),
     _descriptor.EnumValueDescriptor(
-      name='FUCHSIA', index=7, number=7,
+      name='OS_FUCHSIA', index=7, number=7,
       serialized_options=None,
       type=None),
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=173,
-  serialized_end=277,
+  serialized_start=193,
+  serialized_end=318,
 )
 _sym_db.RegisterEnumDescriptor(_OS)
 
 OS = enum_type_wrapper.EnumTypeWrapper(_OS)
 OS_UNSPECIFIED = 0
-LINUX = 1
-WINDOWS = 2
-MAC = 3
-ANDROID = 4
-IOS = 5
-CHROME = 6
-FUCHSIA = 7
+OS_LINUX = 1
+OS_WINDOWS = 2
+OS_MAC = 3
+OS_ANDROID = 4
+OS_IOS = 5
+OS_CHROME = 6
+OS_FUCHSIA = 7
 
 
 
@@ -109,6 +109,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR),
+    _descriptor.FieldDescriptor(
+      name='wpt_notify', full_name='Metadata.wpt_notify', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR),
   ],
   extensions=[
   ],
@@ -122,7 +129,7 @@
   oneofs=[
   ],
   serialized_start=28,
-  serialized_end=123,
+  serialized_end=143,
 )
 
 
@@ -159,8 +166,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=125,
-  serialized_end=171,
+  serialized_start=145,
+  serialized_end=191,
 )
 
 _METADATA.fields_by_name['monorail'].message_type = _MONORAIL
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 18a585a..cde2983 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -14476,6 +14476,14 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="MobileSingleScreenScreenshot">
+  <owner>jmentasti@google.com</owner>
+  <owner>seblalancette@chromium.org</owner>
+  <description>
+    The user took a screenshot of a single chrome window. iOS only.
+  </description>
+</action>
+
 <action name="MobileStackViewCloseTab">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 8f20708..e1612eb 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2308,6 +2308,7 @@
   <int value="5" label="NOT_SENT_FAILED_TO_SERIALIZE"/>
   <int value="6" label="NOT_SENT_FEATURE_NOT_ENABLED"/>
   <int value="7" label="SENT"/>
+  <int value="8" label="NOT_SENT_UNCONSENTED"/>
 </enum>
 
 <enum name="AppBannersBeforeInstallEvent">
@@ -5889,6 +5890,7 @@
   <int value="11" label="Trace upload succeeded"/>
   <int value="12" label="Startup scenario triggered"/>
   <int value="13" label="Large upload waiting to retry"/>
+  <int value="14" label="Reached code scenario triggered"/>
 </enum>
 
 <enum name="BackingStoreResults">
@@ -39814,6 +39816,8 @@
   <int value="-1696619241" label="OmniboxWrapPopupPosition:disabled"/>
   <int value="-1696366449" label="disable-permissions-bubbles"/>
   <int value="-1695774453" label="skip-extra-ash-window-positioning"/>
+  <int value="-1692967465"
+      label="ContextMenuPerformanceInfoAndRemoteHintFetching:enabled"/>
   <int value="-1692384483" label="disambiguate-autofill-server-name-types"/>
   <int value="-1692107333" label="AccessibilityCursorColor:disabled"/>
   <int value="-1691892152" label="SafeSearchUrlReporting:disabled"/>
@@ -40616,7 +40620,6 @@
   <int value="-868138290" label="CrostiniPortForwarding:disabled"/>
   <int value="-867087281" label="enable-virtual-keyboard"/>
   <int value="-866993841" label="OfflinePagesCTV2:disabled"/>
-  <int value="-865414778" label="ContextMenuPerformanceInfo:enabled"/>
   <int value="-864266073" label="cros-regions-mode"/>
   <int value="-864234985" label="UseDdljsonApi:enabled"/>
   <int value="-864232986" label="StartSurfaceAndroid:disabled"/>
@@ -42003,6 +42006,8 @@
   <int value="705407202" label="AutofillSaveCardImprovedUserConsent:disabled"/>
   <int value="705712478" label="EnablePalmOnToolTypePalm:disabled"/>
   <int value="705713283" label="EasyUnlockPromotions:disabled"/>
+  <int value="705946076"
+      label="ContextMenuPerformanceInfoAndRemoteHintFetching:disabled"/>
   <int value="706280254" label="StoragePressureEvent:enabled"/>
   <int value="709138900" label="InstantStart:enabled"/>
   <int value="709850261" label="disable-touch-editing"/>
@@ -42996,9 +43001,9 @@
   <int value="1810258949" label="DisplayLocking:enabled"/>
   <int value="1810311887" label="WebAssemblyThreads:enabled"/>
   <int value="1812368073" label="enable-new-app-list-mixer"/>
-  <int value="1812978232" label="ContextMenuPerformanceInfo:disabled"/>
   <int value="1814671708" label="disable-password-manager-reauthentication"/>
   <int value="1816174635" label="RequestUnbufferedDispatch:enabled"/>
+  <int value="1816723085" label="SchemefulSameSite:enabled"/>
   <int value="1816843861" label="ServiceWorkerServicification:enabled"/>
   <int value="1817312143" label="num-raster-threads"/>
   <int value="1818829958" label="IdentityDisc:enabled"/>
@@ -43173,6 +43178,7 @@
   <int value="1988810119" label="AutofillDropdownLayout:enabled"/>
   <int value="1989051182" label="view-passwords:enabled"/>
   <int value="1989877708" label="PostScriptPrinting:enabled"/>
+  <int value="1990528959" label="SchemefulSameSite:disabled"/>
   <int value="1990562608"
       label="LinkManagedNoticeToChromeUIManagementURL:enabled"/>
   <int value="1990670943"
@@ -52988,6 +52994,8 @@
   <int value="1" label="Password Settings"/>
   <int value="2" label="Phish Guard Dialog"/>
   <int value="3" label="Password Breach Dialog"/>
+  <int value="4" label="More passwords to fix bubble"/>
+  <int value="5" label="Unsafe state bubble"/>
 </enum>
 
 <enum name="PasswordDecryptionResult">
@@ -59706,6 +59714,7 @@
   <int value="68" label="InternalFrameLifecycleControl"/>
   <int value="69" label="MainThreadTaskQueueNonWaking"/>
   <int value="70" label="InternalFindInPage"/>
+  <int value="71" label="InternalHighPriorityLocalFrame"/>
 </enum>
 
 <enum name="RendererSchedulerTaskUseCase">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index a39672ff..c553fc7 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -26353,7 +26353,7 @@
 </histogram>
 
 <histogram name="ChromeOS.SAML.Scraping.PasswordCountAll" units="passwords"
-    expires_after="2020-07-19">
+    expires_after="2021-01-19">
   <owner>mslus@chromium.org</owner>
   <owner>emaxx@chromium.org</owner>
   <summary>
@@ -69274,13 +69274,13 @@
 </histogram>
 
 <histogram name="InputMethod.AutoCorrectLevel" enum="IMECorrectionLevel"
-    expires_after="2020-04-01">
+    expires_after="2021-04-01">
   <owner>essential-inputs-team@google.com</owner>
   <summary>The auto-correction level for suggestion engine.</summary>
 </histogram>
 
 <histogram name="InputMethod.Category" enum="InputMethodCategory"
-    expires_after="2020-04-01">
+    expires_after="2021-04-01">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The breakdown of input method usage by input method category. Recorded when
@@ -69289,7 +69289,7 @@
 </histogram>
 
 <histogram name="InputMethod.Commit.Index" units="units"
-    expires_after="2020-04-01">
+    expires_after="2021-04-01">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The suggestion index (1-based) of the suggestion list item which user
@@ -69309,14 +69309,14 @@
 </histogram>
 
 <histogram name="InputMethod.Commit.Type2" enum="IMECommitType2"
-    expires_after="M85">
+    expires_after="M95">
   <owner>shuchen@chromium.org</owner>
   <summary>
     The suggestion accuracy type which the user chooses to commit.
   </summary>
 </histogram>
 
-<histogram name="InputMethod.CommitLength" units="units" expires_after="M85">
+<histogram name="InputMethod.CommitLength" units="units" expires_after="M95">
   <owner>shuchen@chromium.org</owner>
   <summary>The number of characters committed with composition text.</summary>
 </histogram>
@@ -69383,7 +69383,7 @@
   </summary>
 </histogram>
 
-<histogram name="InputMethod.ID2" enum="InputMethodID2" expires_after="M85">
+<histogram name="InputMethod.ID2" enum="InputMethodID2" expires_after="M95">
   <owner>shuchen@chromium.org</owner>
   <summary>
     The breakdown of input method usage by input method IDs. Recorded when the
@@ -69392,7 +69392,7 @@
 </histogram>
 
 <histogram name="InputMethod.ImeMenu.ActivationChanged"
-    enum="BooleanActivation" expires_after="M85">
+    enum="BooleanActivation" expires_after="M95">
   <owner>azurewei@chromium.org</owner>
   <owner>shuchen@chromium.org</owner>
   <summary>
@@ -69401,7 +69401,7 @@
 </histogram>
 
 <histogram name="InputMethod.ImeMenu.EmojiHandwritingVoiceButton"
-    enum="ImeMenuButtonType" expires_after="M85">
+    enum="ImeMenuButtonType" expires_after="M95">
   <owner>azurewei@chromium.org</owner>
   <owner>shuchen@chromium.org</owner>
   <summary>
@@ -69411,7 +69411,7 @@
 </histogram>
 
 <histogram name="InputMethod.ImeSwitch" enum="IMESwitchType"
-    expires_after="M85">
+    expires_after="M95">
   <owner>shuchen@chromium.org</owner>
   <summary>The trigger type of input method switches by user.</summary>
 </histogram>
@@ -69451,7 +69451,7 @@
 </histogram>
 
 <histogram name="InputMethod.Mojo.Extension.Event" enum="IMEExtensionMojoEvent"
-    expires_after="2020-04-01">
+    expires_after="2021-04-01">
   <owner>essential-inputs-team@google.com</owner>
   <summary>The events of Mojo service in the IME Extension.</summary>
 </histogram>
@@ -69477,7 +69477,7 @@
 </histogram>
 
 <histogram name="InputMethod.PkCommit.Index" units="units"
-    expires_after="2020-04-01">
+    expires_after="2021-04-01">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The suggestion index (1-based) of the suggestion list item which user
@@ -69486,7 +69486,7 @@
 </histogram>
 
 <histogram name="InputMethod.PkCommit.Type" enum="IMECommitType2"
-    expires_after="M85">
+    expires_after="M95">
   <owner>shuchen@chromium.org</owner>
   <summary>
     The suggestion accuracy type which the user chooses to commit for physical
@@ -69504,7 +69504,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.BackspaceCount" units="units"
-    expires_after="M85">
+    expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The number of times the backspace key was pressed on the virtual keyboard,
@@ -69514,7 +69514,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.BackspaceOnLayout"
-    enum="IMEVKLayout" expires_after="M85">
+    enum="IMEVKLayout" expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The layout type of the virtual keyboard, recorded when backspace is pressed.
@@ -69522,7 +69522,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.BackwardsMovesPerSwipe"
-    units="moves" expires_after="M85">
+    units="moves" expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     Chrome OS histogram that counts the number of times the cursor was moved to
@@ -69534,7 +69534,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.CharactersBetweenBackspaces"
-    units="units" expires_after="M85">
+    units="units" expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     Counts the length of text typed by the virtual keyboard between each
@@ -69544,7 +69544,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.CharactersCommitted" units="units"
-    expires_after="M85">
+    expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The total number of characters committed. Recorded when the virtual keyboard
@@ -69553,7 +69553,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.ContainerBehavior"
-    enum="VirtualKeyboardContainerType" expires_after="M85">
+    enum="VirtualKeyboardContainerType" expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     Chrome OS histogram that counts the number of times each virtual keyboard
@@ -69563,7 +69563,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.DecoderEvent"
-    enum="InputMethodDecoderEvent" expires_after="2020-02-01">
+    enum="InputMethodDecoderEvent" expires_after="2021-02-01">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     Chrome OS histogram that counts events from the decoder triggered by the
@@ -69572,7 +69572,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.Duration" units="seconds"
-    expires_after="M85">
+    expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>How long the virtual keyboard was visible.</summary>
 </histogram>
@@ -69585,13 +69585,13 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.ErrorType"
-    enum="VirtualKeyboardErrorTypeHashes" expires_after="2020-02-01">
+    enum="VirtualKeyboardErrorTypeHashes" expires_after="2021-02-01">
   <owner>essential-inputs-team@google.com</owner>
   <summary>Errors from the virtual keyboard extension</summary>
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.FocusedByStylus" enum="Boolean"
-    expires_after="M85">
+    expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     Whether an input field was focused by a stylus or not. Recorded when an
@@ -69600,13 +69600,13 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.GestureTypingEvent"
-    enum="IMEGestureTypingEvent" expires_after="M85">
+    enum="IMEGestureTypingEvent" expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>Text input events related to gesture typing.</summary>
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.InitLatency" units="ms"
-    expires_after="M85">
+    expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The on-screen keyboard initialization latency in milliseconds.
@@ -69625,7 +69625,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.Layout" enum="IMEVKLayout"
-    expires_after="M85">
+    expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The layout of the on-screen keyboard. Logged when the specific layout is
@@ -69634,7 +69634,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.LayoutSwitch" units="units"
-    expires_after="M85">
+    expires_after="M95">
   <owner>dvallet@google.com</owner>
   <owner>essential-inputs-team@google.com</owner>
   <summary>
@@ -69644,7 +69644,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.MovesPerSwipe" units="moves"
-    expires_after="M85">
+    expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     Chrome OS histogram that counts the number of times the cursor was moved to
@@ -69656,7 +69656,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.PreferredLayoutForStylus"
-    enum="IMEVKLayout" expires_after="M85">
+    enum="IMEVKLayout" expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The layout of the virtual keyboard that is shown when the user focuses on an
@@ -69687,7 +69687,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.SwitchMode" enum="IMEVKMode"
-    expires_after="2020-06-30">
+    expires_after="2021-06-30">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The count of user actions to switch keyboard mode (floating, docked).
@@ -69696,7 +69696,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.TapCount" units="units"
-    expires_after="M85">
+    expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The number of times the virtual keyboard was tapped while the virtual
@@ -69705,7 +69705,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.WordsDeletedPerSwipe"
-    units="words" expires_after="M85">
+    units="words" expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     Chrome OS histogram that tracks the total number of words that were deleted
@@ -69717,7 +69717,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.WordsPerMinute" units="units"
-    expires_after="M85">
+    expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     The number of words typed per minute. Recorded when the virtual keyboard is
@@ -69726,7 +69726,7 @@
 </histogram>
 
 <histogram name="InputMethod.VirtualKeyboard.WordsRestoredPerSwipe"
-    units="words" expires_after="M85">
+    units="words" expires_after="M95">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
     Chrome OS histogram that tracks the total number of words that were restored
@@ -123576,7 +123576,7 @@
 </histogram>
 
 <histogram name="PasswordManager.BulkCheck.PasswordCheckReferrer"
-    enum="PasswordCheckReferrer" expires_after="M86">
+    enum="PasswordCheckReferrer" expires_after="M88">
   <owner>jdoerrie@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -144612,8 +144612,9 @@
 </histogram>
 
 <histogram name="SafeBrowsing.AndroidTelemetry.ApkDownload.IncompleteReason"
-    enum="ApkDownloadTelemetryIncompleteReason" expires_after="M85">
-  <owner>vakh@chromium.org</owner>
+    enum="ApkDownloadTelemetryIncompleteReason" expires_after="2021-07-01">
+  <owner>xinghuilu@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
     Records if the telemetry ping sent for APK download contained a full
     referrer chain, or if there was an error collecting the referrer chain.
@@ -144623,8 +144624,9 @@
 </histogram>
 
 <histogram name="SafeBrowsing.AndroidTelemetry.ApkDownload.Outcome"
-    enum="ApkDownloadTelemetryOutcome" expires_after="M85">
-  <owner>vakh@chromium.org</owner>
+    enum="ApkDownloadTelemetryOutcome" expires_after="2021-07-01">
+  <owner>xinghuilu@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
     Records whether a telemetry ping for APK download was sent, or if not, then
     why not. Logged each time a user downloads an APK file on Android.
@@ -166594,7 +166596,7 @@
 </histogram>
 
 <histogram name="StackSamplingProfiler.MetadataSlotsUsed" units="counts"
-    expires_after="2020-07-12">
+    expires_after="2021-01-12">
   <owner>charliea@chromium.org</owner>
   <owner>wittman@chromium.org</owner>
   <summary>
@@ -197710,6 +197712,7 @@
       name="CompositorLatency.DroppedFrame.MainThreadAnimation"/>
   <affected-histogram name="CompositorLatency.DroppedFrame.PinchZoom"/>
   <affected-histogram name="CompositorLatency.DroppedFrame.RAF"/>
+  <affected-histogram name="CompositorLatency.DroppedFrame.ScrollbarScroll"/>
   <affected-histogram name="CompositorLatency.DroppedFrame.TouchScroll"/>
   <affected-histogram name="CompositorLatency.DroppedFrame.WheelScroll"/>
   <affected-histogram name="CompositorLatency.MainThreadAnimation"/>
@@ -197720,6 +197723,8 @@
       name="CompositorLatency.MissedDeadlineFrame.MainThreadAnimation"/>
   <affected-histogram name="CompositorLatency.MissedDeadlineFrame.PinchZoom"/>
   <affected-histogram name="CompositorLatency.MissedDeadlineFrame.RAF"/>
+  <affected-histogram
+      name="CompositorLatency.MissedDeadlineFrame.ScrollbarScroll"/>
   <affected-histogram name="CompositorLatency.MissedDeadlineFrame.TouchScroll"/>
   <affected-histogram name="CompositorLatency.MissedDeadlineFrame.WheelScroll"/>
   <affected-histogram name="CompositorLatency.MissedFrame">
@@ -197799,6 +197804,7 @@
   </affected-histogram>
   <affected-histogram name="CompositorLatency.PinchZoom"/>
   <affected-histogram name="CompositorLatency.RAF"/>
+  <affected-histogram name="CompositorLatency.ScrollbarScroll"/>
   <affected-histogram name="CompositorLatency.TouchScroll"/>
   <affected-histogram name="CompositorLatency.WheelScroll"/>
   <affected-histogram name="SingleThreadedCompositorLatency">
@@ -197965,6 +197971,8 @@
       name="CompositorLatency.CompositorOnlyFrame.MainThreadAnimation"/>
   <affected-histogram name="CompositorLatency.CompositorOnlyFrame.PinchZoom"/>
   <affected-histogram name="CompositorLatency.CompositorOnlyFrame.RAF"/>
+  <affected-histogram
+      name="CompositorLatency.CompositorOnlyFrame.ScrollbarScroll"/>
   <affected-histogram name="CompositorLatency.CompositorOnlyFrame.TouchScroll"/>
   <affected-histogram name="CompositorLatency.CompositorOnlyFrame.WheelScroll"/>
 </histogram_suffixes>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 7931dbb..0a1aff5f 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -80,6 +80,50 @@
   </metric>
 </event>
 
+<event name="Accessibility.ImageDescriptions">
+  <owner>dmazzoni@chromium.org</owner>
+  <summary>
+    Tracks automatic image descriptions provided to blind users.
+  </summary>
+  <metric name="Description" enum="Boolean">
+    <summary>
+      Whether the image description included a description.
+    </summary>
+    <aggregation>
+      <history>
+        <statistics>
+          <enumeration/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+  <metric name="ImageAlreadyHasLabel" enum="Boolean">
+    <summary>
+      Whether the image already had label text before it was augmented with an
+      additional description.
+    </summary>
+    <aggregation>
+      <history>
+        <statistics>
+          <enumeration/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+  <metric name="OCR" enum="Boolean">
+    <summary>
+      Whether the image description included OCR text.
+    </summary>
+    <aggregation>
+      <history>
+        <statistics>
+          <enumeration/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
+</event>
+
 <event name="Accessibility.Renderer">
   <owner>dmazzoni@chromium.org</owner>
   <summary>
@@ -4264,6 +4308,11 @@
       True when a rAF-driven animation was active this frame.
     </summary>
   </metric>
+  <metric name="ScrollbarScroll" enum="Boolean">
+    <summary>
+      True when a scrollbar driven interaction was active this frame.
+    </summary>
+  </metric>
   <metric name="SendBeginMainFrameToCommit">
     <summary>
       The time from when the BeginMainFrame is sent to the beginning of the
@@ -4508,6 +4557,12 @@
       animation.
     </summary>
   </metric>
+  <metric name="CompositorThread.ScrollbarScroll">
+    <summary>
+      The throughput of the compositor thread during scrollbar scroll driven
+      interactions.
+    </summary>
+  </metric>
   <metric name="CompositorThread.TouchScroll">
     <summary>
       The throughput of the compositor thread during touchscroll driven
@@ -4550,6 +4605,12 @@
       The throughput of the main thread during rAF callback driven animation.
     </summary>
   </metric>
+  <metric name="MainThread.ScrollbarScroll">
+    <summary>
+      The throughput of the main thread during scrollbar scroll driven
+      interactions.
+    </summary>
+  </metric>
   <metric name="MainThread.TouchScroll">
     <summary>
       The throughput of the main thread during touchscroll driven interactions.
@@ -4627,6 +4688,20 @@
       </history>
     </aggregation>
   </metric>
+  <metric name="SlowerThread.ScrollbarScroll">
+    <summary>
+      The worse throughput of the main and the compositor thread during
+      scrollbar driven interactions.
+    </summary>
+    <aggregation>
+      <history>
+        <index fields="profile.country"/>
+        <statistics>
+          <quantiles type="std-percentiles"/>
+        </statistics>
+      </history>
+    </aggregation>
+  </metric>
   <metric name="SlowerThread.TouchScroll">
     <summary>
       The worse throughput of the main and the compositor thread during
@@ -5211,6 +5286,18 @@
       100.
     </summary>
   </metric>
+  <metric name="NavigationStartToNavigationCommit">
+    <summary>
+      The time (in milliseconds) that elapsed between navigation start and the
+      commit finished.
+    </summary>
+  </metric>
+  <metric name="NavigationStartToOptimizationGuidePredictionArrived">
+    <summary>
+      The time (in milliseconds) that elapsed between navigation start and the
+      optimization guide prediction arriving for the navigation.
+    </summary>
+  </metric>
   <metric name="OptimizationGuidePredictionCorrectlyPredictedOrigins">
     <summary>
       The number of subresource origins that were correctly predicted by the
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index fed56d5e..65f81f7 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,8 +1,8 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "4da4355fab5741c9081a10c27c74a69723cb1379",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/350be7ea7229bf9916a236738a1c5ec232d918fc/trace_processor_shell.exe"
+            "hash": "4a151fde997372c385eaebeae539c7457ece2b73",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/3039024ba5b48681603706e86b0a8603d41b173a/trace_processor_shell.exe"
         },
         "mac": {
             "hash": "d630f2e7af61d6a9055ce69c0571d9a00088f260",
@@ -10,7 +10,7 @@
         },
         "linux": {
             "hash": "55808c185d8a9e8ca7ec7314e16d76e237b306f3",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/9c6d11136851e6d31953a3710121628d3c9e7dd8/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/3039024ba5b48681603706e86b0a8603d41b173a/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc
index 513253fc..ab584ae 100644
--- a/ui/accessibility/ax_node.cc
+++ b/ui/accessibility/ax_node.cc
@@ -356,6 +356,12 @@
 }
 
 bool AXNode::IsText() const {
+  // In Legacy Layout, a list marker has no children and is thus represented on
+  // all platforms as a leaf node that exposes the marker itself, i.e., it forms
+  // part of the AX tree's text representation. In contrast, in Layout NG, a
+  // list marker has a static text child.
+  if (data().role == ax::mojom::Role::kListMarker)
+    return !children().size();
   return ui::IsText(data().role);
 }
 
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h
index bd19909..dfeed6ed 100644
--- a/ui/accessibility/ax_position.h
+++ b/ui/accessibility/ax_position.h
@@ -645,9 +645,10 @@
 
         // 2. The current position is not whitespace only, unless it is also
         //    the first leaf text position within the document.
-        if (text_position->IsInWhiteSpace())
+        if (text_position->IsInWhiteSpace()) {
           return text_position->CreatePreviousLeafTextPosition()
               ->IsNullPosition();
+        }
 
         // 3. Either (a) the current leaf text position is the first leaf text
         //    position in the document, or (b) there are no line breaking
@@ -3040,7 +3041,7 @@
     if (AnchorUnignoredChildCount())
       return false;
 
-    // All unignored leaf nodes in the AXTree except the document and the text
+    // All unignored leaf nodes in the AXTree except document and text
     // nodes should be replaced by the embedded object character. Also, nodes
     // that only have ignored children (e.g., a button that contains only an
     // empty div) need to be treated as leaf nodes.
@@ -3087,14 +3088,12 @@
     // The first unignored ancestor is necessarily the empty object if this node
     // is the descendant of an empty object.
     AXNodeType* ancestor_node = GetLowestUnignoredAncestor();
-
     if (!ancestor_node)
       return nullptr;
 
     AXPositionInstance position = CreateTextPosition(
         tree_id_, GetAnchorID(ancestor_node), 0 /* text_offset */,
         ax::mojom::TextAffinity::kDownstream);
-
     if (position && position->IsEmptyObjectReplacedByCharacter())
       return ancestor_node;
 
diff --git a/ui/accessibility/ax_role_properties.cc b/ui/accessibility/ax_role_properties.cc
index 77bd771..60115f31 100644
--- a/ui/accessibility/ax_role_properties.cc
+++ b/ui/accessibility/ax_role_properties.cc
@@ -675,16 +675,6 @@
   }
 }
 
-bool IsTextOrLineBreak(ax::mojom::Role role) {
-  switch (role) {
-    case ax::mojom::Role::kLineBreak:
-    case ax::mojom::Role::kStaticText:
-      return true;
-    default:
-      return false;
-  }
-}
-
 bool IsText(ax::mojom::Role role) {
   switch (role) {
     case ax::mojom::Role::kInlineTextBox:
diff --git a/ui/accessibility/ax_role_properties.h b/ui/accessibility/ax_role_properties.h
index 536d275..60e8e57 100644
--- a/ui/accessibility/ax_role_properties.h
+++ b/ui/accessibility/ax_role_properties.h
@@ -161,14 +161,10 @@
 // table is not used for layout purposes.
 AX_BASE_EXPORT bool IsTableRow(ax::mojom::Role role);
 
-// Returns true if it's a text-related node e.g. static text, line break, or
-// inline text box node.
+// Returns true if the provided role is text-related, e.g., static text, line
+// break, or inline text box.
 AX_BASE_EXPORT bool IsText(ax::mojom::Role role);
 
-// Returns true if it's a text-related node e.g. a static text or line break
-// node.
-AX_BASE_EXPORT bool IsTextOrLineBreak(ax::mojom::Role role);
-
 // Returns true if the role supports expand/collapse.
 AX_BASE_EXPORT bool SupportsExpandCollapse(const ax::mojom::Role role);
 
diff --git a/ui/android/javatests/src/org/chromium/ui/test/util/RENDER_TESTS.md b/ui/android/javatests/src/org/chromium/ui/test/util/RENDER_TESTS.md
index 9af416f..1b9d1a22 100644
--- a/ui/android/javatests/src/org/chromium/ui/test/util/RENDER_TESTS.md
+++ b/ui/android/javatests/src/org/chromium/ui/test/util/RENDER_TESTS.md
@@ -78,9 +78,13 @@
 [RenderTestRule](https://cs.chromium.org/chromium/src/ui/android/javatests/src/org/chromium/ui/test/util/RenderTestRule.java)
 or [ChromeRenderTestRule](https://cs.chromium.org/chromium/src/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeRenderTestRule.java).
 
-If you want to separate your baselines from the default `android-render-tests`
-corpus in Gold, you can call `setCorpus()` on your
-`SkiaGoldBuilder` instance before calling `build()`.
+You will need to decide whether you want your test results to be public
+(viewable by anyone) or internal (only viewable by Googlers) and call
+`setCorpus()` accordingly. Public results should use the
+`Corpus.ANDROID_RENDER_TESTS_PUBLIC` corpus, while internal results should use
+the `Corpus.ANDROID_RENDER_TESTS_INTERNAL` corpus. Alternatively, you can use
+`Builder.withPublicCorpus()` as shorthand for creating a builder with the
+default public corpus.
 
 **Note:** Each instance/corpus/description combination results in needing to
 create a new Gold session under the hood, which adds ~250 ms due to extra
diff --git a/ui/android/javatests/src/org/chromium/ui/test/util/RenderTestRule.java b/ui/android/javatests/src/org/chromium/ui/test/util/RenderTestRule.java
index c60156a..fd2dd78 100644
--- a/ui/android/javatests/src/org/chromium/ui/test/util/RenderTestRule.java
+++ b/ui/android/javatests/src/org/chromium/ui/test/util/RenderTestRule.java
@@ -48,10 +48,10 @@
  * @RunWith(BaseJUnit4ClassRunner.class)
  * public class MyTest extends DummyUiActivityTestCase {
  *     @Rule
- *     public RenderTestRule mRenderTestRule = new RenderTestRule.SkiaGoldBuilder()
- *             // Optional, only necessary if you want your results to be kept in a different
- *             // corpus than the default.
- *             .setCorpus("android-render-tests-my-fancy-feature")
+ *     public RenderTestRule mRenderTestRule = new RenderTestRule.Builder()
+ *             // Required. If using ANDROID_RENDER_TESTS_PUBLIC, the Builder can be created with
+ *             // the shorthand RenderTestRule.Builder.withPublicCorpus().
+ *             .setCorpus(RenderTestRule.Corpus.ANDROID_RENDER_TESTS_PUBLIC)
  *             // Optional, only necessary once a CL lands that should invalidate previous golden
  *             // images, e.g. a UI rework.
  *             .setRevision(2)
@@ -101,26 +101,18 @@
     private String mSkiaGoldRevisionDescription;
     private boolean mFailOnUnsupportedConfigs;
 
-    @StringDef({Corpus.ANDROID_RENDER_TESTS, Corpus.ANDROID_VR_RENDER_TESTS})
+    @StringDef({Corpus.ANDROID_RENDER_TESTS_PUBLIC, Corpus.ANDROID_RENDER_TESTS_INTERNAL,
+            Corpus.ANDROID_VR_RENDER_TESTS})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Corpus {
-        // Corpus for general use.
-        String ANDROID_RENDER_TESTS = "android-render-tests";
+        // Corpus for general use and public results.
+        String ANDROID_RENDER_TESTS_PUBLIC = "android-render-tests";
+        // Corpus for general use and internal results.
+        String ANDROID_RENDER_TESTS_INTERNAL = "android-render-tests-internal";
         // Corpus for VR (virtual reality) features.
         String ANDROID_VR_RENDER_TESTS = "android-vr-render-tests";
     }
 
-    /**
-     * Default constructor, which is equivalent to using the SkiaGoldBuilder without setting any
-     * additional configurations on it.
-     *
-     * If any such configurations are desired, e.g. bumping the image revision, please switch to
-     * using the builder instead.
-     */
-    public RenderTestRule() {
-        this(0, null, null, false);
-    }
-
     // Skia Gold-specific constructor used by the builder.
     // Note that each corpus/description combination results in some additional initialization
     // on the host (~250 ms), so consider whether adding unique descriptions is necessary before
@@ -128,8 +120,11 @@
     protected RenderTestRule(int revision, @Corpus String corpus, String description,
             boolean failOnUnsupportedConfigs) {
         assert revision >= 0;
+        // Don't have a default corpus so that users explicitly specify whether
+        // they want their test results to be public or not.
+        assert corpus != null;
 
-        mSkiaGoldCorpus = (corpus == null) ? Corpus.ANDROID_RENDER_TESTS : corpus;
+        mSkiaGoldCorpus = corpus;
         mSkiaGoldRevisionDescription = description;
         mSkiaGoldRevision = revision;
         mFailOnUnsupportedConfigs = failOnUnsupportedConfigs;
@@ -201,6 +196,8 @@
         JSONObject goldKeys = new JSONObject();
         try {
             goldKeys.put("source_type", mSkiaGoldCorpus);
+            goldKeys.put("model", Build.MODEL);
+            goldKeys.put("sdk_version", String.valueOf(Build.VERSION.SDK_INT));
             if (!TextUtils.isEmpty(mSkiaGoldRevisionDescription)) {
                 goldKeys.put("revision_description", mSkiaGoldRevisionDescription);
             }
@@ -332,9 +329,9 @@
     }
 
     /**
-     * Builder to create a RenderTestRule for use with Skia Gold.
+     * Base Builder class for creating RenderTestRules and its derivatives.
      */
-    public static class SkiaGoldBuilder {
+    protected abstract static class BaseBuilder<B extends BaseBuilder<B>> {
         protected int mRevision;
         protected @Corpus String mCorpus;
         protected String mDescription;
@@ -345,25 +342,25 @@
          * be incremented anytime output changes significantly enough that previous baselines
          * should be considered invalid.
          */
-        public SkiaGoldBuilder setRevision(int revision) {
+        public B setRevision(int revision) {
             mRevision = revision;
-            return this;
+            return self();
         }
 
         /**
          * Sets the corpus in the Gold instance that images belong to.
          */
-        public SkiaGoldBuilder setCorpus(@Corpus String corpus) {
+        public B setCorpus(@Corpus String corpus) {
             mCorpus = corpus;
-            return this;
+            return self();
         }
 
         /**
          * Sets the optional description that will be shown alongside the image in the Gold web UI.
          */
-        public SkiaGoldBuilder setDescription(String description) {
+        public B setDescription(String description) {
             mDescription = description;
-            return this;
+            return self();
         }
 
         /**
@@ -372,13 +369,32 @@
          * //build/android/pylib/local/device/local_device_instrumentation_test_run.py under the
          * RENDER_TEST_MODEL_SDK_CONFIGS constant.
          */
-        public SkiaGoldBuilder setFailOnUnsupportedConfigs(boolean fail) {
+        public B setFailOnUnsupportedConfigs(boolean fail) {
             mFailOnUnsupportedConfigs = fail;
-            return this;
+            return self();
         }
 
+        protected B self() {
+            return (B) this;
+        }
+
+        public abstract RenderTestRule build();
+    }
+
+    /**
+     * Builder to create a RenderTestRule.
+     */
+    public static class Builder extends BaseBuilder<Builder> {
+        @Override
         public RenderTestRule build() {
             return new RenderTestRule(mRevision, mCorpus, mDescription, mFailOnUnsupportedConfigs);
         }
+
+        /**
+         * Creates a Builder with the default public corpus.
+         */
+        public static Builder withPublicCorpus() {
+            return new Builder().setCorpus(Corpus.ANDROID_RENDER_TESTS_PUBLIC);
+        }
     }
 }
diff --git a/ui/base/x/test/x11_property_change_waiter.cc b/ui/base/x/test/x11_property_change_waiter.cc
index f73178ff..2e9ed8f2 100644
--- a/ui/base/x/test/x11_property_change_waiter.cc
+++ b/ui/base/x/test/x11_property_change_waiter.cc
@@ -13,6 +13,7 @@
 #include "ui/events/x/x11_window_event_manager.h"
 #include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto.h"
 
 namespace ui {
 
@@ -48,11 +49,9 @@
 }
 
 bool X11PropertyChangeWaiter::DispatchXEvent(x11::Event* x11_event) {
-  XEvent* xev = &x11_event->xlib_event();
-  if (!xev || !wait_ || xev->type != PropertyNotify ||
-      xev->xproperty.window != static_cast<uint32_t>(x_window_) ||
-      static_cast<x11::Atom>(xev->xproperty.atom) != gfx::GetAtom(property_) ||
-      ShouldKeepOnWaiting(x11_event)) {
+  auto* prop = x11_event->As<x11::PropertyNotifyEvent>();
+  if (!wait_ || !prop || prop->window != x_window_ ||
+      prop->atom != gfx::GetAtom(property_) || ShouldKeepOnWaiting(x11_event)) {
     return false;
   }
 
diff --git a/ui/base/x/x11_display_manager.cc b/ui/base/x/x11_display_manager.cc
index 2c265e58..cfbc6aa 100644
--- a/ui/base/x/x11_display_manager.cc
+++ b/ui/base/x/x11_display_manager.cc
@@ -12,6 +12,7 @@
 #include "ui/gfx/x/randr.h"
 #include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto.h"
 
 namespace ui {
 
@@ -61,30 +62,18 @@
   change_notifier_.RemoveObserver(observer);
 }
 
-bool XDisplayManager::CanProcessEvent(const x11::Event& x11_event) {
-  const XEvent& xev = x11_event.xlib_event();
-  return xev.type - xrandr_event_base_ ==
-             x11::RandR::ScreenChangeNotifyEvent::opcode ||
-         xev.type - xrandr_event_base_ == x11::RandR::NotifyEvent::opcode ||
-         (xev.type == PropertyNotify &&
-          static_cast<x11::Window>(xev.xproperty.window) == x_root_window_ &&
-          xev.xproperty.atom ==
-              static_cast<uint32_t>(gfx::GetAtom("_NET_WORKAREA")));
-}
-
-bool XDisplayManager::ProcessEvent(x11::Event* x11_event) {
-  DCHECK(x11_event);
-  XEvent* xev = &x11_event->xlib_event();
-  int ev_type = xev->type - xrandr_event_base_;
-  if (ev_type == x11::RandR::ScreenChangeNotifyEvent::opcode) {
-    // Pass the event through to xlib.
-    XRRUpdateConfiguration(xev);
+bool XDisplayManager::ProcessEvent(x11::Event* xev) {
+  DCHECK(xev);
+  if (xev->As<x11::RandR::ScreenChangeNotifyEvent>()) {
+    // TODO(https://crbug.com/1066670): Remove this when the Xlib dependency is
+    // removed.  We can't remove it now because it could cause the XDisplay
+    // state to become stale.
+    XRRUpdateConfiguration(&xev->xlib_event());
     return true;
   }
-  if (ev_type == x11::RandR::NotifyEvent::opcode ||
-      (xev->type == PropertyNotify &&
-       xev->xproperty.atom ==
-           static_cast<uint32_t>(gfx::GetAtom("_NET_WORKAREA")))) {
+  auto* prop = xev->As<x11::PropertyNotifyEvent>();
+  if (xev->As<x11::RandR::NotifyEvent>() ||
+      (prop && prop->atom == gfx::GetAtom("_NET_WORKAREA"))) {
     DispatchDelayedDisplayListUpdate();
     return true;
   }
diff --git a/ui/base/x/x11_display_manager.h b/ui/base/x/x11_display_manager.h
index d638460..ec6c6762 100644
--- a/ui/base/x/x11_display_manager.h
+++ b/ui/base/x/x11_display_manager.h
@@ -48,7 +48,6 @@
 
   void Init();
   bool IsXrandrAvailable() const;
-  bool CanProcessEvent(const x11::Event& xev);
   bool ProcessEvent(x11::Event* xev);
   void UpdateDisplayList();
   void DispatchDelayedDisplayListUpdate();
diff --git a/ui/base/x/x11_menu_registrar.cc b/ui/base/x/x11_menu_registrar.cc
index 2264b4b..924340bf 100644
--- a/ui/base/x/x11_menu_registrar.cc
+++ b/ui/base/x/x11_menu_registrar.cc
@@ -13,6 +13,7 @@
 #include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 #include "ui/gfx/x/x11_error_tracker.h"
+#include "ui/gfx/x/xproto.h"
 
 namespace {
 
@@ -45,27 +46,15 @@
     ui::X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
 }
 
-bool X11MenuRegistrar::DispatchXEvent(x11::Event* x11_event) {
-  XEvent* event = &x11_event->xlib_event();
-  if (event->type != CreateNotify && event->type != DestroyNotify) {
-    return false;
-  }
-  switch (event->type) {
-    case CreateNotify:
-      OnWindowCreatedOrDestroyed(
-          event->type, x11_event->As<x11::CreateNotifyEvent>()->window);
-      break;
-    case DestroyNotify:
-      OnWindowCreatedOrDestroyed(
-          event->type, x11_event->As<x11::DestroyNotifyEvent>()->window);
-      break;
-    default:
-      NOTREACHED();
-  }
+bool X11MenuRegistrar::DispatchXEvent(x11::Event* xev) {
+  if (auto* create = xev->As<x11::CreateNotifyEvent>())
+    OnWindowCreatedOrDestroyed(true, create->window);
+  else if (auto* destroy = xev->As<x11::DestroyNotifyEvent>())
+    OnWindowCreatedOrDestroyed(false, destroy->window);
   return false;
 }
 
-void X11MenuRegistrar::OnWindowCreatedOrDestroyed(int event_type,
+void X11MenuRegistrar::OnWindowCreatedOrDestroyed(bool created,
                                                   x11::Window window) {
   // Menus created by Chrome can be drag and drop targets. Since they are
   // direct children of the screen root window and have override_redirect
@@ -74,7 +63,7 @@
   // TODO(varkha): Implement caching of all top level X windows and their
   // coordinates and stacking order to eliminate repeated calls to the X server
   // during mouse movement, drag and shaping events.
-  if (event_type == CreateNotify) {
+  if (created) {
     // The window might be destroyed if the message pump did not get a chance to
     // run but we can safely ignore the X error.
     gfx::X11ErrorTracker error_tracker;
diff --git a/ui/base/x/x11_menu_registrar.h b/ui/base/x/x11_menu_registrar.h
index 0fe0a83..9014296 100644
--- a/ui/base/x/x11_menu_registrar.h
+++ b/ui/base/x/x11_menu_registrar.h
@@ -38,7 +38,7 @@
 
   // Called when |window| has been created or destroyed. |window| may not be
   // managed by Chrome.
-  void OnWindowCreatedOrDestroyed(int event_type, x11::Window window);
+  void OnWindowCreatedOrDestroyed(bool created, x11::Window window);
 
   // The display and the native X window hosting the root window.
   XDisplay* xdisplay_;
diff --git a/ui/base/x/x11_shm_image_pool.cc b/ui/base/x/x11_shm_image_pool.cc
index 1824426..23e5309 100644
--- a/ui/base/x/x11_shm_image_pool.cc
+++ b/ui/base/x/x11_shm_image_pool.cc
@@ -22,6 +22,7 @@
 #include "ui/events/platform/platform_event_dispatcher.h"
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/x/extension_manager.h"
 #include "ui/gfx/x/x11_switches.h"
 
 namespace ui {
@@ -299,12 +300,13 @@
 #endif
 }
 
-void XShmImagePool::DispatchShmCompletionEvent(XShmCompletionEvent event) {
+void XShmImagePool::DispatchShmCompletionEvent(
+    x11::Shm::CompletionEvent event) {
   DCHECK(host_task_runner_->RunsTasksInCurrentSequence());
   DCHECK_EQ(event.offset, 0UL);
 
   for (auto it = swap_closures_.begin(); it != swap_closures_.end(); ++it) {
-    if (event.shmseg == it->shmseg) {
+    if (static_cast<uint32_t>(event.shmseg) == it->shmseg) {
       std::move(it->closure).Run();
       swap_closures_.erase(it);
       return;
@@ -312,26 +314,14 @@
   }
 }
 
-bool XShmImagePool::CanDispatchXEvent(x11::Event* x11_event) {
-  const XEvent* xev = &x11_event->xlib_event();
-  DCHECK(event_task_runner_->RunsTasksInCurrentSequence());
-
-  if (xev->type != ui::ShmEventBase() + ShmCompletion)
+bool XShmImagePool::DispatchXEvent(x11::Event* xev) {
+  auto* completion = xev->As<x11::Shm::CompletionEvent>();
+  if (!completion || completion->drawable.value != drawable_.value)
     return false;
 
-  const auto* shm_event = reinterpret_cast<const XShmCompletionEvent*>(xev);
-  return shm_event->drawable == drawable_.value;
-}
-
-bool XShmImagePool::DispatchXEvent(x11::Event* x11_event) {
-  XEvent* xev = &x11_event->xlib_event();
-  if (!CanDispatchXEvent(x11_event))
-    return false;
-
-  XShmCompletionEvent* shm_event = reinterpret_cast<XShmCompletionEvent*>(xev);
   host_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&XShmImagePool::DispatchShmCompletionEvent,
-                                this, *shm_event));
+                                this, *completion));
   return true;
 }
 
diff --git a/ui/base/x/x11_shm_image_pool.h b/ui/base/x/x11_shm_image_pool.h
index b50331d5..0a39094 100644
--- a/ui/base/x/x11_shm_image_pool.h
+++ b/ui/base/x/x11_shm_image_pool.h
@@ -20,6 +20,7 @@
 #include "ui/events/platform/x11/x11_event_source.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/x/event.h"
+#include "ui/gfx/x/shm.h"
 #include "ui/gfx/x/x11.h"
 
 namespace ui {
@@ -65,9 +66,7 @@
  protected:
   ~XShmImagePool() override;
 
-  void DispatchShmCompletionEvent(XShmCompletionEvent event);
-
-  bool CanDispatchXEvent(x11::Event* xev);
+  void DispatchShmCompletionEvent(x11::Shm::CompletionEvent event);
 
   const scoped_refptr<base::SequencedTaskRunner> host_task_runner_;
   const scoped_refptr<base::SequencedTaskRunner> event_task_runner_;
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index 65984b8..5ef6b01 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -584,24 +584,22 @@
 
 int CoalescePendingMotionEvents(const x11::Event* x11_event,
                                 x11::Event* last_event) {
-  const XEvent* xev = &x11_event->xlib_event();
-  DCHECK(xev->type == x11::MotionNotifyEvent::opcode ||
-         xev->type == x11::GeGenericEvent::opcode);
+  const auto* motion = x11_event->As<x11::MotionNotifyEvent>();
+  const auto* device = x11_event->As<x11::Input::DeviceEvent>();
+  DCHECK(motion || device);
   auto* conn = x11::Connection::Get();
-  bool is_motion = false;
   int num_coalesced = 0;
 
   conn->ReadResponses();
-  if (xev->type == x11::MotionNotifyEvent::opcode) {
-    is_motion = true;
+  if (motion) {
     for (auto it = conn->events().begin(); it != conn->events().end();) {
-      const auto& next_event = it->xlib_event();
+      const auto& next_event = *it;
       // Discard all but the most recent motion event that targets the same
       // window with unchanged state.
-      if (next_event.type == x11::MotionNotifyEvent::opcode &&
-          next_event.xmotion.window == xev->xmotion.window &&
-          next_event.xmotion.subwindow == xev->xmotion.subwindow &&
-          next_event.xmotion.state == xev->xmotion.state) {
+      const auto* next_motion = next_event.As<x11::MotionNotifyEvent>();
+      if (next_motion && next_motion->event == motion->event &&
+          next_motion->child == motion->child &&
+          next_motion->state == motion->state) {
         *last_event = std::move(*it);
         it = conn->events().erase(it);
       } else {
@@ -609,48 +607,39 @@
       }
     }
   } else {
-    int event_type = xev->xgeneric.evtype;
-    XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
-    DCHECK(event_type == XI_Motion || event_type == XI_TouchUpdate);
-    is_motion = event_type == XI_Motion;
+    DCHECK(device->opcode == x11::Input::DeviceEvent::Motion ||
+           device->opcode == x11::Input::DeviceEvent::TouchUpdate);
 
     auto* ddmx11 = ui::DeviceDataManagerX11::GetInstance();
     for (auto it = conn->events().begin(); it != conn->events().end();) {
-      auto& next_event = it->xlib_event();
+      auto* next_device = it->As<x11::Input::DeviceEvent>();
 
-      if (next_event.type != x11::GeGenericEvent::opcode ||
-          !next_event.xcookie.data) {
+      if (!next_device)
         break;
-      }
 
       // If this isn't from a valid device, throw the event away, as
       // that's what the message pump would do. Device events come in pairs
       // with one from the master and one from the slave so there will
       // always be at least one pending.
-      if (!ui::TouchFactory::GetInstance()->ShouldProcessXI2Event(
-              &next_event)) {
+      if (!ui::TouchFactory::GetInstance()->ShouldProcessDeviceEvent(
+              *next_device)) {
         it = conn->events().erase(it);
         continue;
       }
 
-      if (next_event.type == x11::GeGenericEvent::opcode &&
-          next_event.xgeneric.evtype == event_type &&
+      if (next_device->opcode == device->opcode &&
           !ddmx11->IsCMTGestureEvent(*it) &&
           ddmx11->GetScrollClassEventDetail(*it) == SCROLL_TYPE_NO_SCROLL) {
-        XIDeviceEvent* next_xievent =
-            static_cast<XIDeviceEvent*>(next_event.xcookie.data);
         // Confirm that the motion event is targeted at the same window
         // and that no buttons or modifiers have changed.
-        if (xievent->event == next_xievent->event &&
-            xievent->child == next_xievent->child &&
-            xievent->detail == next_xievent->detail &&
-            xievent->buttons.mask_len == next_xievent->buttons.mask_len &&
-            (memcmp(xievent->buttons.mask, next_xievent->buttons.mask,
-                    xievent->buttons.mask_len) == 0) &&
-            xievent->mods.base == next_xievent->mods.base &&
-            xievent->mods.latched == next_xievent->mods.latched &&
-            xievent->mods.locked == next_xievent->mods.locked &&
-            xievent->mods.effective == next_xievent->mods.effective) {
+        if (device->event == next_device->event &&
+            device->child == next_device->child &&
+            device->detail == next_device->detail &&
+            device->button_mask == next_device->button_mask &&
+            device->mods.base == next_device->mods.base &&
+            device->mods.latched == next_device->mods.latched &&
+            device->mods.locked == next_device->mods.locked &&
+            device->mods.effective == next_device->mods.effective) {
           *last_event = std::move(*it);
           it = conn->events().erase(it);
           num_coalesced++;
diff --git a/ui/base/x/x11_window.cc b/ui/base/x/x11_window.cc
index 970b02c..9ace93d 100644
--- a/ui/base/x/x11_window.cc
+++ b/ui/base/x/x11_window.cc
@@ -1073,12 +1073,7 @@
 }
 
 bool XWindow::IsTargetedBy(const x11::Event& x11_event) const {
-  const XEvent& xev = x11_event.xlib_event();
-  auto target_window = static_cast<x11::Window>(
-      xev.type == x11::GeGenericEvent::opcode
-          ? static_cast<XIDeviceEvent*>(xev.xcookie.data)->event
-          : xev.xany.window);
-  return target_window == xwindow_;
+  return x11_event.window() == xwindow_;
 }
 
 void XWindow::WmMoveResize(int hittest, const gfx::Point& location) const {
@@ -1124,7 +1119,7 @@
     OnConfigureEvent(*configure);
   } else if (auto* crossing = xev->As<x11::Input::CrossingEvent>()) {
     TouchFactory* factory = TouchFactory::GetInstance();
-    if (factory->ShouldProcessXI2Event(&xev->xlib_event())) {
+    if (factory->ShouldProcessCrossingEvent(*crossing)) {
       auto mode = XI2ModeToXMode(crossing->mode);
       auto detail = XI2DetailToXDetail(crossing->detail);
       switch (crossing->opcode) {
@@ -1176,6 +1171,9 @@
     switch (mapping->request) {
       case x11::Mapping::Modifier:
       case x11::Mapping::Keyboard:
+        // TODO(https://crbug.com/1066670): Remove this when the Xlib dependency
+        // is removed.  We can't remove it now because it could cause the
+        // XDisplay state to become stale.
         XRefreshKeyboardMapping(&xev->xlib_event().xmapping);
         break;
       case x11::Mapping::Pointer:
diff --git a/ui/base/x/x11_workspace_handler.cc b/ui/base/x/x11_workspace_handler.cc
index 9e79abe..adf92e5 100644
--- a/ui/base/x/x11_workspace_handler.cc
+++ b/ui/base/x/x11_workspace_handler.cc
@@ -50,25 +50,15 @@
   return workspace_;
 }
 
-bool X11WorkspaceHandler::DispatchXEvent(x11::Event* x11_event) {
-  XEvent* event = &x11_event->xlib_event();
-  if (event->type != PropertyNotify ||
-      event->xproperty.window != static_cast<uint32_t>(x_root_window_)) {
-    return false;
+bool X11WorkspaceHandler::DispatchXEvent(x11::Event* xev) {
+  auto* prop = xev->As<x11::PropertyNotifyEvent>();
+  if (prop && prop->window == x_root_window_ &&
+      prop->atom == gfx::GetAtom("_NET_CURRENT_DESKTOP")) {
+    GetWorkspace().OnResponse(base::BindOnce(
+        &X11WorkspaceHandler::OnWorkspaceResponse, weak_factory_.GetWeakPtr()));
+    return true;
   }
-  switch (event->type) {
-    case x11::PropertyNotifyEvent::opcode: {
-      if (event->xproperty.atom ==
-          static_cast<uint32_t>(gfx::GetAtom("_NET_CURRENT_DESKTOP"))) {
-        GetWorkspace().OnResponse(
-            base::BindOnce(&X11WorkspaceHandler::OnWorkspaceResponse,
-                           weak_factory_.GetWeakPtr()));
-      }
-      break;
-    }
-    default:
-      NOTREACHED();
-  }
+
   return false;
 }
 
diff --git a/ui/events/devices/x11/touch_factory_x11.cc b/ui/events/devices/x11/touch_factory_x11.cc
index 7396743e7..d339f33 100644
--- a/ui/events/devices/x11/touch_factory_x11.cc
+++ b/ui/events/devices/x11/touch_factory_x11.cc
@@ -55,8 +55,7 @@
   UpdateDeviceList(display);
 }
 
-TouchFactory::~TouchFactory() {
-}
+TouchFactory::~TouchFactory() = default;
 
 // static
 TouchFactory* TouchFactory::GetInstance() {
@@ -146,16 +145,14 @@
   }
 }
 
-bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) {
-  DCHECK_EQ(x11::GeGenericEvent::opcode, xev->type);
-  XIEvent* event = static_cast<XIEvent*>(xev->xcookie.data);
-  XIDeviceEvent* xiev = reinterpret_cast<XIDeviceEvent*>(event);
-
+bool TouchFactory::ShouldProcessDeviceEvent(
+    const x11::Input::DeviceEvent& xiev) {
   const bool is_touch_disabled = !touch_screens_enabled_;
+  const uint16_t deviceid = static_cast<uint16_t>(xiev.deviceid);
 
-  if (event->evtype == XI_TouchBegin ||
-      event->evtype == XI_TouchUpdate ||
-      event->evtype == XI_TouchEnd) {
+  if (xiev.opcode == x11::Input::DeviceEvent::TouchBegin ||
+      xiev.opcode == x11::Input::DeviceEvent::TouchUpdate ||
+      xiev.opcode == x11::Input::DeviceEvent::TouchEnd) {
     // Since SetupXI2ForXWindow() selects events from all devices, for a
     // touchscreen attached to a master pointer device, X11 sends two
     // events for each touch: one from the slave (deviceid == the id of
@@ -166,34 +163,35 @@
     // For a 'floating' touchscreen device, X11 sends only one event for
     // each touch, with both deviceid and sourceid set to the id of the
     // touchscreen device.
-    bool is_from_master_or_float = touch_device_list_[xiev->deviceid].is_master;
-    bool is_from_slave_device = !is_from_master_or_float
-        && xiev->sourceid == xiev->deviceid;
-    return !is_touch_disabled &&
-           IsTouchDevice(xiev->deviceid) &&
+    bool is_from_master_or_float = touch_device_list_[deviceid].is_master;
+    bool is_from_slave_device =
+        !is_from_master_or_float && xiev.sourceid == xiev.deviceid;
+    return !is_touch_disabled && IsTouchDevice(deviceid) &&
            !is_from_slave_device;
   }
 
   // Make sure only key-events from the virtual core keyboard are processed.
-  if (event->evtype == XI_KeyPress || event->evtype == XI_KeyRelease) {
+  if (xiev.opcode == x11::Input::DeviceEvent::KeyPress ||
+      xiev.opcode == x11::Input::DeviceEvent::KeyRelease) {
     return (virtual_core_keyboard_device_ < 0) ||
-           (virtual_core_keyboard_device_ == xiev->deviceid);
+           (virtual_core_keyboard_device_ == deviceid);
   }
 
+  return ShouldProcessEventForDevice(deviceid);
+}
+
+bool TouchFactory::ShouldProcessCrossingEvent(
+    const x11::Input::CrossingEvent& xiev) {
   // Don't automatically accept XI_Enter or XI_Leave. They should be checked
   // against the pointer_device_lookup_ to prevent handling for slave devices.
   // This happens for unknown reasons when using xtest.
   // https://crbug.com/683434.
-  if (event->evtype != XI_ButtonPress && event->evtype != XI_ButtonRelease &&
-      event->evtype != XI_Enter && event->evtype != XI_Leave &&
-      event->evtype != XI_Motion) {
+  if (xiev.opcode != x11::Input::CrossingEvent::Enter &&
+      xiev.opcode != x11::Input::CrossingEvent::Leave) {
     return true;
   }
 
-  if (!pointer_device_lookup_[xiev->deviceid])
-    return false;
-
-  return IsTouchDevice(xiev->deviceid) ? !is_touch_disabled : true;
+  return ShouldProcessEventForDevice(static_cast<uint16_t>(xiev.deviceid));
 }
 
 void TouchFactory::SetupXI2ForXWindow(x11::Window window) {
@@ -297,8 +295,7 @@
 }
 
 bool TouchFactory::IsTouchDevicePresent() {
-  return touch_screens_enabled_ &&
-      touch_device_lookup_.any();
+  return touch_screens_enabled_ && touch_device_lookup_.any();
 }
 
 void TouchFactory::ResetForTest() {
@@ -310,24 +307,21 @@
   SetTouchscreensEnabled(true);
 }
 
-void TouchFactory::SetTouchDeviceForTest(
-    const std::vector<int>& devices) {
+void TouchFactory::SetTouchDeviceForTest(const std::vector<int>& devices) {
   touch_device_lookup_.reset();
   touch_device_list_.clear();
-  for (auto iter = devices.begin(); iter != devices.end(); ++iter) {
-    DCHECK(IsValidDevice(*iter));
-    touch_device_lookup_[*iter] = true;
-    touch_device_list_[*iter] = {true, EventPointerType::kTouch};
+  for (int device : devices) {
+    DCHECK(IsValidDevice(device));
+    touch_device_lookup_[device] = true;
+    touch_device_list_[device] = {true, EventPointerType::kTouch};
   }
   SetTouchscreensEnabled(true);
 }
 
-void TouchFactory::SetPointerDeviceForTest(
-    const std::vector<int>& devices) {
+void TouchFactory::SetPointerDeviceForTest(const std::vector<int>& devices) {
   pointer_device_lookup_.reset();
-  for (auto iter = devices.begin(); iter != devices.end(); ++iter) {
-    pointer_device_lookup_[*iter] = true;
-  }
+  for (int device : devices)
+    pointer_device_lookup_[device] = true;
 }
 
 void TouchFactory::SetTouchscreensEnabled(bool enabled) {
@@ -350,4 +344,11 @@
     touchscreen_ids_.emplace(it->vendor_id, it->product_id);
 }
 
+bool TouchFactory::ShouldProcessEventForDevice(uint16_t device_id) const {
+  if (!pointer_device_lookup_[device_id])
+    return false;
+
+  return IsTouchDevice(device_id) ? touch_screens_enabled_ : true;
+}
+
 }  // namespace ui
diff --git a/ui/events/devices/x11/touch_factory_x11.h b/ui/events/devices/x11/touch_factory_x11.h
index 13482a6..381703f 100644
--- a/ui/events/devices/x11/touch_factory_x11.h
+++ b/ui/events/devices/x11/touch_factory_x11.h
@@ -18,10 +18,11 @@
 #include "ui/events/event_constants.h"
 #include "ui/gfx/sequential_id_generator.h"
 #include "ui/gfx/x/x11_types.h"
+#include "ui/gfx/x/xinput.h"
 
 namespace base {
-
-template <typename T> struct DefaultSingletonTraits;
+template <typename T>
+struct DefaultSingletonTraits;
 }
 
 typedef unsigned long Cursor;
@@ -47,7 +48,8 @@
 
   // Checks whether an XI2 event should be processed or not (i.e. if the event
   // originated from a device we are interested in).
-  bool ShouldProcessXI2Event(XEvent* xevent);
+  bool ShouldProcessDeviceEvent(const x11::Input::DeviceEvent& event);
+  bool ShouldProcessCrossingEvent(const x11::Input::CrossingEvent& event);
 
   // Setup an X Window for XInput2 events.
   void SetupXI2ForXWindow(x11::Window window);
@@ -87,7 +89,7 @@
   bool IsTouchDevicePresent();
 
   // Pairs of <vendor id, product id> of external touch screens.
-  const std::set<std::pair<int, int> >& GetTouchscreenIds() const {
+  const std::set<std::pair<int, int>>& GetTouchscreenIds() const {
     return touchscreen_ids_;
   }
 
@@ -113,6 +115,8 @@
 
   void CacheTouchscreenIds(int id);
 
+  bool ShouldProcessEventForDevice(uint16_t device_id) const;
+
   // NOTE: To keep track of touch devices, we currently maintain a lookup table
   // to quickly decide if a device is a touch device or not. We also maintain a
   // list of the touch devices. Ideally, there will be only one touch device,
@@ -141,7 +145,7 @@
   std::map<int, TouchDeviceDetails> touch_device_list_;
 
   // Touch screen <vid, pid>s.
-  std::set<std::pair<int, int> > touchscreen_ids_;
+  std::set<std::pair<int, int>> touchscreen_ids_;
 
   // Device ID of the virtual core keyboard.
   int virtual_core_keyboard_device_;
diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc
index d3a88c1..c5915630 100644
--- a/ui/events/platform/x11/x11_event_source.cc
+++ b/ui/events/platform/x11/x11_event_source.cc
@@ -28,6 +28,7 @@
 #include "ui/events/x/x11_event_translation.h"
 #include "ui/events/x/x11_window_event_manager.h"
 #include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/extension_manager.h"
 #include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 #include "ui/gfx/x/xproto.h"
@@ -239,29 +240,25 @@
     return base::nullopt;
 
   DCHECK(dispatching_event_);
-  XEvent* event = &dispatching_event_->xlib_event();
+  x11::Event* event = dispatching_event_;
 
-  bool is_xi2_event = event->type == x11::GeGenericEvent::opcode;
-  int event_type = is_xi2_event
-                       ? reinterpret_cast<XIDeviceEvent*>(event)->evtype
-                       : event->type;
+  auto* device = event->As<x11::Input::DeviceEvent>();
+  auto* crossing = event->As<x11::Input::CrossingEvent>();
+  auto* touch_factory = ui::TouchFactory::GetInstance();
 
   bool is_valid_event = false;
-  static_assert(XI_ButtonPress == x11::ButtonEvent::Press, "");
-  static_assert(XI_ButtonRelease == x11::ButtonEvent::Release, "");
-  static_assert(XI_Motion == x11::MotionNotifyEvent::opcode, "");
-  static_assert(XI_Enter == x11::CrossingEvent::EnterNotify, "");
-  static_assert(XI_Leave == x11::CrossingEvent::LeaveNotify, "");
-  switch (event_type) {
-    case x11::ButtonEvent::Press:
-    case x11::ButtonEvent::Release:
-    case x11::MotionNotifyEvent::opcode:
-    case x11::CrossingEvent::EnterNotify:
-    case x11::CrossingEvent::LeaveNotify:
-      is_valid_event =
-          is_xi2_event
-              ? ui::TouchFactory::GetInstance()->ShouldProcessXI2Event(event)
-              : true;
+  if (event->As<x11::ButtonEvent>() || event->As<x11::MotionNotifyEvent>() ||
+      event->As<x11::CrossingEvent>()) {
+    is_valid_event = true;
+  } else if (device &&
+             (device->opcode == x11::Input::DeviceEvent::ButtonPress ||
+              device->opcode == x11::Input::DeviceEvent::ButtonRelease ||
+              device->opcode == x11::Input::DeviceEvent::Motion)) {
+    is_valid_event = touch_factory->ShouldProcessDeviceEvent(*device);
+  } else if (crossing &&
+             (crossing->opcode == x11::Input::CrossingEvent::Enter ||
+              crossing->opcode == x11::Input::CrossingEvent::Leave)) {
+    is_valid_event = touch_factory->ShouldProcessCrossingEvent(*crossing);
   }
 
   if (is_valid_event)
diff --git a/ui/events/x/events_x_utils.cc b/ui/events/x/events_x_utils.cc
index 4229fe4..a1ff4283 100644
--- a/ui/events/x/events_x_utils.cc
+++ b/ui/events/x/events_x_utils.cc
@@ -431,7 +431,8 @@
       return ET_MOUSE_EXITED;
     case x11::GeGenericEvent::opcode: {
       TouchFactory* factory = TouchFactory::GetInstance();
-      if (!factory->ShouldProcessXI2Event(const_cast<XEvent*>(&xev)))
+      auto* device = x11_event.As<x11::Input::DeviceEvent>();
+      if (!device || !factory->ShouldProcessDeviceEvent(*device))
         return ET_UNKNOWN;
 
       XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data);
diff --git a/ui/gfx/x/event.h b/ui/gfx/x/event.h
index 67f7cda..5e28c79 100644
--- a/ui/gfx/x/event.h
+++ b/ui/gfx/x/event.h
@@ -6,6 +6,7 @@
 #define UI_GFX_X_EVENT_H_
 
 #include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
 #include <xcb/xcb.h>
 
 #include <cstdint>
@@ -14,6 +15,7 @@
 #include "base/component_export.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_refptr.h"
+#include "ui/gfx/x/xproto.h"
 
 namespace x11 {
 
@@ -35,7 +37,9 @@
     xlib_event_ = *xlib_event;
     type_id_ = T::type_id;
     deleter_ = [](void* event) { delete reinterpret_cast<T*>(event); };
-    event_ = new T(std::forward<T>(xproto_event));
+    T* event = new T(std::forward<T>(xproto_event));
+    event_ = event;
+    window_ = event->GetWindow();
   }
 
   Event();
@@ -74,6 +78,8 @@
   const XEvent& xlib_event() const { return xlib_event_; }
   XEvent& xlib_event() { return xlib_event_; }
 
+  x11::Window window() const { return window_ ? *window_ : x11::Window::None; }
+
  private:
   friend void ReadEvent(Event* event,
                         Connection* connection,
@@ -93,6 +99,10 @@
   int type_id_ = 0;
   void (*deleter_)(void*) = nullptr;
   void* event_ = nullptr;
+
+  // This member points to a field in |event_|, or may be nullptr if there's no
+  // associated window for the event.  It's owned by |event_|, not us.
+  x11::Window* window_ = nullptr;
 };
 
 }  // namespace x11
diff --git a/ui/gfx/x/gen_xproto.py b/ui/gfx/x/gen_xproto.py
index fe67980f..fd9e7d1 100644
--- a/ui/gfx/x/gen_xproto.py
+++ b/ui/gfx/x/gen_xproto.py
@@ -868,6 +868,40 @@
             for field_type_name in self.declare_field(field):
                 self.write('%s %s{};' % field_type_name)
 
+    # This tries to match XEvent.xany.window, except the window will be
+    # x11::Window::None for events that don't have a window, unlike the XEvent
+    # union which will get whatever data happened to be at the offset of
+    # xany.window.
+    def get_window_field(self, event):
+        # The window field is not stored at any particular offset in the event,
+        # so get a list of all the window fields.
+        WINDOW_TYPES = set([
+            ('xcb', 'WINDOW'),
+            ('xcb', 'DRAWABLE'),
+            ('xcb', 'Glx', 'DRAWABLE'),
+        ])
+        # The window we want may not be the first in the list if there are
+        # multiple windows. This is a list of all possible window names,
+        # ordered from highest to lowest priority.
+        WINDOW_NAMES = [
+            'event',
+            'window',
+            'request_window',
+            'owner',
+        ]
+        windows = set([
+            field.field_name for field in event.fields
+            if field.field_type in WINDOW_TYPES
+        ])
+        if len(windows) == 0:
+            return ''
+        if len(windows) == 1:
+            return list(windows)[0]
+        for name in WINDOW_NAMES:
+            if name in windows:
+                return name
+        assert False
+
     def declare_event(self, event, name):
         event_name = name[-1] + 'Event'
         self.undef(event_name)
@@ -885,6 +919,11 @@
                         self.write('%s = %s,' % (opname, opcode))
             self.write('bool send_event{};')
             self.declare_fields(event.fields)
+            self.write()
+            window_field = self.get_window_field(event)
+            ret = ('reinterpret_cast<x11::Window*>(&%s)' %
+                   window_field if window_field else 'nullptr')
+            self.write('x11::Window* GetWindow() { return %s; }' % ret)
         self.write()
 
     def declare_container(self, struct, struct_name):
@@ -1544,6 +1583,7 @@
                     'event_->opcode', opcode))
             self.write('event_->send_event = send_event;')
             self.write('event->event_ = event_;')
+            self.write('event->window_ = event_->GetWindow();')
             self.write('return;')
         self.write()
 
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index a57441e..0c98d625 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -42,7 +42,9 @@
 /** @const */ var SCREEN_DISCOVER = 'discover';
 /** @const */ var SCREEN_MARKETING_OPT_IN = 'marketing-opt-in';
 
-/* Accelerator identifiers. Must be kept in sync with webui_login_view.cc. */
+/* Accelerator identifiers.
+ * Must be kept in sync with webui_accelerator_mapping.cc.
+ */
 /** @const */ var ACCELERATOR_CANCEL = 'cancel';
 /** @const */ var ACCELERATOR_ENABLE_DEBBUGING = 'debugging';
 /** @const */ var ACCELERATOR_ENROLLMENT = 'enrollment';
diff --git a/ui/ozone/platform/wayland/host/wayland_connection.cc b/ui/ozone/platform/wayland/host/wayland_connection.cc
index bb34953..7342402b 100644
--- a/ui/ozone/platform/wayland/host/wayland_connection.cc
+++ b/ui/ozone/platform/wayland/host/wayland_connection.cc
@@ -163,26 +163,33 @@
     pointer_.reset();
     cursor_.reset();
     wayland_cursor_position_.reset();
-  } else if (wl_pointer* pointer = wl_seat_get_pointer(seat)) {
-    pointer_ = std::make_unique<WaylandPointer>(pointer, this, event_source());
-    cursor_ = std::make_unique<WaylandCursor>(pointer_.get(), this);
-    wayland_cursor_position_ = std::make_unique<WaylandCursorPosition>();
-  } else {
-    LOG(ERROR) << "Failed to get wl_pointer from seat";
+  } else if (!pointer_) {
+    if (wl_pointer* pointer = wl_seat_get_pointer(seat)) {
+      pointer_ =
+          std::make_unique<WaylandPointer>(pointer, this, event_source());
+      cursor_ = std::make_unique<WaylandCursor>(pointer_.get(), this);
+      wayland_cursor_position_ = std::make_unique<WaylandCursorPosition>();
+    } else {
+      LOG(ERROR) << "Failed to get wl_pointer from seat";
+    }
   }
 
   if (!has_keyboard) {
     keyboard_.reset();
-  } else if (!CreateKeyboard()) {
-    LOG(ERROR) << "Failed to create WaylandKeyboard";
+  } else if (!keyboard_) {
+    if (!CreateKeyboard()) {
+      LOG(ERROR) << "Failed to create WaylandKeyboard";
+    }
   }
 
   if (!has_touch) {
     touch_.reset();
-  } else if (wl_touch* touch = wl_seat_get_touch(seat)) {
-    touch_ = std::make_unique<WaylandTouch>(touch, this, event_source());
-  } else {
-    LOG(ERROR) << "Failed to get wl_touch from seat";
+  } else if (!touch_) {
+    if (wl_touch* touch = wl_seat_get_touch(seat)) {
+      touch_ = std::make_unique<WaylandTouch>(touch, this, event_source());
+    } else {
+      LOG(ERROR) << "Failed to get wl_touch from seat";
+    }
   }
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index aed0e403..e1f43d2 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -151,8 +151,7 @@
 }
 
 bool DesktopScreenX11::DispatchXEvent(x11::Event* event) {
-  return x11_display_manager_->CanProcessEvent(*event) &&
-         x11_display_manager_->ProcessEvent(event);
+  return x11_display_manager_->ProcessEvent(event);
 }
 
 void DesktopScreenX11::OnDeviceScaleFactorChanged() {