diff --git a/DEPS b/DEPS
index 70eb4ea..539d028 100644
--- a/DEPS
+++ b/DEPS
@@ -228,11 +228,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': 'd090aa7feee336b4716edc23a1e99125a5a9c642',
+  'skia_revision': 'bc6d93397f9cff3503b3e40efa4ef094bbfeb471',
   # 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': 'c26eb95a3425602903f447d4fd3f8f1cfde43937',
+  'v8_revision': '49898ece362e2784a04d8595e7f5f9d1615a7a19',
   # 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.
@@ -307,7 +307,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': '01a52efc6bd7cf995e2caa76835e8457d3d5107a',
+  'devtools_frontend_revision': 'e83077df4c7793687104404992dce6f8408b990b',
   # 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.
@@ -347,7 +347,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '2d41f8c1df45b1aa642b5149060a8ec9ad9a0c63',
+  'dawn_revision': 'c607e81de239c0c06af6e5cdb76bc4e89b144a63',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -767,7 +767,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'K8c7JN0QlH9y-iVNRC74RIWTTwcUwtM9CIwQ8vPQyFkC',
+          'version': 'R0benUT8A1oqvs7L0N-hfCvDpMzfzemd6fXXr4tBOrEC',
       },
     ],
     'condition': 'checkout_android',
@@ -1389,7 +1389,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f7ba153308a223418921dff22a61527a00aea264',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'cb07e44638b99718b8c54bc19f8dbd84a3743dc6',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1478,7 +1478,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'jIoBgZ-iUWXLCCH8YkbLabPLzKXZ54b27lb6trJpzpUC'
+              'version': 'oLzjQqDQvVJY21nYf9yTG_9MDOl6D5lteCCosHg-Uc0C'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1618,7 +1618,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '827cad9e402b63bbe38787456115bcb681a8a152',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'f19dd8595c4cc6058ec47db576b292d072353e5e',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '1a09f6aebfcb8e2c5d85673902c5198610f9651f',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '6882a3f7d04865975f4c5eeee76fe324f3141521',
@@ -1682,7 +1682,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ab758d53e34a2985054eacd2407fa021827b88fb',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2066aaa5e55d4a55d0371b590e586f75e672c4c5',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 5004d3d6..287c042 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -841,7 +841,6 @@
                   '|components/policy/'\
                   '|chromeos/policy/'\
                   '|chrome/browser/ash/policy/'\
-                  '|chrome/browser/chromeos/policy/'\
                   '|chrome/browser/policy/'
     },
     'cros_reporting': {
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 1ba35f8..f9b86718 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -3253,7 +3253,7 @@
         <ph name="DESC_TEXT">$1<ex>Cannot connect to the internet. Click to try again.</ex></ph>: Retry
       </message>
       <message name="IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_IMPROVE_LABEL" desc="Description text of the report query button for the Quick Answers view.">
-        We want to improve this!
+        Help us improve this!
       </message>
       <message name="IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_REPORT_LABEL" desc="Description text of the report query button for the Quick Answers view.">
         Report this query
diff --git a/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_IMPROVE_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_IMPROVE_LABEL.png.sha1
index 6188fcb..da1dfed 100644
--- a/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_IMPROVE_LABEL.png.sha1
+++ b/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_IMPROVE_LABEL.png.sha1
@@ -1 +1 @@
-64a86d83da87b92b131ae9507b26f352c3970e4c
+122f7b4b961c5e3055532b4c2190f23fb1796a34
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_REPORT_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_REPORT_LABEL.png.sha1
index 6188fcb..da1dfed 100644
--- a/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_REPORT_LABEL.png.sha1
+++ b/ash/ash_strings_grd/IDS_ASH_QUICK_ANSWERS_VIEW_REPORT_QUERY_REPORT_LABEL.png.sha1
@@ -1 +1 @@
-64a86d83da87b92b131ae9507b26f352c3970e4c
+122f7b4b961c5e3055532b4c2190f23fb1796a34
\ No newline at end of file
diff --git a/ash/hud_display/ash_tracing_request.h b/ash/hud_display/ash_tracing_request.h
index 30f0ac5..8849ad1c 100644
--- a/ash/hud_display/ash_tracing_request.h
+++ b/ash/hud_display/ash_tracing_request.h
@@ -5,6 +5,8 @@
 #ifndef ASH_HUD_DISPLAY_ASH_TRACING_REQUEST_H_
 #define ASH_HUD_DISPLAY_ASH_TRACING_REQUEST_H_
 
+#include <sys/stat.h>
+
 #include <memory>
 
 #include "base/callback_forward.h"
diff --git a/ash/public/cpp/shelf_ui_info.h b/ash/public/cpp/shelf_ui_info.h
index 048b5871..1fd1a2b 100644
--- a/ash/public/cpp/shelf_ui_info.h
+++ b/ash/public/cpp/shelf_ui_info.h
@@ -74,6 +74,9 @@
 
   // The current hotseat state.
   HotseatState hotseat_state = HotseatState::kHidden;
+
+  // Indicates whether the hotseat is being autohidden.
+  bool is_auto_hidden = false;
 };
 
 }  // namespace ash
diff --git a/ash/quick_answers/ui/quick_answers_view.cc b/ash/quick_answers/ui/quick_answers_view.cc
index af2f0cf..e653736 100644
--- a/ash/quick_answers/ui/quick_answers_view.cc
+++ b/ash/quick_answers/ui/quick_answers_view.cc
@@ -67,7 +67,7 @@
 
 // Info icon.
 constexpr int kFeedbackIconSizeDip = 16;
-constexpr gfx::Insets kFeedbackIconInsets(8, 10, 8, 8);
+constexpr gfx::Insets kFeedbackIconInsets(9, 10, 7, 8);
 
 // Spacing between lines in the main view.
 constexpr int kLineSpacingDip = 4;
diff --git a/ash/shelf/shelf_test_api.cc b/ash/shelf/shelf_test_api.cc
index 5d82678..5be626c 100644
--- a/ash/shelf/shelf_test_api.cc
+++ b/ash/shelf/shelf_test_api.cc
@@ -118,6 +118,8 @@
   gfx::Point swipe_end_location = info.swipe_up.swipe_start_location;
   swipe_end_location.set_y(swipe_end_location.y() - swipe_distance);
   info.swipe_up.swipe_end_location = swipe_end_location;
+  info.is_auto_hidden =
+      GetShelf()->shelf_layout_manager()->is_shelf_auto_hidden();
 
   return info;
 }
diff --git a/ash/webui/shimless_rma/resources/BUILD.gn b/ash/webui/shimless_rma/resources/BUILD.gn
index 97b469e..11d4773 100644
--- a/ash/webui/shimless_rma/resources/BUILD.gn
+++ b/ash/webui/shimless_rma/resources/BUILD.gn
@@ -23,6 +23,7 @@
   "onboarding_update_page.js",
   "onboarding_wait_for_manual_wp_disable_page.js",
   "onboarding_wp_disable_complete_page.js",
+  "reimaging_accelerometer_calibration_page.js",
   "reimaging_device_information_page.js",
   "reimaging_firmware_update_page.js",
   "reimaging_provisioning_page.js",
@@ -71,6 +72,7 @@
     ":onboarding_update_page",
     ":onboarding_wait_for_manual_wp_disable_page",
     ":onboarding_wp_disable_complete_page",
+    ":reimaging_accelerometer_calibration_page",
     ":reimaging_device_information_page",
     ":reimaging_firmware_update_page",
     ":reimaging_provisioning_page",
@@ -201,6 +203,13 @@
   ]
 }
 
+js_library("reimaging_accelerometer_calibration_page") {
+  deps = [
+    ":shimless_rma_types",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
 js_library("reimaging_firmware_update_page") {
   deps = [
     ":mojo_interface_provider",
diff --git a/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js b/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js
index 6602299..81368f6 100644
--- a/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js
+++ b/ash/webui/shimless_rma/resources/fake_shimless_rma_service.js
@@ -45,6 +45,12 @@
      */
     this.automaticallyTriggerProvisioningObservation_ = false;
 
+    /**
+     * Control automatically triggering calibration observations.
+     * @private {boolean}
+     */
+    this.automaticallyTriggerCalibrationObservation_ = false;
+
     this.reset();
   }
 
@@ -458,6 +464,10 @@
               /** @type {!CalibrationComponent} */ (component),
               /** @type {number} */ (progress));
         });
+    if (this.automaticallyTriggerCalibrationObservation_) {
+      this.triggerCalibrationObserver(
+          CalibrationComponent.kAccelerometer, 100, 1500);
+    }
   }
 
   /**
@@ -491,6 +501,13 @@
   }
 
   /**
+   * Trigger calibration observations when an observer is added.
+   */
+  automaticallyTriggerCalibrationObservation() {
+    this.automaticallyTriggerCalibrationObservation_ = true;
+  }
+
+  /**
    * Implements ShimlessRmaServiceInterface.ObserveHardwareWriteProtectionState.
    * @param {!HardwareWriteProtectionStateObserverRemote} remote
    */
diff --git a/ash/webui/shimless_rma/resources/mojo_interface_provider.js b/ash/webui/shimless_rma/resources/mojo_interface_provider.js
index c70428c..da721559 100644
--- a/ash/webui/shimless_rma/resources/mojo_interface_provider.js
+++ b/ash/webui/shimless_rma/resources/mojo_interface_provider.js
@@ -47,6 +47,7 @@
   service.setReimageRequiredResult(false);
   service.automaticallyTriggerDisableWriteProtectionObservation();
   service.automaticallyTriggerProvisioningObservation();
+  service.automaticallyTriggerCalibrationObservation();
 
   service.setGetOriginalSerialNumberResult('serial# 0001')
   service.setGetRegionListResult(fakeDeviceRegions);
diff --git a/ash/webui/shimless_rma/resources/reimaging_accelerometer_calibration_page.html b/ash/webui/shimless_rma/resources/reimaging_accelerometer_calibration_page.html
new file mode 100644
index 0000000..f362a98
--- /dev/null
+++ b/ash/webui/shimless_rma/resources/reimaging_accelerometer_calibration_page.html
@@ -0,0 +1,19 @@
+<style include="cr-shared-style shimless-rma-shared">
+</style>
+
+<base-page>
+  <div slot="header">
+    <!-- TODO(joonbug): update for i18n -->
+    <h1>Calibrate the device's accelerometer</h1>
+    <div id="preCalibration" hidden$="[[calibrationObserverReceiver_]]">
+      <span>Please place the device on a flat surface before proceeding</span>
+    </div>
+    <div id="calibration" hidden$="[[!calibrationObserverReceiver_]]">
+      <span>Please wait while accelerometer is calibrated</span>
+    </div>
+    <span hidden$="[[!calibrationComplete_]]">Completed</span>
+  </div>
+  <div slot="body">
+    <!-- TODO(joonbug): add accelerometer calibration image -->
+  </div>
+</base-page>
diff --git a/ash/webui/shimless_rma/resources/reimaging_accelerometer_calibration_page.js b/ash/webui/shimless_rma/resources/reimaging_accelerometer_calibration_page.js
new file mode 100644
index 0000000..2a34589
--- /dev/null
+++ b/ash/webui/shimless_rma/resources/reimaging_accelerometer_calibration_page.js
@@ -0,0 +1,97 @@
+// Copyright 2021 The Chromium 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 './shimless_rma_shared_css.js';
+import './base_page.js';
+
+import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {getShimlessRmaService} from './mojo_interface_provider.js';
+import {CalibrationComponent, CalibrationObserverInterface, CalibrationObserverReceiver, ShimlessRmaServiceInterface, StateResult} from './shimless_rma_types.js';
+
+/**
+ * @fileoverview
+ * 'reimaging-accelerometer-calibration-page' is for recalibration of the
+ * accelerometer during the reimaging process.
+ * TODO(joonbug): when needed, generalize this for different components.
+ */
+export class ReimagingAccelerometerCalibrationPageElement extends
+    PolymerElement {
+  static get is() {
+    return 'reimaging-accelerometer-calibration-page';
+  }
+
+  static get template() {
+    return html`{__html_template__}`;
+  }
+
+  static get properties() {
+    return {
+      /** @private {ShimlessRmaServiceInterface} */
+      shimlessRmaService_: {
+        type: Object,
+        value: null,
+      },
+
+      /**
+       * Receiver responsible for observing battery health.
+       * @protected {CalibrationObserverReceiver}
+       */
+      calibrationObserverReceiver_: {
+        type: Object,
+        value: null,
+      },
+
+      /** @protected */
+      calibrationComplete_: {
+        type: Boolean,
+        value: false,
+      }
+    };
+  }
+
+  /** @override */
+  ready() {
+    super.ready();
+    this.shimlessRmaService_ = getShimlessRmaService();
+  }
+
+
+  /** @return {!Promise<!StateResult>} */
+  onNextButtonClick() {
+    if (!this.calibrationObserverReceiver_) {
+      this.observeCalibrationProgress_();
+      return Promise.reject();
+    }
+
+    if (this.calibrationComplete_) {
+      return this.shimlessRmaService_.transitionNextState();
+    }
+    return Promise.reject(new Error('Calibration is not complete.'));
+  }
+
+  /**
+   * Implements ProvisioningObserver.onProvisioningUpdated()
+   * @param {!CalibrationComponent} component
+   * @param {number} progress
+   */
+  onCalibrationUpdated(component, progress) {
+    if (progress === 100) {
+      this.calibrationComplete_ = true;
+    }
+  }
+
+  /** @private */
+  observeCalibrationProgress_() {
+    this.calibrationObserverReceiver_ = new CalibrationObserverReceiver(
+        /** @type {!CalibrationObserverInterface} */ (this));
+
+    this.shimlessRmaService_.observeCalibrationProgress(
+        this.calibrationObserverReceiver_.$.bindNewPipeAndPassRemote());
+  }
+};
+
+customElements.define(
+    ReimagingAccelerometerCalibrationPageElement.is,
+    ReimagingAccelerometerCalibrationPageElement);
diff --git a/ash/webui/shimless_rma/resources/shimless_rma.js b/ash/webui/shimless_rma/resources/shimless_rma.js
index 147057d..e7744b6 100644
--- a/ash/webui/shimless_rma/resources/shimless_rma.js
+++ b/ash/webui/shimless_rma/resources/shimless_rma.js
@@ -11,6 +11,7 @@
 import './onboarding_update_page.js';
 import './onboarding_wait_for_manual_wp_disable_page.js';
 import './onboarding_wp_disable_complete_page.js';
+import './reimaging_accelerometer_calibration_page.js';
 import './reimaging_device_information_page.js';
 import './reimaging_firmware_update_page.js';
 import './reimaging_provisioning_page.js';
@@ -121,6 +122,12 @@
     btnCancel: ButtonState.HIDDEN,
     btnBack: ButtonState.VISIBLE,
   },
+  [RmaState.kCalibrateComponents]: {
+    componentIs: 'reimaging-accelerometer-calibration-page',
+    buttonNext: ButtonState.VISIBLE,
+    buttonCancel: ButtonState.HIDDEN,
+    buttonBack: ButtonState.VISIBLE,
+  },
   [RmaState.kProvisionDevice]: {
     componentIs: 'reimaging-provisioning-page',
     btnNext: ButtonState.VISIBLE,
diff --git a/ash/webui/shimless_rma/resources/shimless_rma_types.js b/ash/webui/shimless_rma/resources/shimless_rma_types.js
index 26219fff..4873de4 100644
--- a/ash/webui/shimless_rma/resources/shimless_rma_types.js
+++ b/ash/webui/shimless_rma/resources/shimless_rma_types.js
@@ -74,6 +74,20 @@
     ash.shimlessRma.mojom.CalibrationObserverRemote;
 
 /**
+ * Type alias for CalibrationObserverReceiver.
+ * @typedef {ash.shimlessRma.mojom.CalibrationObserverReceiver}
+ */
+export let CalibrationObserverReceiver =
+    ash.shimlessRma.mojom.CalibrationObserverReceiver;
+
+/**
+ * Type alias for CalibrationObserverInterface.
+ * @typedef {ash.shimlessRma.mojom.CalibrationObserverInterface}
+ */
+export let CalibrationObserverInterface =
+    ash.shimlessRma.mojom.CalibrationObserverInterface;
+
+/**
  * Type alias for ProvisioningObserverRemote.
  * @typedef {ash.shimlessRma.mojom.ProvisioningObserverRemote}
  */
diff --git a/ash/webui/shortcut_customization_ui/resources/BUILD.gn b/ash/webui/shortcut_customization_ui/resources/BUILD.gn
index c9e85e5f..2ed555f0 100644
--- a/ash/webui/shortcut_customization_ui/resources/BUILD.gn
+++ b/ash/webui/shortcut_customization_ui/resources/BUILD.gn
@@ -13,12 +13,14 @@
 
 polymer_element_files = [
   "accelerator_edit_dialog.js",
+  "accelerator_edit_view.js",
   "accelerator_row.js",
   "accelerator_view.js",
   "accessibility_shortcuts_page.js",
   "android_shortcuts_page.js",
   "browser_shortcuts_page.js",
   "chromeos_shortcuts_page.js",
+  "icons.js",
   "input_key.js",
   "shortcut_customization_app.js",
   "shortcut_input.js",
@@ -114,6 +116,21 @@
   ]
 }
 
+js_library("accelerator_edit_view") {
+  deps = [
+    ":accelerator_view",
+    ":icons",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
+  ]
+}
+
+js_library("icons") {
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
 preprocess_if_expr("preprocess_generated") {
   deps = [ ":web_components" ]
   in_folder = target_gen_dir
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.html b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.html
index d637d9ac..a77ec1f 100644
--- a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.html
+++ b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.html
@@ -12,8 +12,8 @@
   <div slot="body">
     <div id="acceleratorViewList">
       <template is="dom-repeat" items=[[accelerators]]>
-        <accelerator-view class="acceleratorItem" accelerator=[[item]]>
-        </accelerator-view>
+        <accelerator-edit-view class="acceleratorItem" accelerator=[[item]]>
+        </accelerator-edit-view>
       </template>
     </div>
   </div>
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.js b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.js
index 3626c78..d3192fe0 100644
--- a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.js
+++ b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_dialog.js
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import './accelerator_view.js'
+import './accelerator_view.js';
+import './accelerator_edit_view.js';
 
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.html b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.html
new file mode 100644
index 0000000..240eed7
--- /dev/null
+++ b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.html
@@ -0,0 +1,57 @@
+<style include="cr-shared-style">
+  #container {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    padding-bottom: 10px;
+  }
+
+  #acceleratorInfoText {
+    padding-top: 10px
+  }
+
+  #cancelButtonContainer {
+    margin-top: 5px;
+  }
+
+  :host([is-edit-view_]) #acceleratorView {
+    border-color: var(--google-blue-600);
+    border-radius: 5px;
+    border-style: solid;
+    border-width: thin;
+    padding: 5px;
+  }
+</style>
+
+<div id="container">
+  <div id="acceleratorContainer">
+    <div id="acceleratorView">
+      <accelerator-view id="acceleratorItem"
+          accelerator=[[accelerator]] is-editable=[[isEditView_]]>
+      </accelerator-view>
+    </div>
+    <div id="acceleratorInfoText" hidden=[[!isEditView_]]>
+      <!-- TODO(jimmyxgong): Localize string -->
+      Press 1-4 modifiers and 1 other key on your keyboard
+    </div>
+  </div>
+  <div id="buttonContainer">
+    <div id="editButtonsContainer" hidden=[[isEditView_]]>
+      <cr-icon-button id="editButton"
+          iron-icon="shortcut-customization:cancel"
+          aria-hidden="true"
+          on-click="onEditButtonClicked_">
+      </cr-icon-button>
+      <cr-icon-button id="deleteButton"
+          iron-icon="shortcut-customization:delete"
+          aria-hidden="true"
+          on-click="onDeleteButtonClicked_">
+      </cr-icon-button>
+    </div>
+    <div id="cancelButtonContainer" hidden=[[!isEditView_]]>
+      <cr-button id="cancelButton" on-click="onCancelButtonClicked_">
+        <!-- TODO(jimmyxgong): Localize string -->
+        cancel
+      </cr-button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.js b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.js
new file mode 100644
index 0000000..075c702
--- /dev/null
+++ b/ash/webui/shortcut_customization_ui/resources/accelerator_edit_view.js
@@ -0,0 +1,68 @@
+// Copyright 2021 The Chromium 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 './accelerator_view.js'
+import './icons.js'
+
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/icons.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+
+import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+/**
+ * @fileoverview
+ * 'accelerator-edit-view' is a wrapper component for one accelerator. It is
+ * responsible for displaying the edit/remove buttons to an accelerator and also
+ * displaying context or errors strings for an accelerator.
+ */
+export class AcceleratorEditViewElement extends PolymerElement {
+  static get is() {
+    return 'accelerator-edit-view';
+  }
+
+  static get template() {
+    return html`{__html_template__}`;
+  }
+
+  static get properties() {
+    return {
+      /**
+       * TODO(jimmyxgong): Replace with proper mojom::Accelerator type.
+       * @type {!Object}
+       */
+      accelerator: {
+        type: Object,
+        value: () => {},
+      },
+
+      /** @private */
+      isEditView_: {
+        type: Boolean,
+        value: false,
+        reflectToAttribute: true,
+      },
+    }
+  }
+
+  /** @private */
+  onEditButtonClicked_() {
+    this.isEditView_ = true;
+  }
+
+  /** @private */
+  onDeleteButtonClicked_() {
+    // TODO(jimmyxgong): Implement this function
+  }
+
+  /** @private  */
+  onCancelButtonClicked_() {
+    this.isEditView_ = false;
+  }
+}
+
+customElements.define(AcceleratorEditViewElement.is,
+                      AcceleratorEditViewElement);
\ No newline at end of file
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_view.html b/ash/webui/shortcut_customization_ui/resources/accelerator_view.html
index be20f04..ea0e2d0 100644
--- a/ash/webui/shortcut_customization_ui/resources/accelerator_view.html
+++ b/ash/webui/shortcut_customization_ui/resources/accelerator_view.html
@@ -13,4 +13,11 @@
     <input-key key=[[accelerator.key]] key-state="alpha-numeric-selected">
     </input-key>
   </template>
+  <template is="dom-if" if=[[isEditable]]>
+    <input-key key="ctrl" key-state="not-selected"></input-key>
+    <input-key key="alt" key-state="not-selected"></input-key>
+    <input-key key="shift" key-state="not-selected"></input-key>
+    <input-key key="search" key-state="not-selected"></input-key>
+    <input-key key="key" key-state="not-selected"></input-key>
+  </template>
 </div>
\ No newline at end of file
diff --git a/ash/webui/shortcut_customization_ui/resources/icons.html b/ash/webui/shortcut_customization_ui/resources/icons.html
new file mode 100644
index 0000000..c4611b8
--- /dev/null
+++ b/ash/webui/shortcut_customization_ui/resources/icons.html
@@ -0,0 +1,14 @@
+<iron-iconset-svg name="shortcut-customization" size="20">
+  <svg>
+    <defs>
+      <!-- TODO(jimmyxgong): Replace these temporary icons with the actual
+           ones-->
+      <g id="cancel" width="16" height="16" viewBox="0 0 16 16">
+        <path d="M9.65759 5.44L7.99999 7.0976L6.34239 5.44L5.43999 6.3424L7.09759 8L5.43999 9.6576L6.34239 10.56L7.99999 8.9024L9.65759 10.56L10.56 9.6576L8.90239 8L10.56 6.3424L9.65759 5.44ZM8 1.60001C4.4608 1.60001 1.6 4.46081 1.6 8.00001C1.6 11.5392 4.4608 14.4 8 14.4C11.5392 14.4 14.4 11.5392 14.4 8.00001C14.4 4.46081 11.5392 1.60001 8 1.60001ZM8 12.8C5.354 12.8 3.2 10.646 3.2 8.00001C3.2 5.35401 5.354 3.20001 8 3.20001C10.646 3.20001 12.8 5.35401 12.8 8.00001C12.8 10.646 10.646 12.8 8 12.8Z"/>
+      </g>
+      <g id="delete" width="20" height="20" viewBox="0 0 20 20">
+        <path d="M13 3V2H7V3H3V5H4V16C4 17.1 4.9 18 6 18H14C15.1 18 16 17.1 16 16V5H17V3H13ZM14 16H6V5H14V16Z"/>
+      </g>
+    </defs>
+  </svg>
+</iron-iconset-svg>
\ No newline at end of file
diff --git a/ash/webui/shortcut_customization_ui/resources/icons.js b/ash/webui/shortcut_customization_ui/resources/icons.js
new file mode 100644
index 0000000..e585ad2
--- /dev/null
+++ b/ash/webui/shortcut_customization_ui/resources/icons.js
@@ -0,0 +1,10 @@
+// Copyright 2021 The Chromium 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/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+const template = html`{__html_template__}`;
+document.head.appendChild(template.content);
\ No newline at end of file
diff --git a/base/files/file.h b/base/files/file.h
index 8b62129..a264d93 100644
--- a/base/files/file.h
+++ b/base/files/file.h
@@ -18,19 +18,21 @@
 #include "base/trace_event/base_tracing_forward.h"
 #include "build/build_config.h"
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
-#include <sys/stat.h>
+#if defined(OS_BSD) || defined(OS_APPLE) || defined(OS_NACL) || \
+    defined(OS_FUCHSIA) || (defined(OS_ANDROID) && __ANDROID_API__ < 21)
+struct stat;
+namespace base {
+typedef struct stat stat_wrapper_t;
+}
+#elif defined(OS_POSIX)
+struct stat64;
+namespace base {
+typedef struct stat64 stat_wrapper_t;
+}
 #endif
 
 namespace base {
 
-#if defined(OS_BSD) || defined(OS_APPLE) || defined(OS_NACL) || \
-    defined(OS_FUCHSIA) || (defined(OS_ANDROID) && __ANDROID_API__ < 21)
-typedef struct stat stat_wrapper_t;
-#elif defined(OS_POSIX)
-typedef struct stat64 stat_wrapper_t;
-#endif
-
 // Thin wrapper around an OS-level file.
 // Note that this class does not provide any support for asynchronous IO, other
 // than the ability to create asynchronous handles on Windows.
diff --git a/base/files/file_enumerator.h b/base/files/file_enumerator.h
index d9d81d5..baba4d2 100644
--- a/base/files/file_enumerator.h
+++ b/base/files/file_enumerator.h
@@ -20,6 +20,7 @@
 #if defined(OS_WIN)
 #include "base/win/windows_types.h"
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include <sys/stat.h>
 #include <unistd.h>
 #include <unordered_set>
 #endif
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index 460e773..9d1db616 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -7,6 +7,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdint.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include "base/check_op.h"
diff --git a/base/files/file_util.h b/base/files/file_util.h
index f6cacc86..d43c599 100644
--- a/base/files/file_util.h
+++ b/base/files/file_util.h
@@ -17,11 +17,6 @@
 #include <string>
 #include <vector>
 
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
 #include "base/base_export.h"
 #include "base/callback_forward.h"
 #include "base/containers/span.h"
@@ -33,6 +28,8 @@
 #if defined(OS_WIN)
 #include "base/win/windows_types.h"
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include <sys/stat.h>
+#include <unistd.h>
 #include "base/file_descriptor_posix.h"
 #include "base/posix/eintr_wrapper.h"
 #endif
diff --git a/base/os_compat_android.cc b/base/os_compat_android.cc
index fa67706..80a0a10 100644
--- a/base/os_compat_android.cc
+++ b/base/os_compat_android.cc
@@ -8,6 +8,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <math.h>
+#include <sys/stat.h>
 #include <sys/syscall.h>
 #include <unistd.h>
 #include "base/strings/string_util.h"
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 53ab7dc..d3ed277 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-5.20210721.2.1
+5.20210721.4.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 53ab7dc..d3ed277 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-5.20210721.2.1
+5.20210721.4.1
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index 4e20727..735a814 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -170,24 +170,10 @@
   final_pipeline_stage_ = max_requested_pipeline_stage_;
   max_requested_pipeline_stage_ = NO_PIPELINE_STAGE;
 
-  // When we don't need to produce a CompositorFrame, there's also no need to
-  // commit our updates. We still need to run layout and paint though, as it can
-  // have side effects on page loading behavior.
-  bool skip_commit = begin_main_frame_state->begin_frame_args.animate_only;
-
   // If main frame updates and commits are deferred, skip the entire pipeline.
-  bool skip_full_pipeline = defer_main_frame_update_;
-
-  // We may have previously skipped paint and commit. If we should still skip it
-  // now, and there was no intermediate request for a commit since the last
-  // BeginMainFrame, we can skip the full pipeline.
-  skip_full_pipeline |=
-      skip_commit && final_pipeline_stage_ == NO_PIPELINE_STAGE;
-
-  if (skip_full_pipeline) {
+  if (defer_main_frame_update_) {
     TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
                          TRACE_EVENT_SCOPE_THREAD);
-
     // In this case, since the commit is deferred to a later time, gathered
     // events metrics are not discarded so that they can be reported if the
     // commit happens in the future.
@@ -217,7 +203,7 @@
   // the status at this point to keep scroll in sync.
   if (IsDeferringCommits() && base::TimeTicks::Now() > commits_restart_time_)
     StopDeferringCommits(ReasonToTimeoutTrigger(*paint_holding_reason_));
-  skip_commit |= IsDeferringCommits();
+  bool skip_commit = IsDeferringCommits();
 
   if (!skip_commit) {
     // Synchronizes scroll offsets and page scale deltas (for pinch zoom) from
@@ -266,6 +252,11 @@
   // of the defer... flags, so re-evaluate skip_commit.
   skip_commit |= defer_main_frame_update_ || IsDeferringCommits();
 
+  // When we don't need to produce a CompositorFrame, there's also no need to
+  // commit our updates. We still need to run layout and paint though, as it can
+  // have side effects on page loading behavior.
+  skip_commit |= begin_main_frame_state->begin_frame_args.animate_only;
+
   if (skip_commit) {
     current_pipeline_stage_ = NO_PIPELINE_STAGE;
     layer_tree_host_->DidBeginMainFrame();
diff --git a/chrome/VERSION b/chrome/VERSION
index 3cd34dd..849537e 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=94
 MINOR=0
-BUILD=4583
+BUILD=4584
 PATCH=0
diff --git a/chrome/android/features/cablev2_authenticator/BUILD.gn b/chrome/android/features/cablev2_authenticator/BUILD.gn
index dfd66d7..e44113a 100644
--- a/chrome/android/features/cablev2_authenticator/BUILD.gn
+++ b/chrome/android/features/cablev2_authenticator/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/android/rules.gni")
+import("//chrome/android/chrome_common_shared_library.gni")
 
 android_library("java") {
   sources = [
@@ -99,4 +100,9 @@
     "//device/fido:cablev2_registration",
     "//third_party/boringssl",
   ]
+
+  # caBLE v2 authenticator native entrypoints belong in the partition.
+  if (use_native_partitions) {
+    cflags = [ "-fsymbol-partition=cablev2_authenticator_partition" ]
+  }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java
index 0801dee..3eacd71 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java
@@ -83,6 +83,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         ensureActivityNotExported();
 
+        setTheme(R.style.ColorOverlay_ChromiumAndroid);
         setContentView(R.layout.manage_space_activity);
         Resources r = getResources();
         setTitle(String.format(r.getString(R.string.storage_management_activity_label),
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index d00939a1..7cb6ecf 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2388,6 +2388,7 @@
       "//chrome/browser/ui/webui/chromeos/crostini_installer:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/crostini_upgrader:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/emoji:mojo_bindings",
+      "//chrome/browser/ui/webui/chromeos/enterprise_casting:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/launcher_internals:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/vm:mojo_bindings",
       "//chrome/browser/ui/webui/settings/chromeos/constants:mojom",
@@ -2436,7 +2437,6 @@
     if (!is_official_build) {
       deps += [
         "//chromeos/components/demo_mode_app_ui",
-        "//chromeos/components/demo_mode_app_ui/mojom",
         "//chromeos/components/telemetry_extension_ui",
         "//chromeos/components/telemetry_extension_ui/mojom",
       ]
diff --git a/chrome/browser/apps/app_service/app_platform_metrics.cc b/chrome/browser/apps/app_service/app_platform_metrics.cc
index b079da3..01f2cb3 100644
--- a/chrome/browser/apps/app_service/app_platform_metrics.cc
+++ b/chrome/browser/apps/app_service/app_platform_metrics.cc
@@ -6,6 +6,7 @@
 
 #include <set>
 
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
 #include "base/util/values/values_util.h"
@@ -431,6 +432,12 @@
   RecordAppLaunchSource(launch_source);
   RecordAppLaunchPerAppType(
       GetAppTypeName(profile, app_type, app_id, container));
+
+  auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile);
+  if (proxy && proxy->AppPlatformMetrics()) {
+    proxy->AppPlatformMetrics()->RecordAppLaunchUkm(app_type, app_id,
+                                                    launch_source, container);
+  }
 }
 
 AppPlatformMetrics::AppPlatformMetrics(
@@ -531,10 +538,40 @@
   RecordAppsUsageTime();
 }
 
+void AppPlatformMetrics::RecordAppLaunchUkm(
+    apps::mojom::AppType app_type,
+    const std::string& app_id,
+    apps::mojom::LaunchSource launch_source,
+    apps::mojom::LaunchContainer container) {
+  if (app_type == apps::mojom::AppType::kUnknown || !ShouldRecordUkm()) {
+    return;
+  }
+
+  apps::AppTypeName app_type_name =
+      GetAppTypeName(profile_, app_type, app_id, container);
+
+  if (!ShouldRecordUkmForAppTypeName(app_type_name)) {
+    return;
+  }
+
+  ukm::SourceId source_id = GetSourceId(app_id);
+  if (source_id == ukm::kInvalidSourceId) {
+    return;
+  }
+
+  ukm::builders::ChromeOSApp_Launch builder(source_id);
+  builder.SetAppType((int)app_type_name)
+      .SetLaunchSource((int)launch_source)
+      .SetUserDeviceMatrix(GetUserTypeByDeviceTypeMetrics())
+      .Record(ukm::UkmRecorder::Get());
+}
+
 void AppPlatformMetrics::OnAppTypeInitialized(apps::mojom::AppType app_type) {
   if (should_record_metrics_on_new_day_) {
     RecordAppsCount(app_type);
   }
+
+  initialized_app_types.insert(app_type);
 }
 
 void AppPlatformMetrics::OnAppRegistryCacheWillBeDestroyed(
@@ -542,7 +579,22 @@
   apps::AppRegistryCache::Observer::Observe(nullptr);
 }
 
-void AppPlatformMetrics::OnAppUpdate(const apps::AppUpdate& update) {}
+void AppPlatformMetrics::OnAppUpdate(const apps::AppUpdate& update) {
+  if (!ShouldRecordUkm()) {
+    return;
+  }
+
+  if (!update.ReadinessChanged() ||
+      update.Readiness() != apps::mojom::Readiness::kReady) {
+    return;
+  }
+
+  InstallTime install_time =
+      base::Contains(initialized_app_types, update.AppType())
+          ? InstallTime::kRunning
+          : InstallTime::kInit;
+  RecordAppsInstallUkm(update, install_time);
+}
 
 void AppPlatformMetrics::OnInstanceUpdate(const apps::InstanceUpdate& update) {
   if (!update.StateChanged()) {
@@ -774,6 +826,28 @@
   app_id_running_time_per_five_minutes_.clear();
 }
 
+void AppPlatformMetrics::RecordAppsInstallUkm(const apps::AppUpdate& update,
+                                              InstallTime install_time) {
+  AppTypeName app_type_name =
+      GetAppTypeName(profile_, update.AppType(), update.AppId(),
+                     apps::mojom::LaunchContainer::kLaunchContainerNone);
+  if (!ShouldRecordUkmForAppTypeName(app_type_name)) {
+    return;
+  }
+
+  ukm::SourceId source_id = GetSourceId(update.AppId());
+  if (source_id == ukm::kInvalidSourceId) {
+    return;
+  }
+
+  ukm::builders::ChromeOSApp_InstalledApp builder(source_id);
+  builder.SetAppType((int)app_type_name)
+      .SetInstallSource((int)update.InstallSource())
+      .SetInstallTime((int)install_time)
+      .SetUserDeviceMatrix(user_type_by_device_type_)
+      .Record(ukm::UkmRecorder::Get());
+}
+
 bool AppPlatformMetrics::ShouldRecordUkm() {
   switch (syncer::GetUploadToGoogleState(
       SyncServiceFactory::GetForProfile(profile_), syncer::ModelType::APPS)) {
diff --git a/chrome/browser/apps/app_service/app_platform_metrics.h b/chrome/browser/apps/app_service/app_platform_metrics.h
index db492fd..dc7389f 100644
--- a/chrome/browser/apps/app_service/app_platform_metrics.h
+++ b/chrome/browser/apps/app_service/app_platform_metrics.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_APPS_APP_SERVICE_APP_PLATFORM_METRICS_H_
 
 #include <map>
+#include <set>
 
 #include "base/time/time.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
@@ -44,6 +45,16 @@
   kMaxValue = kStandaloneBrowserExtension,
 };
 
+// This is used for logging, so do not remove or reorder existing entries.
+enum class InstallTime {
+  kInit = 0,
+  kRunning = 1,
+
+  // Add any new values above this one, and update kMaxValue to the highest
+  // enumerator value.
+  kMaxValue = kRunning,
+};
+
 extern const char kAppRunningDuration[];
 extern const char kAppActivatedCount[];
 
@@ -110,6 +121,12 @@
   void OnTenMinutes();
   void OnFiveMinutes();
 
+  // Records UKM when launching apps.
+  void RecordAppLaunchUkm(apps::mojom::AppType app_type,
+                          const std::string& app_id,
+                          apps::mojom::LaunchSource launch_source,
+                          apps::mojom::LaunchContainer container);
+
  private:
   struct RunningStartTime {
     base::TimeTicks start_time;
@@ -145,6 +162,10 @@
   // Records the app usage time UKM in five minutes intervals.
   void RecordAppsUsageTimeUkm();
 
+  // Records the installed app in Chrome OS.
+  void RecordAppsInstallUkm(const apps::AppUpdate& update,
+                            InstallTime install_time);
+
   // Returns true if we are allowed to record UKM. Otherwise, returns false.
   bool ShouldRecordUkm();
 
@@ -177,6 +198,8 @@
   std::map<AppTypeName, base::TimeDelta>
       app_type_running_time_per_five_minutes_;
   std::map<std::string, base::TimeDelta> app_id_running_time_per_five_minutes_;
+
+  std::set<apps::mojom::AppType> initialized_app_types;
 };
 
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/app_platform_metrics_service.cc b/chrome/browser/apps/app_service/app_platform_metrics_service.cc
index 742d42a..af9983f0 100644
--- a/chrome/browser/apps/app_service/app_platform_metrics_service.cc
+++ b/chrome/browser/apps/app_service/app_platform_metrics_service.cc
@@ -51,7 +51,7 @@
 void AppPlatformMetricsService::Start(
     apps::AppRegistryCache& app_registry_cache,
     InstanceRegistry& instance_registry) {
-  app_platform_app_metrics_ = std::make_unique<AppPlatformMetrics>(
+  app_platform_app_metrics_ = std::make_unique<apps::AppPlatformMetrics>(
       profile_, app_registry_cache, instance_registry);
 
   day_id_ = profile_->GetPrefs()->GetInteger(kAppPlatformMetricsDayId);
diff --git a/chrome/browser/apps/app_service/app_platform_metrics_service.h b/chrome/browser/apps/app_service/app_platform_metrics_service.h
index c7c68716..96d1b5aa 100644
--- a/chrome/browser/apps/app_service/app_platform_metrics_service.h
+++ b/chrome/browser/apps/app_service/app_platform_metrics_service.h
@@ -39,6 +39,10 @@
   void Start(AppRegistryCache& app_registry_cache,
              InstanceRegistry& instance_registry);
 
+  apps::AppPlatformMetrics* AppPlatformMetrics() {
+    return app_platform_app_metrics_.get();
+  }
+
  private:
   // Helper function to check if a new day has arrived.
   void CheckForNewDay();
@@ -56,7 +60,7 @@
   // A periodic timer that checks if five minutes have arrived.
   base::RepeatingTimer five_minutes_timer_;
 
-  std::unique_ptr<AppPlatformMetrics> app_platform_app_metrics_;
+  std::unique_ptr<apps::AppPlatformMetrics> app_platform_app_metrics_;
 };
 
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/app_platform_metrics_service_unittest.cc b/chrome/browser/apps/app_service/app_platform_metrics_service_unittest.cc
index d78e05c..e67bb2b 100644
--- a/chrome/browser/apps/app_service/app_platform_metrics_service_unittest.cc
+++ b/chrome/browser/apps/app_service/app_platform_metrics_service_unittest.cc
@@ -36,6 +36,7 @@
 #include "components/user_manager/scoped_user_manager.h"
 #include "content/public/test/browser_task_environment.h"
 #include "extensions/common/constants.h"
+#include "services/metrics/public/cpp/ukm_source.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/test/test_window_delegate.h"
@@ -69,10 +70,14 @@
 
 apps::mojom::AppPtr MakeApp(const char* app_id,
                             apps::mojom::AppType app_type,
+                            const std::string& publisher_id,
+                            apps::mojom::Readiness readiness,
                             apps::mojom::InstallSource install_source) {
   apps::mojom::AppPtr app = apps::mojom::App::New();
   app->app_id = app_id;
   app->app_type = app_type;
+  app->publisher_id = publisher_id;
+  app->readiness = readiness;
   app->install_source = install_source;
   return app;
 }
@@ -153,46 +158,77 @@
         apps::AppServiceProxyFactory::GetForProfile(testing_profile_.get());
     std::vector<apps::mojom::AppPtr> deltas;
     apps::AppRegistryCache& cache = proxy->AppRegistryCache();
-    deltas.push_back(MakeApp(/*app_id=*/"u", apps::mojom::AppType::kUnknown,
-                             apps::mojom::InstallSource::kUnknown));
+
     deltas.push_back(MakeApp(/*app_id=*/"a", apps::mojom::AppType::kArc,
+                             "com.google.A", apps::mojom::Readiness::kReady,
                              apps::mojom::InstallSource::kUser));
+    cache.OnApps(std::move(deltas), apps::mojom::AppType::kArc,
+                 true /* should_notify_initialized */);
+    deltas.clear();
+
     deltas.push_back(MakeApp(/*app_id=*/"bu", apps::mojom::AppType::kBuiltIn,
+                             "", apps::mojom::Readiness::kReady,
                              apps::mojom::InstallSource::kSystem));
+    cache.OnApps(std::move(deltas), apps::mojom::AppType::kBuiltIn,
+                 true /* should_notify_initialized */);
+    deltas.clear();
+
     deltas.push_back(MakeApp(/*app_id=*/"c", apps::mojom::AppType::kCrostini,
+                             "", apps::mojom::Readiness::kReady,
                              apps::mojom::InstallSource::kUser));
+    cache.OnApps(std::move(deltas), apps::mojom::AppType::kCrostini,
+                 true /* should_notify_initialized */);
+    deltas.clear();
+
     deltas.push_back(MakeApp(/*app_id=*/"w", apps::mojom::AppType::kWeb,
+                             "https://foo.com", apps::mojom::Readiness::kReady,
                              apps::mojom::InstallSource::kSync));
+    cache.OnApps(std::move(deltas), apps::mojom::AppType::kWeb,
+                 true /* should_notify_initialized */);
+    deltas.clear();
+
     deltas.push_back(MakeApp(
-        /*app_id=*/"m", apps::mojom::AppType::kMacOs,
-        apps::mojom::InstallSource::kUnknown));
+        /*app_id=*/"s", apps::mojom::AppType::kSystemWeb, "https://os-settings",
+        apps::mojom::Readiness::kReady, apps::mojom::InstallSource::kDefault));
+    cache.OnApps(std::move(deltas), apps::mojom::AppType::kWeb,
+                 true /* should_notify_initialized */);
+    deltas.clear();
+
+    deltas.push_back(MakeApp(/*app_id=*/"u", apps::mojom::AppType::kUnknown, "",
+                             apps::mojom::Readiness::kReady,
+                             apps::mojom::InstallSource::kUnknown));
     deltas.push_back(MakeApp(
-        /*app_id=*/"p", apps::mojom::AppType::kPluginVm,
-        apps::mojom::InstallSource::kUser));
+        /*app_id=*/"m", apps::mojom::AppType::kMacOs, "",
+        apps::mojom::Readiness::kReady, apps::mojom::InstallSource::kUnknown));
     deltas.push_back(MakeApp(
-        /*app_id=*/"l", apps::mojom::AppType::kStandaloneBrowser,
-        apps::mojom::InstallSource::kSystem));
+        /*app_id=*/"p", apps::mojom::AppType::kPluginVm, "",
+        apps::mojom::Readiness::kReady, apps::mojom::InstallSource::kUser));
     deltas.push_back(MakeApp(
-        /*app_id=*/"lcr", apps::mojom::AppType::kStandaloneBrowserExtension,
-        apps::mojom::InstallSource::kUser));
+        /*app_id=*/"l", apps::mojom::AppType::kStandaloneBrowser, "",
+        apps::mojom::Readiness::kReady, apps::mojom::InstallSource::kSystem));
     deltas.push_back(MakeApp(
-        /*app_id=*/"r", apps::mojom::AppType::kRemote,
-        apps::mojom::InstallSource::kPolicy));
+        /*app_id=*/"lcr", apps::mojom::AppType::kStandaloneBrowserExtension, "",
+        apps::mojom::Readiness::kReady, apps::mojom::InstallSource::kUser));
+    deltas.push_back(MakeApp(
+        /*app_id=*/"r", apps::mojom::AppType::kRemote, "",
+        apps::mojom::Readiness::kReady, apps::mojom::InstallSource::kPolicy));
     deltas.push_back(MakeApp(/*app_id=*/"bo", apps::mojom::AppType::kBorealis,
+                             "", apps::mojom::Readiness::kReady,
                              apps::mojom::InstallSource::kOem));
-    deltas.push_back(MakeApp(/*app_id=*/"s", apps::mojom::AppType::kSystemWeb,
-                             apps::mojom::InstallSource::kDefault));
     cache.OnApps(std::move(deltas), apps::mojom::AppType::kUnknown,
                  false /* should_notify_initialized */);
   }
 
-  void InstallOneApp(const std::string& app_id, apps::mojom::AppType app_type) {
+  void InstallOneApp(const std::string& app_id,
+                     apps::mojom::AppType app_type,
+                     const std::string& publisher_id,
+                     apps::mojom::Readiness readiness) {
     auto* proxy =
         apps::AppServiceProxyFactory::GetForProfile(testing_profile_.get());
     std::vector<apps::mojom::AppPtr> deltas;
     apps::AppRegistryCache& cache = proxy->AppRegistryCache();
-    deltas.push_back(
-        MakeApp(app_id.c_str(), app_type, apps::mojom::InstallSource::kUser));
+    deltas.push_back(MakeApp(app_id.c_str(), app_type, publisher_id, readiness,
+                             apps::mojom::InstallSource::kUser));
     cache.OnApps(std::move(deltas), apps::mojom::AppType::kUnknown,
                  false /* should_notify_initialized */);
   }
@@ -268,6 +304,15 @@
         /*expected_count=*/1);
     histogram_tester_.ExpectTotalCount(
         AppPlatformMetrics::GetAppsCountHistogramNameForTest(
+            AppTypeName::kStandaloneBrowserExtension),
+        /*expected_count=*/1);
+    histogram_tester_.ExpectTotalCount(
+        AppPlatformMetrics::GetAppsCountPerInstallSourceHistogramNameForTest(
+            AppTypeName::kStandaloneBrowserExtension,
+            apps::mojom::InstallSource::kUser),
+        /*expected_count=*/1);
+    histogram_tester_.ExpectTotalCount(
+        AppPlatformMetrics::GetAppsCountHistogramNameForTest(
             AppTypeName::kRemote),
         /*expected_count=*/1);
     histogram_tester_.ExpectTotalCount(
@@ -437,13 +482,65 @@
     const std::string kUrl = std::string("app://") + app_id;
     const auto entries =
         test_ukm_recorder()->GetEntriesByName("ChromeOSApp.UsageTime");
-    ASSERT_EQ(1ul, entries.size());
-    const auto* entry = entries.back();
-    test_ukm_recorder()->ExpectEntrySourceHasUrl(entry, GURL(kUrl));
-    test_ukm_recorder()->ExpectEntryMetric(entry, "UserDeviceMatrix", 0);
-    test_ukm_recorder()->ExpectEntryMetric(entry, "Duration", duration);
-    test_ukm_recorder()->ExpectEntryMetric(entry, "AppType",
-                                           (int)app_type_name);
+    int count = 0;
+    for (const auto* entry : entries) {
+      const ukm::UkmSource* src =
+          test_ukm_recorder()->GetSourceForSourceId(entry->source_id);
+      if (src == nullptr || src->url() != GURL(kUrl)) {
+        continue;
+      }
+      ++count;
+      test_ukm_recorder()->ExpectEntryMetric(entry, "UserDeviceMatrix", 0);
+      test_ukm_recorder()->ExpectEntryMetric(entry, "Duration", duration);
+      test_ukm_recorder()->ExpectEntryMetric(entry, "AppType",
+                                             (int)app_type_name);
+    }
+    ASSERT_EQ(1, count);
+  }
+
+  void VerifyInstalledAppsUkm(const std::string& app_info,
+                              AppTypeName app_type_name,
+                              apps::mojom::InstallSource install_source,
+                              InstallTime install_time) {
+    const auto entries =
+        test_ukm_recorder()->GetEntriesByName("ChromeOSApp.InstalledApp");
+    int count = 0;
+    for (const auto* entry : entries) {
+      const ukm::UkmSource* src =
+          test_ukm_recorder()->GetSourceForSourceId(entry->source_id);
+      if (src == nullptr || src->url() != GURL(app_info)) {
+        continue;
+      }
+      ++count;
+      test_ukm_recorder()->ExpectEntryMetric(entry, "AppType",
+                                             (int)app_type_name);
+      test_ukm_recorder()->ExpectEntryMetric(entry, "InstallSource",
+                                             (int)install_source);
+      test_ukm_recorder()->ExpectEntryMetric(entry, "InstallTime",
+                                             (int)install_time);
+    }
+    ASSERT_EQ(1, count);
+  }
+
+  void VerifyAppsLaunchUkm(const std::string& app_info,
+                           AppTypeName app_type_name,
+                           apps::mojom::LaunchSource launch_source) {
+    const auto entries =
+        test_ukm_recorder()->GetEntriesByName("ChromeOSApp.Launch");
+    int count = 0;
+    for (const auto* entry : entries) {
+      const ukm::UkmSource* src =
+          test_ukm_recorder()->GetSourceForSourceId(entry->source_id);
+      if (src == nullptr || src->url() != GURL(app_info)) {
+        continue;
+      }
+      ++count;
+      test_ukm_recorder()->ExpectEntryMetric(entry, "AppType",
+                                             (int)app_type_name);
+      test_ukm_recorder()->ExpectEntryMetric(entry, "LaunchSource",
+                                             (int)launch_source);
+    }
+    ASSERT_EQ(1, count);
   }
 
   ukm::TestAutoSetUkmRecorder* test_ukm_recorder() {
@@ -459,6 +556,12 @@
     return GetPrefService()->GetInteger(kAppPlatformMetricsDayId);
   }
 
+  std::unique_ptr<AppPlatformMetricsService> GetAppPlatformMetricsService() {
+    return std::move(app_platform_metrics_service_);
+  }
+
+  TestingProfile* profile() { return testing_profile_.get(); }
+
   syncer::TestSyncService* sync_service() { return sync_service_; }
 
   base::HistogramTester& histogram_tester() { return histogram_tester_; }
@@ -523,7 +626,8 @@
   task_environment_.FastForwardBy(base::TimeDelta::FromHours(3));
   VerifyMetrics();
 
-  InstallOneApp("aa", apps::mojom::AppType::kArc);
+  InstallOneApp("aa", apps::mojom::AppType::kArc, "com.google.AA",
+                apps::mojom::Readiness::kReady);
   task_environment_.FastForwardBy(base::TimeDelta::FromDays(1));
   histogram_tester().ExpectTotalCount(
       AppPlatformMetrics::GetAppsCountHistogramNameForTest(AppTypeName::kArc),
@@ -531,7 +635,8 @@
 }
 
 TEST_F(AppPlatformMetricsServiceTest, BrowserWindow) {
-  InstallOneApp(extension_misc::kChromeAppId, apps::mojom::AppType::kExtension);
+  InstallOneApp(extension_misc::kChromeAppId, apps::mojom::AppType::kExtension,
+                "Chrome", apps::mojom::Readiness::kReady);
 
   BrowserList* active_browser_list = BrowserList::GetInstance();
   // Expect BrowserList is empty at the beginning.
@@ -594,7 +699,8 @@
 // Tests the UMA metrics when launching an app in one day .
 TEST_F(AppPlatformMetricsServiceTest, OpenWindowInOneDay) {
   std::string app_id = "aa";
-  InstallOneApp(app_id, apps::mojom::AppType::kArc);
+  InstallOneApp(app_id, apps::mojom::AppType::kArc, "com.google.AA",
+                apps::mojom::Readiness::kReady);
 
   // Create a window to simulate launching the app.
   auto window = std::make_unique<aura::Window>(nullptr);
@@ -640,7 +746,8 @@
 // Tests the UMA metrics when launching an app multiple days.
 TEST_F(AppPlatformMetricsServiceTest, OpenWindowInMultipleDays) {
   std::string app_id = "aa";
-  InstallOneApp(app_id, apps::mojom::AppType::kArc);
+  InstallOneApp(app_id, apps::mojom::AppType::kArc, "com.google.AA",
+                apps::mojom::Readiness::kReady);
 
   // Create a window to simulate launching the app.
   auto window = std::make_unique<aura::Window>(nullptr);
@@ -686,7 +793,8 @@
 // Tests the UMA metrics when an app window is reactivated.
 TEST_F(AppPlatformMetricsServiceTest, ReactiveWindow) {
   std::string app_id = "aa";
-  InstallOneApp(app_id, apps::mojom::AppType::kArc);
+  InstallOneApp(app_id, apps::mojom::AppType::kArc, "com.google.AA",
+                apps::mojom::Readiness::kReady);
 
   // Create a window to simulate launching the app.
   auto window = std::make_unique<aura::Window>(nullptr);
@@ -784,7 +892,8 @@
 // and an ARC app in one day.
 TEST_F(AppPlatformMetricsServiceTest, AppRunningPercentrage) {
   // Launch a browser window.
-  InstallOneApp(extension_misc::kChromeAppId, apps::mojom::AppType::kExtension);
+  InstallOneApp(extension_misc::kChromeAppId, apps::mojom::AppType::kExtension,
+                "Chrome", apps::mojom::Readiness::kReady);
   std::unique_ptr<Browser> browser = CreateBrowserWithAuraWindow1();
   EXPECT_EQ(1U, BrowserList::GetInstance()->size());
 
@@ -799,7 +908,8 @@
 
   // Launch an ARC app.
   std::string app_id = "aa";
-  InstallOneApp(app_id, apps::mojom::AppType::kArc);
+  InstallOneApp(app_id, apps::mojom::AppType::kArc, "com.google.AA",
+                apps::mojom::Readiness::kReady);
 
   // Create a window to simulate launching the app.
   auto window = std::make_unique<aura::Window>(nullptr);
@@ -826,7 +936,8 @@
 TEST_F(AppPlatformMetricsServiceTest, UsageTime) {
   // Create an ARC app window.
   std::string app_id = "aa";
-  InstallOneApp(app_id, apps::mojom::AppType::kArc);
+  InstallOneApp(app_id, apps::mojom::AppType::kArc, "com.google.AA",
+                apps::mojom::Readiness::kReady);
   auto window = std::make_unique<aura::Window>(nullptr);
   window->Init(ui::LAYER_NOT_DRAWN);
   ModifyInstance(app_id, window.get(), apps::InstanceState::kActive);
@@ -840,7 +951,8 @@
   ModifyInstance(app_id, window.get(), kInactiveInstanceState);
 
   // Create a browser window
-  InstallOneApp(extension_misc::kChromeAppId, apps::mojom::AppType::kExtension);
+  InstallOneApp(extension_misc::kChromeAppId, apps::mojom::AppType::kExtension,
+                "Chrome", apps::mojom::Readiness::kReady);
   std::unique_ptr<Browser> browser = CreateBrowserWithAuraWindow1();
   EXPECT_EQ(1U, BrowserList::GetInstance()->size());
 
@@ -871,7 +983,8 @@
 
 TEST_F(AppPlatformMetricsServiceTest, UsageTimeUkm) {
   // Create a browser window.
-  InstallOneApp(extension_misc::kChromeAppId, apps::mojom::AppType::kExtension);
+  InstallOneApp(extension_misc::kChromeAppId, apps::mojom::AppType::kExtension,
+                "Chrome", apps::mojom::Readiness::kReady);
   std::unique_ptr<Browser> browser = CreateBrowserWithAuraWindow1();
   EXPECT_EQ(1U, BrowserList::GetInstance()->size());
 
@@ -886,7 +999,6 @@
   task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(5));
 
   // Verify UKM is not reported.
-  const std::string kUrl = std::string("app://") + extension_misc::kChromeAppId;
   const auto entries =
       test_ukm_recorder()->GetEntriesByName("ChromeOSApp.UsageTime");
   ASSERT_EQ(0U, entries.size());
@@ -898,4 +1010,59 @@
                         AppTypeName::kChromeBrowser);
 }
 
+TEST_F(AppPlatformMetricsServiceTest, InstalledAppsUkm) {
+  // Verify the apps installed during the init phase.
+  VerifyInstalledAppsUkm("app://com.google.A", AppTypeName::kArc,
+                         apps::mojom::InstallSource::kUser, InstallTime::kInit);
+  VerifyInstalledAppsUkm("app://bu", AppTypeName::kBuiltIn,
+                         apps::mojom::InstallSource::kSystem,
+                         InstallTime::kInit);
+  VerifyInstalledAppsUkm("https://os-settings", AppTypeName::kSystemWeb,
+                         apps::mojom::InstallSource::kDefault,
+                         InstallTime::kInit);
+  VerifyInstalledAppsUkm("https://foo.com", AppTypeName::kChromeBrowser,
+                         apps::mojom::InstallSource::kSync, InstallTime::kInit);
+
+  // Install a new ARC app during the running time.
+  InstallOneApp("aa", apps::mojom::AppType::kArc, "com.google.AA",
+                apps::mojom::Readiness::kReady);
+
+  // Verify the ARC app installed during the running time.
+  VerifyInstalledAppsUkm("app://com.google.AA", AppTypeName::kArc,
+                         apps::mojom::InstallSource::kUser,
+                         InstallTime::kRunning);
+}
+
+TEST_F(AppPlatformMetricsServiceTest, LaunchAppsUkm) {
+  auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile());
+  proxy->SetAppPlatformMetricsServiceForTesting(GetAppPlatformMetricsService());
+
+  proxy->Launch(
+      /*app_id=*/"c", ui::EventFlags::EF_NONE,
+      apps::mojom::LaunchSource::kFromChromeInternal, nullptr);
+  // Verify UKM is not reported for the Crostini app.
+  const auto entries =
+      test_ukm_recorder()->GetEntriesByName("ChromeOSApp.Launch");
+  ASSERT_EQ(0U, entries.size());
+
+  proxy->Launch(
+      /*app_id=*/"a", ui::EventFlags::EF_NONE,
+      apps::mojom::LaunchSource::kFromChromeInternal, nullptr);
+  VerifyAppsLaunchUkm("app://com.google.A", AppTypeName::kArc,
+                      apps::mojom::LaunchSource::kFromChromeInternal);
+
+  proxy->LaunchAppWithUrl(
+      /*app_id=*/"w", ui::EventFlags::EF_NONE, GURL("https://boo.com/a"),
+      apps::mojom::LaunchSource::kFromFileManager, nullptr);
+  VerifyAppsLaunchUkm("https://foo.com", AppTypeName::kChromeBrowser,
+                      apps::mojom::LaunchSource::kFromFileManager);
+
+  proxy->BrowserAppLauncher()->LaunchAppWithParams(apps::AppLaunchParams(
+      "s", apps::mojom::LaunchContainer::kLaunchContainerTab,
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      apps::mojom::AppLaunchSource::kSourceTest));
+  VerifyAppsLaunchUkm("https://os-settings", AppTypeName::kChromeBrowser,
+                      apps::mojom::LaunchSource::kFromTest);
+}
+
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc b/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc
index 1572e68..7bcc5ca 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc
@@ -146,6 +146,12 @@
   return instance_registry_;
 }
 
+apps::AppPlatformMetrics* AppServiceProxyChromeOs::AppPlatformMetrics() {
+  return app_platform_metrics_service_
+             ? app_platform_metrics_service_->AppPlatformMetrics()
+             : nullptr;
+}
+
 void AppServiceProxyChromeOs::Uninstall(
     const std::string& app_id,
     apps::mojom::UninstallSource uninstall_source,
@@ -264,6 +270,12 @@
                 std::move(callback));
 }
 
+void AppServiceProxyChromeOs::SetAppPlatformMetricsServiceForTesting(
+    std::unique_ptr<apps::AppPlatformMetricsService>
+        app_platform_metrics_service) {
+  app_platform_metrics_service_ = std::move(app_platform_metrics_service);
+}
+
 void AppServiceProxyChromeOs::Shutdown() {
   app_platform_metrics_service_.reset();
 
diff --git a/chrome/browser/apps/app_service/app_service_proxy_chromeos.h b/chrome/browser/apps/app_service/app_service_proxy_chromeos.h
index 0252d4d..2715e19 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_chromeos.h
+++ b/chrome/browser/apps/app_service/app_service_proxy_chromeos.h
@@ -32,6 +32,7 @@
 
 namespace apps {
 
+class AppPlatformMetrics;
 class AppPlatformMetricsService;
 class BorealisApps;
 class BuiltInChromeOsApps;
@@ -61,6 +62,7 @@
   ~AppServiceProxyChromeOs() override;
 
   apps::InstanceRegistry& InstanceRegistry();
+  apps::AppPlatformMetrics* AppPlatformMetrics();
 
   // apps::AppServiceProxyBase overrides:
   void Uninstall(const std::string& app_id,
@@ -94,6 +96,9 @@
   void UninstallForTesting(const std::string& app_id,
                            gfx::NativeWindow parent_window,
                            base::OnceClosure callback);
+  void SetAppPlatformMetricsServiceForTesting(
+      std::unique_ptr<apps::AppPlatformMetricsService>
+          app_platform_metrics_service);
 
  private:
   using UninstallDialogs = std::set<std::unique_ptr<apps::UninstallDialog>,
@@ -189,7 +194,8 @@
 
   UninstallDialogs uninstall_dialogs_;
 
-  std::unique_ptr<AppPlatformMetricsService> app_platform_metrics_service_;
+  std::unique_ptr<apps::AppPlatformMetricsService>
+      app_platform_metrics_service_;
 
   base::WeakPtrFactory<AppServiceProxyChromeOs> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/ash/arc/fileapi/arc_content_file_system_size_util.cc b/chrome/browser/ash/arc/fileapi/arc_content_file_system_size_util.cc
index e4758f67..cffa330 100644
--- a/chrome/browser/ash/arc/fileapi/arc_content_file_system_size_util.cc
+++ b/chrome/browser/ash/arc/fileapi/arc_content_file_system_size_util.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ash/arc/fileapi/arc_content_file_system_size_util.h"
 
+#include <sys/stat.h>
+
 #include "base/task/thread_pool.h"
 #include "chrome/browser/ash/arc/fileapi/arc_file_system_operation_runner_util.h"
 #include "content/public/browser/browser_task_traits.h"
diff --git a/chrome/browser/ash/child_accounts/child_status_reporting_service.cc b/chrome/browser/ash/child_accounts/child_status_reporting_service.cc
index 217a2c1..c130fb0 100644
--- a/chrome/browser/ash/child_accounts/child_status_reporting_service.cc
+++ b/chrome/browser/ash/child_accounts/child_status_reporting_service.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/ash/child_accounts/usage_time_limit_processor.h"
 #include "chrome/browser/ash/policy/core/user_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/ash/policy/status_collector/child_status_collector.h"
-#include "chrome/browser/chromeos/policy/uploading/status_uploader.h"
+#include "chrome/browser/ash/policy/uploading/status_uploader.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/system/statistics_provider.h"
diff --git a/chrome/browser/ash/first_run/drive_first_run_browsertest.cc b/chrome/browser/ash/first_run/drive_first_run_browsertest.cc
index e2e32bc..2f648ba 100644
--- a/chrome/browser/ash/first_run/drive_first_run_browsertest.cc
+++ b/chrome/browser/ash/first_run/drive_first_run_browsertest.cc
@@ -22,7 +22,7 @@
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -180,4 +180,4 @@
   EXPECT_TRUE(timed_out());
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/first_run/drive_first_run_controller.cc b/chrome/browser/ash/first_run/drive_first_run_controller.cc
index e408971..1eb8a953 100644
--- a/chrome/browser/ash/first_run/drive_first_run_controller.cc
+++ b/chrome/browser/ash/first_run/drive_first_run_controller.cc
@@ -48,7 +48,7 @@
 #include "ui/message_center/public/cpp/notification_delegate.h"
 #include "url/gurl.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -450,4 +450,4 @@
       NotificationHandler::Type::TRANSIENT, notification, /*metadata=*/nullptr);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/first_run/drive_first_run_controller.h b/chrome/browser/ash/first_run/drive_first_run_controller.h
index d05293c..cbfe683 100644
--- a/chrome/browser/ash/first_run/drive_first_run_controller.h
+++ b/chrome/browser/ash/first_run/drive_first_run_controller.h
@@ -10,7 +10,7 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/profiles/profile.h"
 
-namespace chromeos {
+namespace ash {
 
 class DriveWebContentsManager;
 
@@ -92,6 +92,11 @@
   DISALLOW_COPY_AND_ASSIGN(DriveFirstRunController);
 };
 
+}  // namespace ash
+
+// TODO(https://crbug.com/1164001): remove when ChromeOS code migration is done.
+namespace chromeos {
+using ::ash::DriveFirstRunController;
 }  // namespace chromeos
 
 // TODO(https://crbug.com/1164001): remove after the //chrome/browser/chromeos
diff --git a/chrome/browser/ash/first_run/first_run.cc b/chrome/browser/ash/first_run/first_run.cc
index 0deb0b8..71607755 100644
--- a/chrome/browser/ash/first_run/first_run.cc
+++ b/chrome/browser/ash/first_run/first_run.cc
@@ -40,7 +40,7 @@
 #include "ui/events/event_constants.h"
 #include "ui/gfx/geometry/rect.h"
 
-namespace chromeos {
+namespace ash {
 namespace first_run {
 
 namespace {
@@ -139,7 +139,7 @@
   if (!IsRegularUserOrSupervisedChild(user_manager))
     return false;
 
-  if (chromeos::switches::ShouldSkipOobePostLogin())
+  if (switches::ShouldSkipOobePostLogin())
     return false;
 
   if (command_line->HasSwitch(switches::kForceFirstRunUI)) {
@@ -177,4 +177,4 @@
 }
 
 }  // namespace first_run
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/ash/first_run/first_run.h b/chrome/browser/ash/first_run/first_run.h
index b2a46657..28486a7 100644
--- a/chrome/browser/ash/first_run/first_run.h
+++ b/chrome/browser/ash/first_run/first_run.h
@@ -9,9 +9,9 @@
 
 namespace user_prefs {
 class PrefRegistrySyncable;
-}
+}  // namespace user_prefs
 
-namespace chromeos {
+namespace ash {
 namespace first_run {
 
 // Registers preferences related to ChromeOS first-run tutorial.
@@ -26,15 +26,6 @@
 void LaunchHelpApp(Profile* profile);
 
 }  // namespace first_run
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove after the //chrome/browser/chromeos
-// source migration is finished.
-namespace ash {
-namespace first_run {
-using ::chromeos::first_run::LaunchHelpApp;
-using ::chromeos::first_run::ShouldLaunchHelpApp;
-}  // namespace first_run
 }  // namespace ash
 
 #endif  // CHROME_BROWSER_ASH_FIRST_RUN_FIRST_RUN_H_
diff --git a/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc b/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc
index 21b26cb..83b88e8 100644
--- a/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc
+++ b/chrome/browser/ash/login/enrollment/enrollment_local_policy_server_browsertest.cc
@@ -852,9 +852,17 @@
   EXPECT_TRUE(InstallAttributes::Get()->IsEnterpriseManaged());
 }
 
+// This test is flaky on ChromeOS. https://crbug.com/1231472
+#if defined(OS_CHROMEOS)
+#define MAYBE_ZeroTouchForcedAttestationFail \
+  DISABLED_ZeroTouchForcedAttestationFail
+#else
+#define MAYBE_ZeroTouchForcedAttestationFail ZeroTouchForcedAttestationFail
+#endif
 // Zero touch with attestation authentication fail. Attestation fails because we
 // send empty cert request. Should switch to interactive authentication.
-IN_PROC_BROWSER_TEST_F(InitialEnrollmentTest, ZeroTouchForcedAttestationFail) {
+IN_PROC_BROWSER_TEST_F(InitialEnrollmentTest,
+                       MAYBE_ZeroTouchForcedAttestationFail) {
   auto initial_enrollment =
       enterprise_management::DeviceInitialEnrollmentStateResponse::
           INITIAL_ENROLLMENT_MODE_ZERO_TOUCH_ENFORCED;
diff --git a/chrome/browser/ash/policy/DEPS b/chrome/browser/ash/policy/DEPS
index dfab6f6..9e8fc49 100644
--- a/chrome/browser/ash/policy/DEPS
+++ b/chrome/browser/ash/policy/DEPS
@@ -1,6 +1,3 @@
-# TODO(https://crbug.com/1164001): When this file is edited, same file in
-# //chrome/browser/chromeos/policy should be updated as well. We need to sync
-# both files until the migration of //chrome/browser/chromeos/policy is done.
 include_rules = [
   # Run
   #
diff --git a/chrome/browser/ash/policy/DIR_METADATA b/chrome/browser/ash/policy/DIR_METADATA
index 11999464..543dab0e 100644
--- a/chrome/browser/ash/policy/DIR_METADATA
+++ b/chrome/browser/ash/policy/DIR_METADATA
@@ -1,6 +1,3 @@
-# TODO(https://crbug.com/1164001): When this file is edited, same file in
-# //chrome/browser/chromeos/policy should be updated as well. We need to sync
-# both files until the migration of //chrome/browser/chromeos/policy is done.
 monorail: {
   component: "OS>Software>Enterprise"
 }
diff --git a/chrome/browser/ash/policy/core/device_cloud_policy_manager_chromeos.cc b/chrome/browser/ash/policy/core/device_cloud_policy_manager_chromeos.cc
index 1da2c04..baa0114 100644
--- a/chrome/browser/ash/policy/core/device_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/ash/policy/core/device_cloud_policy_manager_chromeos.cc
@@ -33,10 +33,10 @@
 #include "chrome/browser/ash/policy/rsu/lookup_key_uploader.h"
 #include "chrome/browser/ash/policy/server_backed_state/server_backed_state_keys_broker.h"
 #include "chrome/browser/ash/policy/status_collector/device_status_collector.h"
+#include "chrome/browser/ash/policy/uploading/heartbeat_scheduler.h"
+#include "chrome/browser/ash/policy/uploading/status_uploader.h"
+#include "chrome/browser/ash/policy/uploading/system_log_uploader.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/policy/uploading/heartbeat_scheduler.h"
-#include "chrome/browser/chromeos/policy/uploading/status_uploader.h"
-#include "chrome/browser/chromeos/policy/uploading/system_log_uploader.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/system/statistics_provider.h"
 #include "chromeos/tpm/install_attributes.h"
diff --git a/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.cc b/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.cc
index 4693c9d..08eb20c 100644
--- a/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.cc
+++ b/chrome/browser/ash/policy/core/device_cloud_policy_store_ash.cc
@@ -14,7 +14,7 @@
 #include "base/sequenced_task_runner.h"
 #include "chrome/browser/ash/login/startup_utils.h"
 #include "chrome/browser/ash/policy/core/device_policy_decoder_chromeos.h"
-#include "chrome/browser/chromeos/policy/value_validation/onc_device_policy_value_validator.h"
+#include "chrome/browser/ash/policy/value_validation/onc_device_policy_value_validator.h"
 #include "chromeos/tpm/install_attributes.h"
 #include "components/ownership/owner_key_util.h"
 #include "components/policy/core/common/cloud/cloud_external_data_manager.h"
diff --git a/chrome/browser/ash/policy/core/device_local_account_policy_store.cc b/chrome/browser/ash/policy/core/device_local_account_policy_store.cc
index 3e6764b..8dae914 100644
--- a/chrome/browser/ash/policy/core/device_local_account_policy_store.cc
+++ b/chrome/browser/ash/policy/core/device_local_account_policy_store.cc
@@ -10,7 +10,7 @@
 #include "base/callback.h"
 #include "base/sequence_checker.h"
 #include "base/sequenced_task_runner.h"
-#include "chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.h"
+#include "chrome/browser/ash/policy/value_validation/onc_user_policy_value_validator.h"
 #include "components/ownership/owner_key_util.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
 #include "components/policy/core/common/external_data_fetcher.h"
diff --git a/chrome/browser/ash/policy/core/user_cloud_policy_store_chromeos.cc b/chrome/browser/ash/policy/core/user_cloud_policy_store_chromeos.cc
index ae418cb..5dcbf1ac 100644
--- a/chrome/browser/ash/policy/core/user_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/ash/policy/core/user_cloud_policy_store_chromeos.cc
@@ -14,7 +14,7 @@
 #include "base/sequenced_task_runner.h"
 #include "chrome/browser/ash/crosapi/browser_manager.h"
 #include "chrome/browser/ash/policy/core/cached_policy_key_loader.h"
-#include "chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.h"
+#include "chrome/browser/ash/policy/value_validation/onc_user_policy_value_validator.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "components/policy/proto/device_management_backend.pb.h"
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_fetch_status_job.cc b/chrome/browser/ash/policy/remote_commands/device_command_fetch_status_job.cc
index 4062f84..8dcc8f2 100644
--- a/chrome/browser/ash/policy/remote_commands/device_command_fetch_status_job.cc
+++ b/chrome/browser/ash/policy/remote_commands/device_command_fetch_status_job.cc
@@ -12,10 +12,10 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/ash/policy/core/browser_policy_connector_chromeos.h"
 #include "chrome/browser/ash/policy/core/device_cloud_policy_manager_chromeos.h"
+#include "chrome/browser/ash/policy/uploading/status_uploader.h"
+#include "chrome/browser/ash/policy/uploading/system_log_uploader.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/chromeos/policy/uploading/status_uploader.h"
-#include "chrome/browser/chromeos/policy/uploading/system_log_uploader.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 
 namespace policy {
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.cc b/chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.cc
index 516f6ff5..643c26d 100644
--- a/chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.cc
+++ b/chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.cc
@@ -17,7 +17,7 @@
 #include "base/syslog_logging.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
-#include "chrome/browser/chromeos/policy/uploading/upload_job_impl.h"
+#include "chrome/browser/ash/policy/uploading/upload_job_impl.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/http/http_request_headers.h"
diff --git a/chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.h b/chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.h
index d65ea34..60f3f3e 100644
--- a/chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.h
+++ b/chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.h
@@ -17,7 +17,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task_runner.h"
-#include "chrome/browser/chromeos/policy/uploading/upload_job.h"
+#include "chrome/browser/ash/policy/uploading/upload_job.h"
 #include "components/policy/core/common/remote_commands/remote_command_job.h"
 #include "ui/snapshot/snapshot.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/ash/policy/remote_commands/screenshot_delegate.cc b/chrome/browser/ash/policy/remote_commands/screenshot_delegate.cc
index 38b0900..570f53d 100644
--- a/chrome/browser/ash/policy/remote_commands/screenshot_delegate.cc
+++ b/chrome/browser/ash/policy/remote_commands/screenshot_delegate.cc
@@ -12,10 +12,10 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/ash/policy/core/browser_policy_connector_chromeos.h"
 #include "chrome/browser/ash/policy/core/device_cloud_policy_manager_chromeos.h"
+#include "chrome/browser/ash/policy/uploading/status_uploader.h"
+#include "chrome/browser/ash/policy/uploading/upload_job_impl.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/chromeos/policy/uploading/status_uploader.h"
-#include "chrome/browser/chromeos/policy/uploading/upload_job_impl.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service_factory.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ash/policy/remote_commands/screenshot_delegate.h b/chrome/browser/ash/policy/remote_commands/screenshot_delegate.h
index 433c357..d233ab2 100644
--- a/chrome/browser/ash/policy/remote_commands/screenshot_delegate.h
+++ b/chrome/browser/ash/policy/remote_commands/screenshot_delegate.h
@@ -11,7 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/policy/remote_commands/device_command_screenshot_job.h"
-#include "chrome/browser/chromeos/policy/uploading/upload_job.h"
+#include "chrome/browser/ash/policy/uploading/upload_job.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/snapshot/snapshot.h"
diff --git a/chrome/browser/chromeos/policy/tools/generate_device_policy_remover.py b/chrome/browser/ash/policy/tools/generate_device_policy_remover.py
similarity index 100%
rename from chrome/browser/chromeos/policy/tools/generate_device_policy_remover.py
rename to chrome/browser/ash/policy/tools/generate_device_policy_remover.py
diff --git a/chrome/browser/chromeos/policy/uploading/README.md b/chrome/browser/ash/policy/uploading/README.md
similarity index 86%
rename from chrome/browser/chromeos/policy/uploading/README.md
rename to chrome/browser/ash/policy/uploading/README.md
index 6fcf703..a7e600a 100644
--- a/chrome/browser/chromeos/policy/uploading/README.md
+++ b/chrome/browser/ash/policy/uploading/README.md
@@ -1,4 +1,4 @@
-chrome/browser/chromeos/policy/uploading
+chrome/browser/ash/policy/uploading
 ========================================
 
 This directory should contain code that handles periodically scheduled
diff --git a/chrome/browser/chromeos/policy/uploading/heartbeat_scheduler.cc b/chrome/browser/ash/policy/uploading/heartbeat_scheduler.cc
similarity index 99%
rename from chrome/browser/chromeos/policy/uploading/heartbeat_scheduler.cc
rename to chrome/browser/ash/policy/uploading/heartbeat_scheduler.cc
index f4a4409..f17b19a1 100644
--- a/chrome/browser/chromeos/policy/uploading/heartbeat_scheduler.cc
+++ b/chrome/browser/ash/policy/uploading/heartbeat_scheduler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/uploading/heartbeat_scheduler.h"
+#include "chrome/browser/ash/policy/uploading/heartbeat_scheduler.h"
 
 #include <memory>
 #include <vector>
diff --git a/chrome/browser/chromeos/policy/uploading/heartbeat_scheduler.h b/chrome/browser/ash/policy/uploading/heartbeat_scheduler.h
similarity index 96%
rename from chrome/browser/chromeos/policy/uploading/heartbeat_scheduler.h
rename to chrome/browser/ash/policy/uploading/heartbeat_scheduler.h
index f6ad295..d7ba8238 100644
--- a/chrome/browser/chromeos/policy/uploading/heartbeat_scheduler.h
+++ b/chrome/browser/ash/policy/uploading/heartbeat_scheduler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_HEARTBEAT_SCHEDULER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_HEARTBEAT_SCHEDULER_H_
+#ifndef CHROME_BROWSER_ASH_POLICY_UPLOADING_HEARTBEAT_SCHEDULER_H_
+#define CHROME_BROWSER_ASH_POLICY_UPLOADING_HEARTBEAT_SCHEDULER_H_
 
 #include <stdint.h>
 
@@ -163,4 +163,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_HEARTBEAT_SCHEDULER_H_
+#endif  // CHROME_BROWSER_ASH_POLICY_UPLOADING_HEARTBEAT_SCHEDULER_H_
diff --git a/chrome/browser/chromeos/policy/uploading/heartbeat_scheduler_unittest.cc b/chrome/browser/ash/policy/uploading/heartbeat_scheduler_unittest.cc
similarity index 99%
rename from chrome/browser/chromeos/policy/uploading/heartbeat_scheduler_unittest.cc
rename to chrome/browser/ash/policy/uploading/heartbeat_scheduler_unittest.cc
index 3ed75d3..34fc2ff 100644
--- a/chrome/browser/chromeos/policy/uploading/heartbeat_scheduler_unittest.cc
+++ b/chrome/browser/ash/policy/uploading/heartbeat_scheduler_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/chromeos/policy/uploading/heartbeat_scheduler.h"
+#include "chrome/browser/ash/policy/uploading/heartbeat_scheduler.h"
 
 #include <stdint.h>
 
diff --git a/chrome/browser/chromeos/policy/uploading/status_uploader.cc b/chrome/browser/ash/policy/uploading/status_uploader.cc
similarity index 99%
rename from chrome/browser/chromeos/policy/uploading/status_uploader.cc
rename to chrome/browser/ash/policy/uploading/status_uploader.cc
index c87078d..9fbb475 100644
--- a/chrome/browser/chromeos/policy/uploading/status_uploader.cc
+++ b/chrome/browser/ash/policy/uploading/status_uploader.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/uploading/status_uploader.h"
+#include "chrome/browser/ash/policy/uploading/status_uploader.h"
 
 #include <algorithm>
 #include <string>
diff --git a/chrome/browser/chromeos/policy/uploading/status_uploader.h b/chrome/browser/ash/policy/uploading/status_uploader.h
similarity index 95%
rename from chrome/browser/chromeos/policy/uploading/status_uploader.h
rename to chrome/browser/ash/policy/uploading/status_uploader.h
index 6df09bf..ccda664 100644
--- a/chrome/browser/chromeos/policy/uploading/status_uploader.h
+++ b/chrome/browser/ash/policy/uploading/status_uploader.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_STATUS_UPLOADER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_STATUS_UPLOADER_H_
+#ifndef CHROME_BROWSER_ASH_POLICY_UPLOADING_STATUS_UPLOADER_H_
+#define CHROME_BROWSER_ASH_POLICY_UPLOADING_STATUS_UPLOADER_H_
 
 #include <memory>
 
@@ -119,4 +119,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_STATUS_UPLOADER_H_
+#endif  // CHROME_BROWSER_ASH_POLICY_UPLOADING_STATUS_UPLOADER_H_
diff --git a/chrome/browser/chromeos/policy/uploading/status_uploader_unittest.cc b/chrome/browser/ash/policy/uploading/status_uploader_unittest.cc
similarity index 99%
rename from chrome/browser/chromeos/policy/uploading/status_uploader_unittest.cc
rename to chrome/browser/ash/policy/uploading/status_uploader_unittest.cc
index 341b361..98d0e84 100644
--- a/chrome/browser/chromeos/policy/uploading/status_uploader_unittest.cc
+++ b/chrome/browser/ash/policy/uploading/status_uploader_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/chromeos/policy/uploading/status_uploader.h"
+#include "chrome/browser/ash/policy/uploading/status_uploader.h"
 
 #include <memory>
 #include <utility>
diff --git a/chrome/browser/chromeos/policy/uploading/system_log_uploader.cc b/chrome/browser/ash/policy/uploading/system_log_uploader.cc
similarity index 99%
rename from chrome/browser/chromeos/policy/uploading/system_log_uploader.cc
rename to chrome/browser/ash/policy/uploading/system_log_uploader.cc
index 55a5b28..52dcb82 100644
--- a/chrome/browser/chromeos/policy/uploading/system_log_uploader.cc
+++ b/chrome/browser/ash/policy/uploading/system_log_uploader.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/uploading/system_log_uploader.h"
+#include "chrome/browser/ash/policy/uploading/system_log_uploader.h"
 
 #include <algorithm>
 #include <map>
@@ -24,8 +24,8 @@
 #include "base/task/thread_pool.h"
 #include "base/values.h"
 #include "chrome/browser/ash/policy/core/policy_pref_names.h"
+#include "chrome/browser/ash/policy/uploading/upload_job_impl.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/policy/uploading/upload_job_impl.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service_factory.h"
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
diff --git a/chrome/browser/chromeos/policy/uploading/system_log_uploader.h b/chrome/browser/ash/policy/uploading/system_log_uploader.h
similarity index 95%
rename from chrome/browser/chromeos/policy/uploading/system_log_uploader.h
rename to chrome/browser/ash/policy/uploading/system_log_uploader.h
index cb1a06d..97bd7f9 100644
--- a/chrome/browser/chromeos/policy/uploading/system_log_uploader.h
+++ b/chrome/browser/ash/policy/uploading/system_log_uploader.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_SYSTEM_LOG_UPLOADER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_SYSTEM_LOG_UPLOADER_H_
+#ifndef CHROME_BROWSER_ASH_POLICY_UPLOADING_SYSTEM_LOG_UPLOADER_H_
+#define CHROME_BROWSER_ASH_POLICY_UPLOADING_SYSTEM_LOG_UPLOADER_H_
 
 #include <stdint.h>
 
@@ -18,8 +18,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
+#include "chrome/browser/ash/policy/uploading/upload_job.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
-#include "chrome/browser/chromeos/policy/uploading/upload_job.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -198,4 +198,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_SYSTEM_LOG_UPLOADER_H_
+#endif  // CHROME_BROWSER_ASH_POLICY_UPLOADING_SYSTEM_LOG_UPLOADER_H_
diff --git a/chrome/browser/chromeos/policy/uploading/system_log_uploader_unittest.cc b/chrome/browser/ash/policy/uploading/system_log_uploader_unittest.cc
similarity index 99%
rename from chrome/browser/chromeos/policy/uploading/system_log_uploader_unittest.cc
rename to chrome/browser/ash/policy/uploading/system_log_uploader_unittest.cc
index 6ba0f60..da58349 100644
--- a/chrome/browser/chromeos/policy/uploading/system_log_uploader_unittest.cc
+++ b/chrome/browser/ash/policy/uploading/system_log_uploader_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/chromeos/policy/uploading/system_log_uploader.h"
+#include "chrome/browser/ash/policy/uploading/system_log_uploader.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/policy/uploading/upload_job.h b/chrome/browser/ash/policy/uploading/upload_job.h
similarity index 93%
rename from chrome/browser/chromeos/policy/uploading/upload_job.h
rename to chrome/browser/ash/policy/uploading/upload_job.h
index 0583aad..5886ed7 100644
--- a/chrome/browser/chromeos/policy/uploading/upload_job.h
+++ b/chrome/browser/ash/policy/uploading/upload_job.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_UPLOAD_JOB_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_UPLOAD_JOB_H_
+#ifndef CHROME_BROWSER_ASH_POLICY_UPLOADING_UPLOAD_JOB_H_
+#define CHROME_BROWSER_ASH_POLICY_UPLOADING_UPLOAD_JOB_H_
 
 #include <map>
 #include <memory>
@@ -75,4 +75,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_UPLOAD_JOB_H_
+#endif  // CHROME_BROWSER_ASH_POLICY_UPLOADING_UPLOAD_JOB_H_
diff --git a/chrome/browser/chromeos/policy/uploading/upload_job_impl.cc b/chrome/browser/ash/policy/uploading/upload_job_impl.cc
similarity index 99%
rename from chrome/browser/chromeos/policy/uploading/upload_job_impl.cc
rename to chrome/browser/ash/policy/uploading/upload_job_impl.cc
index 9e6bc7a..3753b33 100644
--- a/chrome/browser/chromeos/policy/uploading/upload_job_impl.cc
+++ b/chrome/browser/ash/policy/uploading/upload_job_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/uploading/upload_job_impl.h"
+#include "chrome/browser/ash/policy/uploading/upload_job_impl.h"
 
 #include <stddef.h>
 
diff --git a/chrome/browser/chromeos/policy/uploading/upload_job_impl.h b/chrome/browser/ash/policy/uploading/upload_job_impl.h
similarity index 95%
rename from chrome/browser/chromeos/policy/uploading/upload_job_impl.h
rename to chrome/browser/ash/policy/uploading/upload_job_impl.h
index 0d5ff14..01a4e3d1 100644
--- a/chrome/browser/chromeos/policy/uploading/upload_job_impl.h
+++ b/chrome/browser/ash/policy/uploading/upload_job_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_UPLOAD_JOB_IMPL_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_UPLOAD_JOB_IMPL_H_
+#ifndef CHROME_BROWSER_ASH_POLICY_UPLOADING_UPLOAD_JOB_IMPL_H_
+#define CHROME_BROWSER_ASH_POLICY_UPLOADING_UPLOAD_JOB_IMPL_H_
 
 #include <map>
 #include <memory>
@@ -13,7 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
-#include "chrome/browser/chromeos/policy/uploading/upload_job.h"
+#include "chrome/browser/ash/policy/uploading/upload_job.h"
 #include "google_apis/gaia/oauth2_access_token_manager.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "url/gurl.h"
@@ -195,4 +195,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_UPLOADING_UPLOAD_JOB_IMPL_H_
+#endif  // CHROME_BROWSER_ASH_POLICY_UPLOADING_UPLOAD_JOB_IMPL_H_
diff --git a/chrome/browser/chromeos/policy/uploading/upload_job_unittest.cc b/chrome/browser/ash/policy/uploading/upload_job_unittest.cc
similarity index 98%
rename from chrome/browser/chromeos/policy/uploading/upload_job_unittest.cc
rename to chrome/browser/ash/policy/uploading/upload_job_unittest.cc
index 7d76a4e..bb01f271 100644
--- a/chrome/browser/chromeos/policy/uploading/upload_job_unittest.cc
+++ b/chrome/browser/ash/policy/uploading/upload_job_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/chromeos/policy/uploading/upload_job.h"
+#include "chrome/browser/ash/policy/uploading/upload_job.h"
 
 #include <stddef.h>
 
@@ -19,7 +19,7 @@
 #include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "chrome/browser/chromeos/policy/uploading/upload_job_impl.h"
+#include "chrome/browser/ash/policy/uploading/upload_job_impl.h"
 #include "content/public/test/browser_task_environment.h"
 #include "google_apis/gaia/core_account_id.h"
 #include "google_apis/gaia/fake_oauth2_access_token_manager.h"
diff --git a/chrome/browser/chromeos/policy/value_validation/onc_device_policy_value_validator.cc b/chrome/browser/ash/policy/value_validation/onc_device_policy_value_validator.cc
similarity index 91%
rename from chrome/browser/chromeos/policy/value_validation/onc_device_policy_value_validator.cc
rename to chrome/browser/ash/policy/value_validation/onc_device_policy_value_validator.cc
index c1e34adb..00f117a 100644
--- a/chrome/browser/chromeos/policy/value_validation/onc_device_policy_value_validator.cc
+++ b/chrome/browser/ash/policy/value_validation/onc_device_policy_value_validator.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/value_validation/onc_device_policy_value_validator.h"
+#include "chrome/browser/ash/policy/value_validation/onc_device_policy_value_validator.h"
 
 #include "components/policy/policy_constants.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
diff --git a/chrome/browser/chromeos/policy/value_validation/onc_device_policy_value_validator.h b/chrome/browser/ash/policy/value_validation/onc_device_policy_value_validator.h
similarity index 66%
rename from chrome/browser/chromeos/policy/value_validation/onc_device_policy_value_validator.h
rename to chrome/browser/ash/policy/value_validation/onc_device_policy_value_validator.h
index 4e5b556..6a087dc 100644
--- a/chrome/browser/chromeos/policy/value_validation/onc_device_policy_value_validator.h
+++ b/chrome/browser/ash/policy/value_validation/onc_device_policy_value_validator.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_VALUE_VALIDATION_ONC_DEVICE_POLICY_VALUE_VALIDATOR_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_VALUE_VALIDATION_ONC_DEVICE_POLICY_VALUE_VALIDATOR_H_
+#ifndef CHROME_BROWSER_ASH_POLICY_VALUE_VALIDATION_ONC_DEVICE_POLICY_VALUE_VALIDATOR_H_
+#define CHROME_BROWSER_ASH_POLICY_VALUE_VALIDATION_ONC_DEVICE_POLICY_VALUE_VALIDATOR_H_
 
-#include "chrome/browser/chromeos/policy/value_validation/onc_policy_value_validator_base.h"
+#include "chrome/browser/ash/policy/value_validation/onc_policy_value_validator_base.h"
 
 namespace enterprise_management {
 class ChromeDeviceSettingsProto;
@@ -31,4 +31,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_VALUE_VALIDATION_ONC_DEVICE_POLICY_VALUE_VALIDATOR_H_
+#endif  // CHROME_BROWSER_ASH_POLICY_VALUE_VALIDATION_ONC_DEVICE_POLICY_VALUE_VALIDATOR_H_
diff --git a/chrome/browser/chromeos/policy/value_validation/onc_policy_value_validator_base.h b/chrome/browser/ash/policy/value_validation/onc_policy_value_validator_base.h
similarity index 91%
rename from chrome/browser/chromeos/policy/value_validation/onc_policy_value_validator_base.h
rename to chrome/browser/ash/policy/value_validation/onc_policy_value_validator_base.h
index 8f98d0c2..7f7366a 100644
--- a/chrome/browser/chromeos/policy/value_validation/onc_policy_value_validator_base.h
+++ b/chrome/browser/ash/policy/value_validation/onc_policy_value_validator_base.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_VALUE_VALIDATION_ONC_POLICY_VALUE_VALIDATOR_BASE_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_VALUE_VALIDATION_ONC_POLICY_VALUE_VALIDATOR_BASE_H_
+#ifndef CHROME_BROWSER_ASH_POLICY_VALUE_VALIDATION_ONC_POLICY_VALUE_VALIDATOR_BASE_H_
+#define CHROME_BROWSER_ASH_POLICY_VALUE_VALIDATION_ONC_POLICY_VALUE_VALIDATOR_BASE_H_
 
 #include "components/policy/core/common/cloud/policy_value_validator.h"
 
@@ -81,4 +81,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_VALUE_VALIDATION_ONC_POLICY_VALUE_VALIDATOR_BASE_H_
+#endif  // CHROME_BROWSER_ASH_POLICY_VALUE_VALIDATION_ONC_POLICY_VALUE_VALIDATOR_BASE_H_
diff --git a/chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.cc b/chrome/browser/ash/policy/value_validation/onc_user_policy_value_validator.cc
similarity index 90%
rename from chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.cc
rename to chrome/browser/ash/policy/value_validation/onc_user_policy_value_validator.cc
index 685724b..94d0f6c 100644
--- a/chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.cc
+++ b/chrome/browser/ash/policy/value_validation/onc_user_policy_value_validator.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.h"
+#include "chrome/browser/ash/policy/value_validation/onc_user_policy_value_validator.h"
 
 #include "components/policy/policy_constants.h"
 #include "components/policy/proto/cloud_policy.pb.h"
diff --git a/chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.h b/chrome/browser/ash/policy/value_validation/onc_user_policy_value_validator.h
similarity index 66%
rename from chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.h
rename to chrome/browser/ash/policy/value_validation/onc_user_policy_value_validator.h
index ade5b9d..aa940ab 100644
--- a/chrome/browser/chromeos/policy/value_validation/onc_user_policy_value_validator.h
+++ b/chrome/browser/ash/policy/value_validation/onc_user_policy_value_validator.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_VALUE_VALIDATION_ONC_USER_POLICY_VALUE_VALIDATOR_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_VALUE_VALIDATION_ONC_USER_POLICY_VALUE_VALIDATOR_H_
+#ifndef CHROME_BROWSER_ASH_POLICY_VALUE_VALIDATION_ONC_USER_POLICY_VALUE_VALIDATOR_H_
+#define CHROME_BROWSER_ASH_POLICY_VALUE_VALIDATION_ONC_USER_POLICY_VALUE_VALIDATOR_H_
 
-#include "chrome/browser/chromeos/policy/value_validation/onc_policy_value_validator_base.h"
+#include "chrome/browser/ash/policy/value_validation/onc_policy_value_validator_base.h"
 
 namespace enterprise_management {
 class CloudPolicySettings;
@@ -31,4 +31,4 @@
 
 }  // namespace policy
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_VALUE_VALIDATION_ONC_USER_POLICY_VALUE_VALIDATOR_H_
+#endif  // CHROME_BROWSER_ASH_POLICY_VALUE_VALIDATION_ONC_USER_POLICY_VALUE_VALIDATOR_H_
diff --git a/chrome/browser/ash/web_applications/demo_mode_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/demo_mode_app_integration_browsertest.cc
index eb9839c..5439897 100644
--- a/chrome/browser/ash/web_applications/demo_mode_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/demo_mode_app_integration_browsertest.cc
@@ -7,7 +7,6 @@
 #include "chrome/browser/ash/web_applications/system_web_app_integration_test.h"
 #include "chromeos/components/demo_mode_app_ui/url_constants.h"
 #include "content/public/test/browser_test.h"
-#include "ui/views/widget/widget.h"
 
 class DemoModeAppIntegrationTest : public SystemWebAppIntegrationTest {
  public:
@@ -26,23 +25,5 @@
       web_app::SystemAppType::DEMO_MODE, url, "Demo Mode App"));
 }
 
-// Test that Demo Mode app starts in fullscreen from initial call to
-// ToggleFullscreen() Mojo API, and subsequent call exits fullscreen
-IN_PROC_BROWSER_TEST_P(DemoModeAppIntegrationTest,
-                       DemoModeAppToggleFullscreen) {
-  WaitForTestSystemAppInstall();
-  Browser* browser;
-  content::WebContents* web_contents =
-      LaunchApp(web_app::SystemAppType::DEMO_MODE, &browser);
-  views::Widget* widget = views::Widget::GetWidgetForNativeWindow(
-      web_contents->GetTopLevelNativeWindow());
-  EXPECT_TRUE(widget->IsFullscreen());
-
-  bool success = content::ExecuteScript(
-      web_contents, "window.pageHandler.toggleFullscreen();");
-  EXPECT_TRUE(success);
-  EXPECT_FALSE(widget->IsFullscreen());
-}
-
 INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_GUEST_SESSION_P(
     DemoModeAppIntegrationTest);
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_notification_controller.cc b/chrome/browser/ash/web_applications/help_app/help_app_notification_controller.cc
index c02d767..b3b82d1 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_notification_controller.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_notification_controller.cc
@@ -26,7 +26,7 @@
 // This stores the latest milestone with new Discover Tab content. If the last
 // milestone the user has seen the notification is before this, a new
 // notification will be shown.
-constexpr int kLastChromeVersionWithDiscoverTabContent = 92;
+constexpr int kLastChromeVersionWithDiscoverTabContent = 94;
 constexpr int kTimesToShowSuggestionChip = 3;
 
 int CurrentMilestone() {
diff --git a/chrome/browser/ash/web_applications/help_app/help_app_notification_controller_unittest.cc b/chrome/browser/ash/web_applications/help_app/help_app_notification_controller_unittest.cc
index 858400ed..46a3b17 100644
--- a/chrome/browser/ash/web_applications/help_app/help_app_notification_controller_unittest.cc
+++ b/chrome/browser/ash/web_applications/help_app/help_app_notification_controller_unittest.cc
@@ -333,34 +333,6 @@
   EXPECT_EQ(false, HasDiscoverTabNotification());
 }
 
-TEST_F(HelpAppNotificationControllerTest,
-       DoesNotShowDiscoverNotificationIfAlreadyShownIfM92) {
-  std::unique_ptr<Profile> profile = CreateChildProfile();
-  profile->GetPrefs()->SetInteger(prefs::kHelpAppNotificationLastShownMilestone,
-                                  92);
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile.get());
-
-  controller->MaybeShowDiscoverNotification();
-
-  EXPECT_EQ(0, notification_count_);
-  EXPECT_EQ(false, HasDiscoverTabNotification());
-}
-
-TEST_F(HelpAppNotificationControllerTest,
-       DoesNotShowDiscoverNotificationIfAlreadyShownInM93) {
-  std::unique_ptr<Profile> profile = CreateChildProfile();
-  profile->GetPrefs()->SetInteger(prefs::kHelpAppNotificationLastShownMilestone,
-                                  93);
-  std::unique_ptr<HelpAppNotificationController> controller =
-      std::make_unique<HelpAppNotificationController>(profile.get());
-
-  controller->MaybeShowDiscoverNotification();
-
-  EXPECT_EQ(0, notification_count_);
-  EXPECT_EQ(false, HasDiscoverTabNotification());
-}
-
 // TODO(b/187774783): Remove this when discover tab is supported in all locales.
 TEST_F(HelpAppNotificationControllerTest,
        DoesNotShowDiscoverNotificationIfSystemLanguageNotEnglish) {
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 7ec620d..964593b8 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -187,6 +187,8 @@
 #include "chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h"
 #include "chrome/browser/ui/webui/chromeos/emoji/emoji_picker.mojom.h"
 #include "chrome/browser/ui/webui/chromeos/emoji/emoji_ui.h"
+#include "chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting.mojom.h"
+#include "chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting_ui.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h"
 #include "chrome/browser/ui/webui/chromeos/internet_config_dialog.h"
 #include "chrome/browser/ui/webui/chromeos/internet_detail_dialog.h"
@@ -239,8 +241,6 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OFFICIAL_BUILD)
-#include "chromeos/components/demo_mode_app_ui/demo_mode_app_ui.h"
-#include "chromeos/components/demo_mode_app_ui/mojom/demo_mode_app_ui.mojom.h"
 #include "chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom.h"  // nogncheck crbug.com/1125897
 #include "chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom.h"  // nogncheck crbug.com/1125897
 #include "chromeos/components/telemetry_extension_ui/mojom/system_events_service.mojom.h"  // nogncheck crbug.com/1125897
@@ -893,15 +893,13 @@
   RegisterWebUIControllerInterfaceBinder<
       launcher_internals::mojom::PageHandlerFactory,
       chromeos::LauncherInternalsUI>(map);
+
+  RegisterWebUIControllerInterfaceBinder<
+      enterprise_casting::mojom::PageHandlerFactory,
+      chromeos::EnterpriseCastingUI>(map);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OFFICIAL_BUILD)
-  if (chromeos::features::IsDemoModeSWAEnabled()) {
-    RegisterWebUIControllerInterfaceBinder<
-        chromeos::mojom::demo_mode::PageHandlerFactory,
-        chromeos::DemoModeAppUI>(map);
-  }
-
   if (base::FeatureList::IsEnabled(chromeos::features::kTelemetryExtension)) {
     RegisterWebUIControllerInterfaceBinder<
         chromeos::health::mojom::DiagnosticsService,
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 5dc5ab6..2aa89a3 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -88,6 +88,7 @@
 #include "chrome/browser/startup_data.h"
 #include "chrome/browser/tracing/background_tracing_field_trial.h"
 #include "chrome/browser/tracing/trace_event_system_stats_monitor.h"
+#include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/translate/translate_service.h"
 #include "chrome/browser/ui/javascript_dialogs/chrome_javascript_app_modal_dialog_view_factory.h"
 #include "chrome/browser/ui/profile_error_dialog.h"
@@ -142,6 +143,7 @@
 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "components/translate/core/browser/translate_download_manager.h"
+#include "components/translate/core/browser/translate_metrics_logger_impl.h"
 #include "components/variations/field_trial_config/field_trial_util.h"
 #include "components/variations/pref_names.h"
 #include "components/variations/service/variations_service.h"
@@ -1554,6 +1556,8 @@
       profile_->GetPrefs()->GetString(language::prefs::kAcceptLanguages));
   language::LanguageUsageMetrics::RecordApplicationLanguage(
       browser_process_->GetApplicationLocale());
+  translate::TranslateMetricsLoggerImpl::LogApplicationStartMetrics(
+      ChromeTranslateClient::CreateTranslatePrefs(profile_->GetPrefs()));
 // On ChromeOS results in a crash. https://crbug.com/1151558
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
   language::LanguageUsageMetrics::RecordPageLanguages(
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index f4e2daf..c9ceb41 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2264,6 +2264,20 @@
     "../ash/policy/status_collector/status_collector_state.h",
     "../ash/policy/status_collector/tpm_status_combiner.cc",
     "../ash/policy/status_collector/tpm_status_combiner.h",
+    "../ash/policy/uploading/heartbeat_scheduler.cc",
+    "../ash/policy/uploading/heartbeat_scheduler.h",
+    "../ash/policy/uploading/status_uploader.cc",
+    "../ash/policy/uploading/status_uploader.h",
+    "../ash/policy/uploading/system_log_uploader.cc",
+    "../ash/policy/uploading/system_log_uploader.h",
+    "../ash/policy/uploading/upload_job.h",
+    "../ash/policy/uploading/upload_job_impl.cc",
+    "../ash/policy/uploading/upload_job_impl.h",
+    "../ash/policy/value_validation/onc_device_policy_value_validator.cc",
+    "../ash/policy/value_validation/onc_device_policy_value_validator.h",
+    "../ash/policy/value_validation/onc_policy_value_validator_base.h",
+    "../ash/policy/value_validation/onc_user_policy_value_validator.cc",
+    "../ash/policy/value_validation/onc_user_policy_value_validator.h",
     "../ash/power/auto_screen_brightness/adapter.cc",
     "../ash/power/auto_screen_brightness/adapter.h",
     "../ash/power/auto_screen_brightness/als_file_reader.cc",
@@ -2983,20 +2997,6 @@
     "platform_keys/platform_keys_service_factory.cc",
     "platform_keys/platform_keys_service_factory.h",
     "platform_keys/platform_keys_service_nss.cc",
-    "policy/uploading/heartbeat_scheduler.cc",
-    "policy/uploading/heartbeat_scheduler.h",
-    "policy/uploading/status_uploader.cc",
-    "policy/uploading/status_uploader.h",
-    "policy/uploading/system_log_uploader.cc",
-    "policy/uploading/system_log_uploader.h",
-    "policy/uploading/upload_job.h",
-    "policy/uploading/upload_job_impl.cc",
-    "policy/uploading/upload_job_impl.h",
-    "policy/value_validation/onc_device_policy_value_validator.cc",
-    "policy/value_validation/onc_device_policy_value_validator.h",
-    "policy/value_validation/onc_policy_value_validator_base.h",
-    "policy/value_validation/onc_user_policy_value_validator.cc",
-    "policy/value_validation/onc_user_policy_value_validator.h",
     "preferences.cc",
     "preferences.h",
     "printing/automatic_usb_printer_configurer.cc",
@@ -4040,6 +4040,10 @@
     "../ash/policy/status_collector/enterprise_activity_storage_unittest.cc",
     "../ash/policy/status_collector/interval_map_unittest.cc",
     "../ash/policy/status_collector/managed_session_service_unittest.cc",
+    "../ash/policy/uploading/heartbeat_scheduler_unittest.cc",
+    "../ash/policy/uploading/status_uploader_unittest.cc",
+    "../ash/policy/uploading/system_log_uploader_unittest.cc",
+    "../ash/policy/uploading/upload_job_unittest.cc",
     "../ash/power/auto_screen_brightness/adapter_unittest.cc",
     "../ash/power/auto_screen_brightness/als_file_reader_unittest.cc",
     "../ash/power/auto_screen_brightness/als_reader_unittest.cc",
@@ -4259,10 +4263,6 @@
     "phonehub/browser_tabs_model_provider_impl_unittest.cc",
     "platform_keys/key_permissions/arc_key_permissions_manager_delegate_unittest.cc",
     "platform_keys/key_permissions/key_permissions_service_impl_unittest.cc",
-    "policy/uploading/heartbeat_scheduler_unittest.cc",
-    "policy/uploading/status_uploader_unittest.cc",
-    "policy/uploading/system_log_uploader_unittest.cc",
-    "policy/uploading/upload_job_unittest.cc",
     "preferences_unittest.cc",
     "printing/automatic_usb_printer_configurer_unittest.cc",
     "printing/bulk_printers_calculator_unittest.cc",
@@ -4566,7 +4566,7 @@
 device_policy_remover_path = "$target_gen_dir/device_policy_remover.cc"
 
 action("device_policy_remover_generate") {
-  script = "policy/tools/generate_device_policy_remover.py"
+  script = "../ash/policy/tools/generate_device_policy_remover.py"
   descriptor_pool_path = "//third_party/protobuf/python"
   symbol_database_path = "$root_out_dir/pyproto"
 
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index 5266dd3..db84f16 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -4849,6 +4849,7 @@
     hotseat_ui_info.swipe_up = std::move(swipe_up_descriptor);
     hotseat_ui_info.is_animating = hotseat_info.is_animating;
     hotseat_ui_info.state = GetHotseatState(hotseat_info.hotseat_state);
+    hotseat_ui_info.is_auto_hidden = hotseat_info.is_auto_hidden;
 
     shelf_ui_info.hotseat_info = std::move(hotseat_ui_info);
   }
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
index 3436b50..7398616 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -450,6 +450,8 @@
           base::BindRepeating(&EventRouter::DispatchDirectoryChangeEventImpl,
                               base::Unretained(this))) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // Notification manager can call into Drive FS for dialog handling.
+  notification_manager_->SetDriveFSEventRouter(drivefs_event_router_.get());
   ObserveEvents();
 }
 
@@ -901,6 +903,7 @@
   util::VolumeToVolumeMetadata(profile_, volume, &event.volume_metadata);
   event.should_notify =
       ShouldShowNotificationForVolume(profile_, *device_event_router_, volume);
+  notification_manager_->HandleMountCompletedEvent(event, volume);
   BroadcastEvent(profile_,
                  extensions::events::FILE_MANAGER_PRIVATE_ON_MOUNT_COMPLETED,
                  file_manager_private::OnMountCompleted::kEventName,
diff --git a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.cc b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.cc
index 49ea195..1394a4d 100644
--- a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.cc
@@ -8,6 +8,11 @@
 #include "base/bind.h"
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ash/drive/drivefs_native_message_host.h"
+#include "chrome/browser/chromeos/extensions/file_manager/drivefs_event_router.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
+#include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom-forward.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/strings/grit/ui_chromeos_strings.h"
@@ -151,7 +156,144 @@
   }
 }
 
-void SystemNotificationManager::HandleEvent(const extensions::Event& event) {}
+namespace file_manager_private = extensions::api::file_manager_private;
+
+std::unique_ptr<message_center::Notification>
+SystemNotificationManager::MakeDriveSyncErrorNotification(
+    const extensions::Event& event,
+    base::Value::ListView& event_arguments) {
+  std::unique_ptr<message_center::Notification> notification;
+  file_manager_private::DriveSyncErrorEvent sync_error;
+  const char* id;
+  std::u16string title =
+      l10n_util::GetStringUTF16(IDS_FILE_BROWSER_DRIVE_DIRECTORY_LABEL);
+  std::u16string message;
+  if (file_manager_private::DriveSyncErrorEvent::Populate(event_arguments[0],
+                                                          &sync_error)) {
+    id = file_manager_private::ToString(sync_error.type);
+    switch (sync_error.type) {
+      case file_manager_private::
+          DRIVE_SYNC_ERROR_TYPE_DELETE_WITHOUT_PERMISSION:
+        message = l10n_util::GetStringFUTF16(
+            IDS_FILE_BROWSER_SYNC_DELETE_WITHOUT_PERMISSION_ERROR,
+            base::UTF8ToUTF16(event.event_url.ExtractFileName()));
+        notification = CreateNotification(id, title, message);
+        break;
+      case file_manager_private::DRIVE_SYNC_ERROR_TYPE_SERVICE_UNAVAILABLE:
+        notification =
+            CreateNotification(id, IDS_FILE_BROWSER_DRIVE_DIRECTORY_LABEL,
+                               IDS_FILE_BROWSER_SYNC_SERVICE_UNAVAILABLE_ERROR);
+        break;
+      case file_manager_private::DRIVE_SYNC_ERROR_TYPE_NO_SERVER_SPACE:
+        message = l10n_util::GetStringFUTF16(
+            IDS_FILE_BROWSER_SYNC_NO_SERVER_SPACE,
+            base::UTF8ToUTF16(event.event_url.ExtractFileName()));
+        notification = CreateNotification(id, title, message);
+        break;
+      case file_manager_private::DRIVE_SYNC_ERROR_TYPE_NO_LOCAL_SPACE:
+        notification =
+            CreateNotification(id, IDS_FILE_BROWSER_DRIVE_DIRECTORY_LABEL,
+                               IDS_FILE_BROWSER_DRIVE_OUT_OF_SPACE_HEADER);
+        break;
+      case file_manager_private::DRIVE_SYNC_ERROR_TYPE_MISC:
+        message = l10n_util::GetStringFUTF16(
+            IDS_FILE_BROWSER_SYNC_MISC_ERROR,
+            base::UTF8ToUTF16(event.event_url.ExtractFileName()));
+        notification = CreateNotification(id, title, message);
+        break;
+      default:
+        DLOG(WARNING) << "Unknown Drive Sync error: " << sync_error.type;
+        break;
+    }
+  }
+  return notification;
+}
+
+const char* kDriveDialogId = "swa-drive-confirm-dialog";
+
+void SystemNotificationManager::HandleDriveDialogClick(
+    absl::optional<int> button_index) {
+  drivefs::mojom::DialogResult result = drivefs::mojom::DialogResult::kDismiss;
+  if (button_index) {
+    if (button_index.value() == 1) {
+      result = drivefs::mojom::DialogResult::kAccept;
+    } else {
+      result = drivefs::mojom::DialogResult::kReject;
+    }
+  }
+  // Send the dialog result to the callback stored in DriveFS on dialog
+  // creation.
+  if (drivefs_event_router_) {
+    drivefs_event_router_->OnDialogResult(result);
+  }
+  GetNotificationDisplayService()->Close(NotificationHandler::Type::TRANSIENT,
+                                         kDriveDialogId);
+}
+
+std::unique_ptr<message_center::Notification>
+SystemNotificationManager::MakeDriveConfirmDialogNotification(
+    const extensions::Event& event,
+    base::Value::ListView& event_arguments) {
+  std::unique_ptr<message_center::Notification> notification;
+  file_manager_private::DriveConfirmDialogEvent dialog_event;
+  const char* id;
+  std::u16string title =
+      l10n_util::GetStringUTF16(IDS_FILE_BROWSER_DRIVE_DIRECTORY_LABEL);
+  std::u16string message;
+  if (file_manager_private::DriveConfirmDialogEvent::Populate(
+          event_arguments[0], &dialog_event)) {
+    std::vector<message_center::ButtonInfo> notification_buttons;
+    id = file_manager_private::ToString(dialog_event.type);
+    notification = ash::CreateSystemNotification(
+        message_center::NOTIFICATION_TYPE_SIMPLE, kDriveDialogId,
+        l10n_util::GetStringUTF16(IDS_FILE_BROWSER_DRIVE_DIRECTORY_LABEL),
+        l10n_util::GetStringUTF16(IDS_FILE_BROWSER_OFFLINE_ENABLE_MESSAGE),
+        std::u16string(), GURL(), message_center::NotifierId(),
+        message_center::RichNotificationData(),
+        new message_center::HandleNotificationClickDelegate(base::BindRepeating(
+            &SystemNotificationManager::HandleDriveDialogClick,
+            weak_ptr_factory_.GetWeakPtr())),
+        kNotificationGoogleIcon,
+        message_center::SystemNotificationWarningLevel::NORMAL);
+
+    notification_buttons.push_back(message_center::ButtonInfo(
+        l10n_util::GetStringUTF16(IDS_FILE_BROWSER_OFFLINE_ENABLE_REJECT)));
+    notification_buttons.push_back(message_center::ButtonInfo(
+        l10n_util::GetStringUTF16(IDS_FILE_BROWSER_OFFLINE_ENABLE_ACCEPT)));
+    notification->set_buttons(notification_buttons);
+  }
+  return notification;
+}
+
+void SystemNotificationManager::HandleEvent(const extensions::Event& event) {
+  if (!swa_enabled_) {
+    return;
+  }
+  base::Value::ListView event_arguments;
+
+  event_arguments = event.event_args->GetList();
+  if (event_arguments.size() < 1) {
+    return;
+  }
+  std::unique_ptr<message_center::Notification> notification;
+  switch (event.histogram_value) {
+    case extensions::events::FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR:
+      notification = MakeDriveSyncErrorNotification(event, event_arguments);
+      break;
+    case extensions::events::FILE_MANAGER_PRIVATE_ON_DRIVE_CONFIRM_DIALOG:
+      notification = MakeDriveConfirmDialogNotification(event, event_arguments);
+      break;
+    default:
+      DLOG(WARNING) << "Unhandled event: " << event.event_name;
+      break;
+  }
+
+  if (notification) {
+    GetNotificationDisplayService()->Display(
+        NotificationHandler::Type::TRANSIENT, *notification,
+        /*metadata=*/nullptr);
+  }
+}
 
 void SystemNotificationManager::HandleCopyStart(
     int copy_id,
@@ -166,8 +308,6 @@
 
 const char* kSwaFileOperationPrefix = "swa-file-operation-";
 
-namespace file_manager_private = extensions::api::file_manager_private;
-
 void SystemNotificationManager::HandleCopyEvent(
     int copy_id,
     file_manager_private::CopyOrMoveProgressStatus& status) {
@@ -228,9 +368,88 @@
   }
 }
 
+const char* kRemovableNotificationId = "swa-removable-device-id";
+
+void SystemNotificationManager::HandleRemovableNotificationClick(
+    const std::string& path,
+    absl::optional<int> button_index) {
+  if (button_index) {
+    if (button_index.value() == 0) {
+      base::FilePath volume_root(path);
+      platform_util::ShowItemInFolder(profile_, volume_root);
+    } else {
+      chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
+          profile_, chromeos::settings::mojom::kExternalStorageSubpagePath);
+    }
+  }
+
+  GetNotificationDisplayService()->Close(NotificationHandler::Type::TRANSIENT,
+                                         kRemovableNotificationId);
+}
+
+std::unique_ptr<message_center::Notification>
+SystemNotificationManager::MakeRemovableNotification(
+    file_manager_private::MountCompletedEvent& event,
+    const Volume& volume) {
+  std::unique_ptr<message_center::Notification> notification =
+      ash::CreateSystemNotification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, kRemovableNotificationId,
+          l10n_util::GetStringUTF16(IDS_REMOVABLE_DEVICE_DETECTION_TITLE),
+          l10n_util::GetStringUTF16(IDS_REMOVABLE_DEVICE_NAVIGATION_MESSAGE),
+          std::u16string(), GURL(), message_center::NotifierId(),
+          message_center::RichNotificationData(),
+          new message_center::HandleNotificationClickDelegate(
+              base::BindRepeating(
+                  &SystemNotificationManager::HandleRemovableNotificationClick,
+                  weak_ptr_factory_.GetWeakPtr(), volume.mount_path().value())),
+          kNotificationGoogleIcon,
+          message_center::SystemNotificationWarningLevel::NORMAL);
+
+  std::vector<message_center::ButtonInfo> notification_buttons;
+  notification_buttons.push_back(message_center::ButtonInfo(
+      l10n_util::GetStringUTF16(IDS_REMOVABLE_DEVICE_NAVIGATION_BUTTON_LABEL)));
+  notification_buttons.push_back(
+      message_center::ButtonInfo(l10n_util::GetStringUTF16(
+          IDS_REMOVABLE_DEVICE_OPEN_SETTTINGS_BUTTON_LABEL)));
+  notification->set_buttons(notification_buttons);
+
+  return notification;
+}
+
+void SystemNotificationManager::HandleMountCompletedEvent(
+    file_manager_private::MountCompletedEvent& event,
+    const Volume& volume) {
+  if (!swa_enabled_) {
+    return;
+  }
+  std::unique_ptr<message_center::Notification> notification;
+
+  switch (event.event_type) {
+    case file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT:
+      if (event.should_notify) {
+        notification = MakeRemovableNotification(event, volume);
+      }
+      break;
+    default:
+      DLOG(WARNING) << "Unhandled mount event for type " << event.event_type;
+      break;
+  }
+
+  if (notification) {
+    GetNotificationDisplayService()->Display(
+        NotificationHandler::Type::TRANSIENT, *notification,
+        /*metadata=*/nullptr);
+  }
+}
+
 NotificationDisplayService*
 SystemNotificationManager::GetNotificationDisplayService() {
   return NotificationDisplayServiceFactory::GetForProfile(profile_);
 }
 
+void SystemNotificationManager::SetDriveFSEventRouter(
+    DriveFsEventRouter* drivefs_event_router) {
+  drivefs_event_router_ = drivefs_event_router;
+}
+
 }  // namespace file_manager
diff --git a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.h b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.h
index bcd2362..b7a6a9a 100644
--- a/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.h
+++ b/chrome/browser/chromeos/extensions/file_manager/system_notification_manager.h
@@ -8,6 +8,7 @@
 #include "ash/public/cpp/notification_utils.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/ash/file_manager/volume_manager.h"
 #include "chrome/browser/notifications/notification_display_service.h"
 #include "chrome/browser/notifications/notification_display_service_factory.h"
 #include "chrome/browser/notifications/system_notification_helper.h"
@@ -21,6 +22,8 @@
 
 namespace file_manager_private = extensions::api::file_manager_private;
 
+class DriveFsEventRouter;
+
 // Manages creation/deletion and update of system notifications on behalf
 // of the File Manager application.
 class SystemNotificationManager {
@@ -83,12 +86,56 @@
                        file_manager_private::CopyOrMoveProgressStatus& status);
 
   /**
+   * Processes volume mount completed events.
+   */
+  void HandleMountCompletedEvent(
+      file_manager_private::MountCompletedEvent& event,
+      const Volume& volume);
+
+  /**
    * Returns the message center display service that manages notifications.
    */
   NotificationDisplayService* GetNotificationDisplayService();
 
+  /**
+   * Stores a reference to the DriveFS event router instance.
+   */
+  void SetDriveFSEventRouter(DriveFsEventRouter* drivefs_event_router);
+
  private:
   /**
+   * Make notifications for DriveFS sync errors.
+   */
+  std::unique_ptr<message_center::Notification> MakeDriveSyncErrorNotification(
+      const extensions::Event& event,
+      base::Value::ListView& event_arguments);
+
+  /**
+   * Click handler for the Drive offline confirmation dialog notification.
+   */
+  void HandleDriveDialogClick(absl::optional<int> button_index);
+
+  /**
+   * Make notification from the DriveFS offline settings event.
+   */
+  std::unique_ptr<message_center::Notification>
+  MakeDriveConfirmDialogNotification(const extensions::Event& event,
+                                     base::Value::ListView& event_arguments);
+
+  /**
+   * Click handler for the removable device notification.
+   */
+  void HandleRemovableNotificationClick(const std::string& path,
+                                        absl::optional<int> button_index);
+
+  /**
+   * Makes a notification instance for removable devices.
+   */
+  std::unique_ptr<message_center::Notification> MakeRemovableNotification(
+      file_manager_private::MountCompletedEvent& event,
+      const Volume& volume);
+
+  /**
    * Helper function bound to notification instances that hides notifications.
    */
   void Dismiss(const std::string& notification_id);
@@ -99,6 +146,9 @@
   std::map<int, double> required_copy_space_;
 
   Profile* const profile_;
+  // Reference to non-owned DriveFS event router.
+  DriveFsEventRouter* drivefs_event_router_;
+
   // Caches the SWA feature flag.
   bool swa_enabled_;
   base::WeakPtrFactory<SystemNotificationManager> weak_ptr_factory_{this};
diff --git a/chrome/browser/chromeos/policy/DEPS b/chrome/browser/chromeos/policy/DEPS
deleted file mode 100644
index f18c9e9a..0000000
--- a/chrome/browser/chromeos/policy/DEPS
+++ /dev/null
@@ -1,13 +0,0 @@
-# TODO(https://crbug.com/1164001): When this file is edited, same file in
-# //chrome/browser/ash/policy should be updated as well. We need to sync
-# both files until the migration of //chrome/browser/chromeos/policy is done.
-include_rules = [
-  # Run
-  #
-  #   buildtools/checkdeps/checkdeps.py chrome/browser/chromeos/policy
-  #
-  # to test.
-  # Allow includes for shell-encryption and private_membership third_party libs.
-  "+third_party/private_membership",
-  "+third_party/shell-encryption",
-]
diff --git a/chrome/browser/chromeos/policy/DIR_METADATA b/chrome/browser/chromeos/policy/DIR_METADATA
deleted file mode 100644
index 650bca92..0000000
--- a/chrome/browser/chromeos/policy/DIR_METADATA
+++ /dev/null
@@ -1,6 +0,0 @@
-# TODO(https://crbug.com/1164001): When this file is edited, same file in
-# //chrome/browser/ash/policy should be updated as well. We need to sync
-# both files until the migration of //chrome/browser/chromeos/policy is done.
-monorail: {
-  component: "OS>Software>Enterprise"
-}
diff --git a/chrome/browser/chromeos/policy/OWNERS b/chrome/browser/chromeos/policy/OWNERS
deleted file mode 100644
index f5d20cd..0000000
--- a/chrome/browser/chromeos/policy/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# TODO(https://crbug.com/1164001): Share OWNERS until the migration of
-# //chrome/browser/chromeos/policy completes.
-file://chrome/browser/ash/policy/OWNERS
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index 16c7e30..4eba2c0 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -27,6 +27,7 @@
 #include "components/download/public/common/download_danger_type.h"
 #include "components/download/public/common/download_item.h"
 #include "components/download/public/common/download_path_reservation_tracker.h"
+#include "components/safe_browsing/buildflags.h"
 #include "content/public/browser/download_manager_delegate.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 18476c6..92da7da 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/download_protection/deep_scanning_request.h"
 #include "chrome/browser/safe_browsing/download_protection/download_feedback_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/download/public/common/download_danger_type.h"
diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
index f42bf4c..b65fdfe4 100644
--- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
+++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
@@ -36,6 +36,7 @@
 #include "chrome/browser/installable/installable_utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/ui/file_system_access_dialogs.h"
 #include "chrome/common/chrome_paths.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
diff --git a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java
index 8341627..1f5a39c 100644
--- a/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java
+++ b/chrome/browser/password_check/android/java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java
@@ -9,7 +9,6 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
-
 import androidx.fragment.app.DialogFragment;
 import androidx.preference.PreferenceFragmentCompat;
 import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
@@ -83,7 +82,9 @@
         // by the system.
         mComponentDelegate.onDestroyFragment();
         if (getActivity().isFinishing()
-                && mPasswordCheckReferrer == PasswordCheckReferrer.LEAK_DIALOG) {
+                && (mPasswordCheckReferrer == PasswordCheckReferrer.LEAK_DIALOG
+                        || mPasswordCheckReferrer
+                                == PasswordCheckReferrer.PHISHED_WARNING_DIALOG)) {
             mComponentDelegate.destroy();
         }
     }
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index dcf65ba4..180d0b7 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -747,11 +747,8 @@
   // achieved by attaching an observer (SafeBrowsingUserInteractionObserver) to
   // the current WebContents. Create an observer and attach it to simulate a
   // delayed warning.
-  auto safe_browsing_service =
-      base::MakeRefCounted<safe_browsing::TestSafeBrowsingService>();
   auto ui_manager =
-      base::MakeRefCounted<safe_browsing::TestSafeBrowsingUIManager>(
-          safe_browsing_service);
+      base::MakeRefCounted<safe_browsing::TestSafeBrowsingUIManager>();
   security_interstitials::UnsafeResource resource;
   safe_browsing::SafeBrowsingUserInteractionObserver::CreateForWebContents(
       test_web_contents.get(), resource, /* is_main_frame= */ true, ui_manager);
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 2f10fe8..8c156eb 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1268,7 +1268,7 @@
   ash::FamilyUserMetricsService::RegisterProfilePrefs(registry);
   ash::FamilyUserSessionMetrics::RegisterProfilePrefs(registry);
   chromeos::InlineLoginHandlerChromeOS::RegisterProfilePrefs(registry);
-  chromeos::first_run::RegisterProfilePrefs(registry);
+  ash::first_run::RegisterProfilePrefs(registry);
   ash::file_system_provider::RegisterProfilePrefs(registry);
   chromeos::full_restore::RegisterProfilePrefs(registry);
   ash::KerberosCredentialsManager::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 6ac28d92..366e22fa 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -57,6 +57,7 @@
       "chromeos:multidevice_setup_resources",
       "chromeos/accessibility:build",
       "chromeos/emoji_picker:resources",
+      "chromeos/enterprise_casting:resources",
       "chromeos/launcher_internals:resources",
       "chromeos/login:modulized_resources",
       "chromeos/login:resources",
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
index 4695c0f..b901c0a 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/BUILD.gn
@@ -83,6 +83,7 @@
   sources = [
     # These are end-to-end tests.
     "paragraph_utils_overflow_test.js",
+    "select_to_speak_enhanced_voices_test.js",
     "select_to_speak_keystroke_selection_test.js",
     "select_to_speak_mouse_selection_test.js",
     "select_to_speak_navigation_control_test.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/prefs_manager.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/prefs_manager.js
index 59d4554..fc7603fa 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/prefs_manager.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/prefs_manager.js
@@ -42,6 +42,9 @@
 
     /** @private {boolean} */
     this.enhancedNetworkVoicesEnabled_ = true;
+
+    /** @private {boolean} */
+    this.enhancedVoicesDialogShown_ = false;
   }
 
   /**
@@ -231,7 +234,8 @@
       chrome.storage.sync.get(
           [
             'voice', 'rate', 'pitch', 'wordHighlight', 'highlightColor',
-            'backgroundShading', 'navigationControls', 'enhancedNetworkVoices'
+            'backgroundShading', 'navigationControls', 'enhancedNetworkVoices',
+            'enhancedVoicesDialogShown'
           ],
           (prefs) => {
             if (prefs['voice']) {
@@ -267,6 +271,14 @@
                 'enhancedNetworkVoices': this.enhancedNetworkVoicesEnabled_
               });
             }
+            if (prefs['enhancedVoicesDialogShown'] !== undefined) {
+              this.enhancedVoicesDialogShown_ =
+                  prefs['enhancedVoicesDialogShown'];
+            } else {
+              chrome.storage.sync.set({
+                'enhancedVoicesDialogShown': this.enhancedVoicesDialogShown_
+              });
+            }
             if (prefs['rate'] && prefs['pitch']) {
               // Removes 'rate' and 'pitch' prefs after migrating data to global
               // TTS settings if appropriate.
@@ -372,6 +384,32 @@
   enhancedNetworkVoicesEnabled() {
     return this.enhancedNetworkVoicesEnabled_;
   }
+
+  /**
+   * Gets whether the initial popup authorizing enhanced network voices has been
+   * shown to the user or not.
+   *
+   * @returns {boolean} True if the initial popup dialog has been shown already.
+   */
+  enhancedVoicesDialogShown() {
+    return this.enhancedVoicesDialogShown_;
+  }
+
+  /**
+   * Sets whether enhanced network voices are enabled or not from initial popup.
+   * @param {boolean} enabled Specifies if the user enabled enhanced voices in
+   *     the popup.
+   */
+  setEnhancedNetworkVoicesFromDialog(enabled) {
+    if (enabled !== undefined) {
+      this.enhancedNetworkVoicesEnabled_ = enabled;
+      chrome.storage.sync.set(
+          {'enhancedNetworkVoices': this.enhancedNetworkVoicesEnabled_});
+      this.enhancedVoicesDialogShown_ = true;
+      chrome.storage.sync.set(
+          {'enhancedVoicesDialogShown': this.enhancedVoicesDialogShown_});
+    }
+  }
 }
 
 /**
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
index 7605bcb..5410df0 100644
--- a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak.js
@@ -192,6 +192,16 @@
           this.navigationControlFlag_ = result;
         });
 
+    /**
+     * Feature flag controlling availability of enhanced network voices
+     * @type {boolean}
+     */
+    this.enhancedVoicesFlag_ = false;
+    chrome.accessibilityPrivate.isFeatureEnabled(
+        AccessibilityFeature.ENHANCED_NETWORK_VOICES, (result) => {
+          this.enhancedVoicesFlag_ = result;
+        });
+
     /** @private {number} Default speech rate set in system settings. */
     this.systemSpeechRate_ = 1.0;
     chrome.settingsPrivate.getPref(SPEECH_RATE_KEY, (pref) => {
@@ -922,21 +932,23 @@
    */
   startSpeech_(text) {
     this.prepareForSpeech_(true /* clearFocusRing */);
-    const options = this.prefsManager_.speechOptions();
-    // Without nodes to anchor on, navigate is not supported.
-    this.supportsNavigationPanel_ = false;
-    options.onEvent = (event) => {
-      if (event.type === 'start') {
-        this.onStateChanged_(SelectToSpeakState.SPEAKING);
-        this.updateUi_();
-      } else if (
-          event.type === 'end' || event.type === 'interrupted' ||
-          event.type === 'cancelled') {
-        // Automatically dismiss when we're at the end.
-        this.onStateChanged_(SelectToSpeakState.INACTIVE);
-      }
-    };
-    this.ttsManager_.speak(text, options);
+    this.maybeShowEnhancedVoicesDialog_(() => {
+      const options = this.prefsManager_.speechOptions();
+      // Without nodes to anchor on, navigate is not supported.
+      this.supportsNavigationPanel_ = false;
+      options.onEvent = (event) => {
+        if (event.type === 'start') {
+          this.onStateChanged_(SelectToSpeakState.SPEAKING);
+          this.updateUi_();
+        } else if (
+            event.type === 'end' || event.type === 'interrupted' ||
+            event.type === 'cancelled') {
+          // Automatically dismiss when we're at the end.
+          this.onStateChanged_(SelectToSpeakState.INACTIVE);
+        }
+      };
+      this.ttsManager_.speak(text, options);
+    });
   }
 
   /**
@@ -958,37 +970,39 @@
    * @private
    */
   startSpeechQueue_(nodes, opt_params) {
-    const params = opt_params || {};
-    const clearFocusRing = params.clearFocusRing || false;
-    let startCharIndex = params.startCharIndex;
-    let endCharIndex = params.endCharIndex;
+    this.maybeShowEnhancedVoicesDialog_(() => {
+      const params = opt_params || {};
+      const clearFocusRing = params.clearFocusRing || false;
+      let startCharIndex = params.startCharIndex;
+      let endCharIndex = params.endCharIndex;
 
-    this.prepareForSpeech_(clearFocusRing /* clear the focus ring */);
+      this.prepareForSpeech_(clearFocusRing /* clear the focus ring */);
 
-    if (nodes.length === 0) {
-      return;
-    }
+      if (nodes.length === 0) {
+        return;
+      }
 
-    // Remember the original first and last node in the given list, as
-    // |startCharIndex| and |endCharIndex| pertain to them. If, after SVG
-    // resorting, the first or last nodes are re-ordered, do not clip them.
-    const originalFirstNode = nodes[0];
-    const originalLastNode = nodes[nodes.length - 1];
-    // Sort any SVG child nodes, if present, by visual reading order.
-    NodeUtils.sortSvgNodesByReadingOrder(nodes);
-    // Override start or end index if original nodes were sorted.
-    if (originalFirstNode !== nodes[0]) {
-      startCharIndex = undefined;
-    }
-    if (originalLastNode !== nodes[nodes.length - 1]) {
-      endCharIndex = undefined;
-    }
+      // Remember the original first and last node in the given list, as
+      // |startCharIndex| and |endCharIndex| pertain to them. If, after SVG
+      // resorting, the first or last nodes are re-ordered, do not clip them.
+      const originalFirstNode = nodes[0];
+      const originalLastNode = nodes[nodes.length - 1];
+      // Sort any SVG child nodes, if present, by visual reading order.
+      NodeUtils.sortSvgNodesByReadingOrder(nodes);
+      // Override start or end index if original nodes were sorted.
+      if (originalFirstNode !== nodes[0]) {
+        startCharIndex = undefined;
+      }
+      if (originalLastNode !== nodes[nodes.length - 1]) {
+        endCharIndex = undefined;
+      }
 
-    this.supportsNavigationPanel_ = this.isNavigationPanelSupported_(nodes);
-    this.updateNodeGroups_(nodes, startCharIndex, endCharIndex);
+      this.supportsNavigationPanel_ = this.isNavigationPanelSupported_(nodes);
+      this.updateNodeGroups_(nodes, startCharIndex, endCharIndex);
 
-    // Play TTS according to the current state variables.
-    this.startCurrentNodeGroup_();
+      // Play TTS according to the current state variables.
+      this.startCurrentNodeGroup_();
+    });
   }
 
   /**
@@ -1541,6 +1555,38 @@
   }
 
   /**
+   * Shows a dialog to the user on first-run after enhanced voices update,
+   * showing privacy disclaimer and asking if the user wants to turn on enhanced
+   * network voices.
+   *
+   * @param {function()} callback Called back after user has confirmed or
+   *     canceled in the dialog.
+   */
+  maybeShowEnhancedVoicesDialog_(callback) {
+    if (this.enhancedVoicesFlag_ &&
+        !this.prefsManager_.enhancedVoicesDialogShown()) {
+      // TODO(crbug.com/1230227): Style this dialog to match UX mocks.
+      const title =
+          chrome.i18n.getMessage('select_to_speak_natural_voice_dialog_title');
+      const description = chrome.i18n.getMessage(
+          'select_to_speak_natural_voice_dialog_description');
+      chrome.accessibilityPrivate.showConfirmationDialog(
+          title, description, (confirm) => {
+            this.prefsManager_.setEnhancedNetworkVoicesFromDialog(confirm);
+            if (callback !== undefined) {
+              callback();
+            }
+          });
+    } else {
+      // Flag not set or already shown, so we can continue the control flow
+      // synchronously.
+      if (callback !== undefined) {
+        callback();
+      }
+    }
+  }
+
+  /**
    * Updates the currently highlighted node word based on the current text
    * and the character index of an event.
    * @param {string} text The current text
diff --git a/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js
new file mode 100644
index 0000000..6814a53
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/select_to_speak/select_to_speak_enhanced_voices_test.js
@@ -0,0 +1,109 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+GEN_INCLUDE(['select_to_speak_e2e_test_base.js']);
+GEN_INCLUDE(['mock_tts.js']);
+
+SelectToSpeakEnhancedNetworkTtsVoicesTest = class extends SelectToSpeakE2ETest {
+  constructor() {
+    super();
+    this.mockTts = new MockTts();
+    chrome.tts = this.mockTts;
+    this.confirmationDialogShowCount_ = 0;
+    this.confirmationDialogResponse_ = true;
+
+    chrome.accessibilityPrivate.showConfirmationDialog =
+        (title, description, callback) => {
+          this.confirmationDialogShowCount_ += 1;
+          callback(this.confirmationDialogResponse_);
+        };
+  }
+
+  /** @override */
+  setUp() {
+    var runTest = this.deferRunTest(WhenTestDone.EXPECT);
+
+    (async () => {
+      await importModule(
+          'selectToSpeak', '/select_to_speak/select_to_speak_main.js');
+      await importModule(
+          'SelectToSpeakConstants',
+          '/select_to_speak/select_to_speak_constants.js');
+      await importModule('PrefsManager', '/select_to_speak/prefs_manager.js');
+
+      runTest();
+    })();
+  }
+
+  /** @override */
+  get featureList() {
+    return {enabled: ['features::kEnhancedNetworkVoices']};
+  }
+};
+
+TEST_F(
+    'SelectToSpeakEnhancedNetworkTtsVoicesTest',
+    'EnablesVoicesIfConfirmedInDialog', function() {
+      this.confirmationDialogResponse_ = true;
+
+      this.runWithLoadedTree(
+          'data:text/html;charset=utf-8,' +
+              '<p>This is some text</p>',
+          function(root) {
+            assertFalse(this.mockTts.currentlySpeaking());
+            assertEquals(this.mockTts.pendingUtterances().length, 0);
+            this.mockTts.setOnSpeechCallbacks([this.newCallback(function(
+                utterance) {
+              // Speech starts asynchronously.
+              assertEquals(this.confirmationDialogShowCount_, 1);
+              assertTrue(
+                  selectToSpeak.prefsManager_.enhancedVoicesDialogShown());
+              assertTrue(
+                  selectToSpeak.prefsManager_.enhancedNetworkVoicesEnabled());
+              assertTrue(this.mockTts.currentlySpeaking());
+              assertEquals(this.mockTts.pendingUtterances().length, 1);
+              this.assertEqualsCollapseWhitespace(
+                  this.mockTts.pendingUtterances()[0], 'This is some text');
+            })]);
+            const textNode = this.findTextNode(root, 'This is some text');
+            const event = {
+              screenX: textNode.location.left + 1,
+              screenY: textNode.location.top + 1
+            };
+            this.triggerReadMouseSelectedText(event, event);
+          });
+    });
+
+
+TEST_F(
+    'SelectToSpeakEnhancedNetworkTtsVoicesTest',
+    'DisablesVoicesIfCanceledInDialog', function() {
+      this.confirmationDialogResponse_ = false;
+      this.runWithLoadedTree(
+          'data:text/html;charset=utf-8,' +
+              '<p>This is some text</p>',
+          function(root) {
+            assertFalse(this.mockTts.currentlySpeaking());
+            assertEquals(this.mockTts.pendingUtterances().length, 0);
+            this.mockTts.setOnSpeechCallbacks([this.newCallback(function(
+                utterance) {
+              // Speech starts asynchronously.
+              assertEquals(this.confirmationDialogShowCount_, 1);
+              assertTrue(
+                  selectToSpeak.prefsManager_.enhancedVoicesDialogShown());
+              assertFalse(
+                  selectToSpeak.prefsManager_.enhancedNetworkVoicesEnabled());
+              assertTrue(this.mockTts.currentlySpeaking());
+              assertEquals(this.mockTts.pendingUtterances().length, 1);
+              this.assertEqualsCollapseWhitespace(
+                  this.mockTts.pendingUtterances()[0], 'This is some text');
+            })]);
+            const textNode = this.findTextNode(root, 'This is some text');
+            const event = {
+              screenX: textNode.location.left + 1,
+              screenY: textNode.location.top + 1
+            };
+            this.triggerReadMouseSelectedText(event, event);
+          });
+    });
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings.grdp b/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings.grdp
index 535be6b..b2eeb72 100644
--- a/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings.grdp
+++ b/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings.grdp
@@ -114,4 +114,10 @@
 <message desc="Sample text around which will be drawn a Select to Speak visual preview. This should be less than one line long." name="IDS_SELECT_TO_SPEAK_OPTIONS_SAMPLE_TEXT">
   The quick brown fox jumped over the lazy dog.
 </message>
+<message desc="Title of the dialog shown to users the first time they use Select to speak after the natural voices update." name="IDS_SELECT_TO_SPEAK_NATURAL_VOICE_DIALOG_TITLE">
+  Use natural voice?
+</message>
+<message desc="Content of the dialog shown to users the first time they use Select to speak after the natural voices update." name="IDS_SELECT_TO_SPEAK_NATURAL_VOICE_DIALOG_DESCRIPTION">
+  You can use a natural, human-like voice when your device is online. Text will be sent to Google for processing. You can turn this off any time in Settings.
+</message>
 </grit-part>
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings_grdp/IDS_SELECT_TO_SPEAK_NATURAL_VOICE_DIALOG_DESCRIPTION.png.sha1 b/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings_grdp/IDS_SELECT_TO_SPEAK_NATURAL_VOICE_DIALOG_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..171da66
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings_grdp/IDS_SELECT_TO_SPEAK_NATURAL_VOICE_DIALOG_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+1b6f00e02d27c97116c0731d3d62cbc76b6780b3
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings_grdp/IDS_SELECT_TO_SPEAK_NATURAL_VOICE_DIALOG_TITLE.png.sha1 b/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings_grdp/IDS_SELECT_TO_SPEAK_NATURAL_VOICE_DIALOG_TITLE.png.sha1
new file mode 100644
index 0000000..171da66
--- /dev/null
+++ b/chrome/browser/resources/chromeos/accessibility/strings/select_to_speak_strings_grdp/IDS_SELECT_TO_SPEAK_NATURAL_VOICE_DIALOG_TITLE.png.sha1
@@ -0,0 +1 @@
+1b6f00e02d27c97116c0731d3d62cbc76b6780b3
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.html b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.html
index 4513bc5..e9b397f 100644
--- a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.html
+++ b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.html
@@ -5,7 +5,9 @@
     width: 100%;
   }
 </style>
-<bluetooth-dialog id="deviceDialog" no-cancel on-close="onDialogClose_"
-    pairing-device="[[pairingDevice_]]"
-    dialog-title="$i18n{bluetoothPairDeviceTitle}">
-</bluetooth-dialog>
+<template is="dom-if" if="[[!isBluetoothRevampEnabled_]]" restamp>
+  <bluetooth-dialog id="deviceDialog" no-cancel on-close="onDialogClose_"
+      pairing-device="[[pairingDevice_]]"
+      dialog-title="$i18n{bluetoothPairDeviceTitle}">
+  </bluetooth-dialog>
+</template>
diff --git a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.js b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.js
index 717aeaa..3d5c4c6 100644
--- a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.js
+++ b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/bluetooth_pairing_dialog.js
@@ -8,8 +8,9 @@
 import 'chrome://resources/cr_elements/cr_page_host_style_css.js';
 import './strings.m.js';
 
+import {loadTimeData} from '//resources/js/load_time_data.m.js';
 import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
-import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {afterNextRender, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 /**
  * @fileoverview
@@ -34,21 +35,38 @@
      * @private
      */
     pairingDevice_: Object,
+
+    /** @private */
+    isBluetoothRevampEnabled_: {
+      type: Boolean,
+      value() {
+        return loadTimeData.getBoolean('enableBluetoothRevamp');
+      }
+    },
   },
 
   /** @override */
   attached() {
+    if (this.isBluetoothRevampEnabled_) {
+      // TODO(crbug.com/1010321): Add revamp Bluetooth init logic here.
+      return;
+    }
+
     let dialogArgs = chrome.getVariableValue('dialogArguments');
     if (!dialogArgs) {
       // This situation currently only occurs if the user navigates to the debug
       // chrome://bluetooth-pairing.
       console.warn('No arguments were provided to the dialog.');
-      this.$.deviceDialog.open();
+
+      // Wait for next render or deviceDialog has not been created yet.
+      afterNextRender(this, () => this.$$('#deviceDialog').open());
       return;
     }
 
     let parsedDialogArgs = JSON.parse(dialogArgs);
-    this.connect_(parsedDialogArgs.address);
+
+    // Wait for next render or deviceDialog has not been created yet.
+    afterNextRender(this, () => this.connect_(parsedDialogArgs.address));
   },
 
   /**
@@ -56,12 +74,12 @@
    * @private
    */
   connect_(address) {
-    this.$.deviceDialog.open();
+    this.$$('#deviceDialog').open();
 
     chrome.bluetooth.getDevice(address, device => {
       this.pairingDevice_ = device;
       chrome.bluetoothPrivate.connect(address, result => {
-        var dialog = this.$.deviceDialog;
+        var dialog = this.$$('#deviceDialog');
         dialog.endConnectionAttempt(
             this.pairingDevice_, true /* wasPairing */,
             chrome.runtime.lastError, result);
diff --git a/chrome/browser/resources/chromeos/enterprise_casting/BUILD.gn b/chrome/browser/resources/chromeos/enterprise_casting/BUILD.gn
new file mode 100644
index 0000000..14d4854
--- /dev/null
+++ b/chrome/browser/resources/chromeos/enterprise_casting/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2021 The Chromium 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("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/grit_rule.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+assert(is_chromeos, "enterprise_casting is Chrome OS only.")
+
+mojo_grdp_file = "$target_gen_dir/mojo_resources.grdp"
+resources_grd_file = "$target_gen_dir/resources.grd"
+
+generate_grd("build_mojo_grdp") {
+  input_files = [ "enterprise_casting.mojom-webui.js" ]
+  input_files_base_dir = rebase_path(
+          "${root_gen_dir}/mojom-webui/chrome/browser/ui/webui/chromeos/enterprise_casting",
+          "$root_build_dir")
+  deps = [ "//chrome/browser/ui/webui/chromeos/enterprise_casting:mojo_bindings_webui_js" ]
+
+  grd_prefix = "enterprise_casting"
+  out_grd = mojo_grdp_file
+}
+
+generate_grd("build_grd") {
+  input_files = [ "index.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":build_mojo_grdp" ]
+  grdp_files = [ mojo_grdp_file ]
+
+  grd_prefix = "enterprise_casting"
+  out_grd = resources_grd_file
+}
+
+grit("resources") {
+  # These arguments are needed since the grd is generated at build time.
+  enable_input_discovery_for_gn_analyze = false
+  source = resources_grd_file
+  deps = [ ":build_grd" ]
+
+  outputs = [
+    "grit/enterprise_casting_resources.h",
+    "grit/enterprise_casting_resources_map.cc",
+    "grit/enterprise_casting_resources_map.h",
+    "enterprise_casting_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/chrome"
+}
diff --git a/chrome/browser/resources/chromeos/enterprise_casting/index.html b/chrome/browser/resources/chromeos/enterprise_casting/index.html
new file mode 100644
index 0000000..d61adc5
--- /dev/null
+++ b/chrome/browser/resources/chromeos/enterprise_casting/index.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="utf-8">
+  <title>Cast Receiver</title>
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+</head>
+
+<body>
+  enterprise_casting Skeleton
+</body>
+
+</html>
diff --git a/chrome/browser/resources/downloads/item.html b/chrome/browser/resources/downloads/item.html
index 577f8a9..6ec3a75 100644
--- a/chrome/browser/resources/downloads/item.html
+++ b/chrome/browser/resources/downloads/item.html
@@ -42,7 +42,6 @@
     flex: none;
     margin: 6px auto;
     min-height: 103px;
-    position: relative;
     width: var(--downloads-card-width);
   }
 
@@ -169,10 +168,6 @@
     max-width: 100%;
   }
 
-  div[role='gridcell'] {
-    display: inline;
-  }
-
   #name,
   #file-link {
     font-weight: 500;
@@ -253,6 +248,10 @@
     color: var(--controlled-by-active-link-color);
   }
 
+  .more-options {
+    display: flex;
+    flex-direction: column;
+  }
 
   cr-icon-button {
     --cr-icon-button-icon-size: 16px;
@@ -262,11 +261,12 @@
 
   #incognito {
     -webkit-mask-image: url(images/incognito_marker.svg);
+    align-self: flex-end;
     background-color: var(--cr-secondary-text-color);
-    bottom: 20px;
     height: 16px;
-    position: absolute;
-    right: 16px;
+    margin-block-end: 20px;
+    margin-block-start: auto;
+    margin-inline-end: 16px;
     width: 16px;
   }
 
@@ -341,42 +341,42 @@
     </template>
 
     <div id="safe" class="controls" hidden="[[isDangerous_]]">
-      <div role="gridcell">
+      <span role="gridcell" hidden="[[!hasShowInFolderLink_]]">
         <a is="action-link" id="show" on-click="onShowTap_"
-            hidden="[[!hasShowInFolderLink_]]" focus-row-control
+            focus-row-control
             focus-type="show">[[data.showInFolderText]]</a>
-      </div>
+      </span>
       <template is="dom-if" if="[[data.retry]]">
-        <div role="gridcell">
+        <span role="gridcell">
           <cr-button class="action-button" on-click="onRetryTap_"
               focus-row-control focus-type="retry">
             $i18n{controlRetry}
           </cr-button>
-        </div>
+        </span>
       </template>
       <template is="dom-if" if="[[pauseOrResumeText_]]">
-        <div role="gridcell">
+        <span role="gridcell">
           <cr-button on-click="onPauseOrResumeTap_" id="pauseOrResume"
               focus-row-control focus-type="pauseOrResume">
             [[pauseOrResumeText_]]
           </cr-button>
-        </div>
+        </span>
       </template>
       <template is="dom-if" if="[[showOpenNow_]]" restamp>
-        <div role="gridcell">
+        <span role="gridcell">
           <cr-button on-click="onOpenNowTap_" id="openNow" class="action-button"
                      focus-row-control focus-type="open">
             $i18n{controlOpenNow}
           </cr-button>
-        </div>
+        </span>
       </template>
       <template is="dom-if" if="[[showCancel_]]">
-        <div role="gridcell">
+        <span role="gridcell">
           <cr-button on-click="onCancelTap_" focus-row-control
               focus-type="cancel">
             $i18n{controlCancel}
           </cr-button>
-        </div>
+        </span>
       </template>
       <span id="controlled-by"><!-- Text populated dynamically. --></span>
     </div>
@@ -385,43 +385,44 @@
       <div id="dangerous" class="controls">
         <!-- Dangerous file types (e.g. .exe, .jar). -->
         <template is="dom-if" if="[[!isMalware_]]">
-          <div role="gridcell">
+          <span role="gridcell">
             <cr-button on-click="onDiscardDangerousTap_"
                 class="action-button" focus-row-control
                 focus-type="discard">$i18n{dangerDiscard}</cr-button>
-          </div>
-          <div role="gridcell">
+          </span>
+          <span role="gridcell">
             <cr-button on-click="onSaveDangerousTap_" focus-row-control
                 focus-type="save">
               $i18n{dangerSave}</cr-button>
-          </div>
+          </span>
         </template>
 
         <!-- Things that safe browsing has determined to be dangerous. -->
         <template is="dom-if" if="[[isMalware_]]">
-          <div role="gridcell">
+          <span role="gridcell">
             <cr-button on-click="onDiscardDangerousTap_"
                 class="action-button"
                 focus-row-control focus-type="discard">
               $i18n{controlRemoveFromList}</cr-button>
-          </div>
-          <div role="gridcell">
+          </span>
+          <span role="gridcell">
             <cr-button on-click="onSaveDangerousTap_" focus-row-control
                 focus-type="save">
               $i18n{dangerRestore}</cr-button>
-          </div>
+          </span>
         </template>
       </div>
     </template>
   </div>
-  <div role="gridcell">
-    <cr-icon-button class="icon-clear"
-        style$="[[computeRemoveStyle_(isDangerous_, showCancel_)]]"
-        id="remove" title="$i18n{controlRemoveFromList}"
-        aria-label$="[[controlRemoveFromListAriaLabel_]]"
-        on-click="onRemoveTap_" focus-row-control focus-type="remove">
-    </cr-icon-button>
-  </div>
-  <div id="incognito" title="$i18n{inIncognito}" hidden="[[!data.otr]]">
+  <div class="more-options">
+    <div role="gridcell">
+      <cr-icon-button class="icon-clear"
+          style$="[[computeRemoveStyle_(isDangerous_, showCancel_)]]"
+          id="remove" title="$i18n{controlRemoveFromList}"
+          aria-label$="[[controlRemoveFromListAriaLabel_]]"
+          on-click="onRemoveTap_" focus-row-control focus-type="remove">
+      </cr-icon-button>
+    </div>
+    <div id="incognito" title="$i18n{inIncognito}" hidden="[[!data.otr]]"></div>
   </div>
 </div>
diff --git a/chrome/browser/resources/new_tab_page/icons/BUILD.gn b/chrome/browser/resources/new_tab_page/icons/BUILD.gn
index eb88ea8..c0cf6e1 100644
--- a/chrome/browser/resources/new_tab_page/icons/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/icons/BUILD.gn
@@ -16,6 +16,7 @@
     "colored_header.svg",
     "colors.svg",
     "copy.svg",
+    "drive_logo.svg",
     "facebook.svg",
     "generic_globe.svg",
     "google_logo.svg",
diff --git a/chrome/browser/resources/new_tab_page/realbox/icons/drive_logo.svg b/chrome/browser/resources/new_tab_page/icons/drive_logo.svg
similarity index 100%
rename from chrome/browser/resources/new_tab_page/realbox/icons/drive_logo.svg
rename to chrome/browser/resources/new_tab_page/icons/drive_logo.svg
diff --git a/chrome/browser/resources/new_tab_page/modules/drive_v2/BUILD.gn b/chrome/browser/resources/new_tab_page/modules/drive_v2/BUILD.gn
index f1fca89..ee729189 100644
--- a/chrome/browser/resources/new_tab_page/modules/drive_v2/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/modules/drive_v2/BUILD.gn
@@ -8,6 +8,7 @@
 js_library("module") {
   deps = [
     "..:module_descriptor",
+    "../..:i18n_setup",
     "//chrome/browser/resources/new_tab_page/modules/drive:drive_module_proxy",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
diff --git a/chrome/browser/resources/new_tab_page/modules/drive_v2/module.html b/chrome/browser/resources/new_tab_page/modules/drive_v2/module.html
index e1f5898..b1472e2 100644
--- a/chrome/browser/resources/new_tab_page/modules/drive_v2/module.html
+++ b/chrome/browser/resources/new_tab_page/modules/drive_v2/module.html
@@ -6,11 +6,14 @@
     width: 100%;
   }
 
+  ntp-module-header {
+    margin-bottom: 8px;
+  }
+
   #files {
     display: flex;
     flex-direction: column;
     margin-bottom: 12px;
-    margin-top: 15px;
   }
 
   .file:hover {
@@ -69,6 +72,17 @@
     width: 24px;
   }
 </style>
+<ntp-module-header
+    show-dismiss-button show-info-button-dropdown
+    dismiss-text="[[i18nRecursive('',
+                                  'modulesDismissButtonText',
+                                  'modulesDriveFilesLower')]]"
+    disable-text="[[i18nRecursive('',
+                                  'modulesDisableButtonText',
+                                  'modulesDriveSentence2')]]"
+    icon-src="icons/drive_logo.svg">
+  [[i18n('modulesDriveTitle')]]
+</ntp-module-header>
 <div id="files">
   <template id="fileRepeat" is="dom-repeat" items="[[files]]">
     <a class="file" href="[[item.itemUrl.url]]">
diff --git a/chrome/browser/resources/new_tab_page/modules/drive_v2/module.js b/chrome/browser/resources/new_tab_page/modules/drive_v2/module.js
index 65f06c58..01d483dc69 100644
--- a/chrome/browser/resources/new_tab_page/modules/drive_v2/module.js
+++ b/chrome/browser/resources/new_tab_page/modules/drive_v2/module.js
@@ -2,13 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import '../module_header.js';
 
-import {loadTimeData} from '../../i18n_setup.js';
+import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {I18nBehavior, loadTimeData} from '../../i18n_setup.js';
 import {DriveProxy} from '../drive/drive_module_proxy.js';
 import {ModuleDescriptor} from '../module_descriptor.js';
 
-class DriveModuleElement extends PolymerElement {
+/**
+ * The Drive module, which serves as an inside look in to recent activity within
+ * a user's Google Drive.
+ * @polymer
+ * @extends {PolymerElement}
+ */
+class DriveModuleElement extends mixinBehaviors
+([I18nBehavior], PolymerElement) {
   static get is() {
     return 'ntp-drive-module-redesigned';
   }
diff --git a/chrome/browser/resources/new_tab_page/modules/module_header.html b/chrome/browser/resources/new_tab_page/modules/module_header.html
index 6aad5dd..b758568 100644
--- a/chrome/browser/resources/new_tab_page/modules/module_header.html
+++ b/chrome/browser/resources/new_tab_page/modules/module_header.html
@@ -11,6 +11,22 @@
     height: 22px;
   }
 
+  .icon-background {
+    align-items: center;
+    background-color: var(--ntp-module-scroll-button-color);
+    border-radius: 50%;
+    display: flex;
+    height: 18px;
+    justify-content: center;
+    margin-inline-end: 8px;
+    width: 18px;
+  }
+
+  .module-icon {
+    height: 10px;
+    width: 10px;
+  }
+
   #title {
     color: var(--cr-primary-text-color);
     font-size: 15px;
@@ -44,6 +60,21 @@
     margin-inline-end: -10px;
   }
 
+  :host([modules-redesigned-enabled_]) #menuButton {
+    background-color: var(--ntp-module-scroll-button-color);
+    height: 18px;
+    margin: 0;
+    width: 18px;
+  }
+
+  :host([modules-redesigned-enabled_]) #menuButton:hover {
+    background-color: var(--ntp-module-scroll-button-hover-color);
+  }
+
+  :host([modules-redesigned-enabled_]) .dropdown-item {
+    font-size: 13px;
+  }
+
   #description {
     color: var(--cr-secondary-text-color);
     font-size: 12px;
@@ -52,6 +83,11 @@
   }
 </style>
 <div id="titleContainer">
+  <template is="dom-if" if="[[iconSrc]]">
+    <div class="icon-background">
+      <img class="module-icon" src="[[iconSrc]]"></img>
+    </div>
+  </template>
   <span id="title"><slot></slot></span>
   <template is="dom-if" if="[[chipText]]">
     <div id="chip">[[chipText]]</div>
@@ -84,4 +120,9 @@
       on-click="onCustomizeButtonClick_">
     [[i18n('modulesCustomizeButtonText')]]
   </button>
+  <template is="dom-if" if="[[showInfoButtonDropdown]]">
+    <button id="infoButton" class="dropdown-item">
+      [[i18n('moduleInfoButtonTitle')]]
+    </button>
+  </template>
 </cr-action-menu>
diff --git a/chrome/browser/resources/new_tab_page/modules/module_header.js b/chrome/browser/resources/new_tab_page/modules/module_header.js
index 6d75558..8f282845 100644
--- a/chrome/browser/resources/new_tab_page/modules/module_header.js
+++ b/chrome/browser/resources/new_tab_page/modules/module_header.js
@@ -6,7 +6,7 @@
 
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-import {I18nBehavior} from '../i18n_setup.js';
+import {I18nBehavior, loadTimeData} from '../i18n_setup.js';
 
 /**
  * Element that displays a header inside a module.
@@ -26,6 +26,12 @@
   static get properties() {
     return {
       /**
+       * The src for the icon showing on the header.
+       * @type {string}
+       */
+      iconSrc: String,
+
+      /**
        * The chip text showing on the header.
        * @type {string}
        */
@@ -47,6 +53,17 @@
       },
 
       /**
+       * True if the redesigned modules are enabled. Will put the info
+       * button in the action menu dropdown instead of separate button next to
+       * the action menu.
+       * @type {boolean}
+       */
+      showInfoButtonDropdown: {
+        type: Boolean,
+        value: false,
+      },
+
+      /**
        * True if the header should display a dismiss button.
        * @type {boolean}
        */
@@ -60,6 +77,13 @@
 
       /** @type {string} */
       disableText: String,
+
+      /** @private */
+      modulesRedesignedEnabled_: {
+        type: Boolean,
+        value: () => loadTimeData.getBoolean('modulesRedesignedEnabled'),
+        reflectToAttribute: true,
+      },
     };
   }
 
diff --git a/chrome/browser/resources/new_tab_page/realbox/icons/BUILD.gn b/chrome/browser/resources/new_tab_page/realbox/icons/BUILD.gn
index d0865aa..2f4928e 100644
--- a/chrome/browser/resources/new_tab_page/realbox/icons/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/realbox/icons/BUILD.gn
@@ -14,7 +14,6 @@
     "drive_folder.svg",
     "drive_form.svg",
     "drive_image.svg",
-    "drive_logo.svg",
     "drive_pdf.svg",
     "drive_sheets.svg",
     "drive_slides.svg",
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index 45786b6..0c0dbd9 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -308,14 +308,9 @@
     StringProvider sync_password_hash_provider =
         base::BindLambdaForTesting([=] { return sync_password_hash; });
 
-    // TODO(crbug/925153): Port consumers of the SafeBrowsingService
-    // to use the interface in components/safe_browsing, and remove this
-    // cast.
     return std::make_unique<MockChromePasswordProtectionService>(
         profile(),
         new SafeBrowsingUIManager(
-            static_cast<safe_browsing::SafeBrowsingService*>(
-                SafeBrowsingService::CreateSafeBrowsingService()),
             std::make_unique<ChromeSafeBrowsingUIManagerDelegate>(),
             std::make_unique<ChromeSafeBrowsingBlockingPageFactory>(),
             GURL(chrome::kChromeUINewTabURL)),
diff --git a/chrome/browser/safe_browsing/chrome_ui_manager_delegate.cc b/chrome/browser/safe_browsing/chrome_ui_manager_delegate.cc
index 5848801..107687b 100644
--- a/chrome/browser/safe_browsing/chrome_ui_manager_delegate.cc
+++ b/chrome/browser/safe_browsing/chrome_ui_manager_delegate.cc
@@ -10,7 +10,9 @@
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "content/public/browser/web_contents.h"
+#include "services/network/public/cpp/cross_thread_pending_shared_url_loader_factory.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "extensions/browser/process_manager.h"
@@ -83,6 +85,17 @@
       ServiceAccessType::EXPLICIT_ACCESS);
 }
 
+PingManager* ChromeSafeBrowsingUIManagerDelegate::GetPingManagerIfExists() {
+  return g_browser_process->safe_browsing_service()->ping_manager();
+}
+
+scoped_refptr<network::SharedURLLoaderFactory>
+ChromeSafeBrowsingUIManagerDelegate::GetURLLoaderFactory(
+    content::BrowserContext* browser_context) {
+  return g_browser_process->safe_browsing_service()->GetURLLoaderFactory(
+      browser_context);
+}
+
 bool ChromeSafeBrowsingUIManagerDelegate::IsMetricsAndCrashReportingEnabled() {
   return ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled();
 }
diff --git a/chrome/browser/safe_browsing/chrome_ui_manager_delegate.h b/chrome/browser/safe_browsing/chrome_ui_manager_delegate.h
index 8d34be8..a960530 100644
--- a/chrome/browser/safe_browsing/chrome_ui_manager_delegate.h
+++ b/chrome/browser/safe_browsing/chrome_ui_manager_delegate.h
@@ -39,6 +39,9 @@
   PrefService* GetPrefs(content::BrowserContext* browser_context) override;
   history::HistoryService* GetHistoryService(
       content::BrowserContext* browser_context) override;
+  PingManager* GetPingManagerIfExists() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory(
+      content::BrowserContext* browser_context) override;
   bool IsMetricsAndCrashReportingEnabled() override;
 };
 
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc b/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc
index 533d6b3..98e99b4 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h"
 #include "chrome/browser/safe_browsing/chrome_ui_manager_delegate.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -79,7 +80,6 @@
  public:
   MockSafeBrowsingUIManager()
       : SafeBrowsingUIManager(
-            nullptr,
             std::make_unique<ChromeSafeBrowsingUIManagerDelegate>(),
             std::make_unique<ChromeSafeBrowsingBlockingPageFactory>(),
             GURL(chrome::kChromeUINewTabURL)) {}
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
index 2fe3db7..54ecb35 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -150,9 +150,8 @@
 
 class MockSafeBrowsingUIManager : public SafeBrowsingUIManager {
  public:
-  explicit MockSafeBrowsingUIManager(SafeBrowsingService* service)
+  MockSafeBrowsingUIManager()
       : SafeBrowsingUIManager(
-            service,
             std::make_unique<ChromeSafeBrowsingUIManagerDelegate>(),
             std::make_unique<ChromeSafeBrowsingBlockingPageFactory>(),
             GURL(chrome::kChromeUINewTabURL)) {}
@@ -323,11 +322,7 @@
     // Inject service classes.
     csd_service_ = std::make_unique<MockClientSideDetectionService>();
     database_manager_ = new StrictMock<MockSafeBrowsingDatabaseManager>();
-    ui_manager_ = new StrictMock<MockSafeBrowsingUIManager>(
-        // TODO(crbug/925153): Port consumers of the SafeBrowsingService to
-        // use the interface in components/safe_browsing, and remove this cast.
-        static_cast<safe_browsing::SafeBrowsingService*>(
-            SafeBrowsingService::CreateSafeBrowsingService()));
+    ui_manager_ = new StrictMock<MockSafeBrowsingUIManager>();
 
     identity_test_env_.MakePrimaryAccountAvailable("user@gmail.com",
                                                    signin::ConsentLevel::kSync);
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
index e5eb6e74..b243a31 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/safe_browsing/download_protection/download_url_sb_client.h"
 #include "chrome/browser/safe_browsing/download_protection/ppapi_download_request.h"
 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager_factory.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/services_delegate.h"
 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
 #include "chrome/common/safe_browsing/download_type_util.h"
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index 802fa35..a9b5b36 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -279,7 +279,7 @@
 
 SafeBrowsingUIManager* SafeBrowsingService::CreateUIManager() {
   return new SafeBrowsingUIManager(
-      this, std::make_unique<ChromeSafeBrowsingUIManagerDelegate>(),
+      std::make_unique<ChromeSafeBrowsingUIManagerDelegate>(),
       std::make_unique<ChromeSafeBrowsingBlockingPageFactory>(),
       GURL(chrome::kChromeUINewTabURL));
 }
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_service.cc b/chrome/browser/safe_browsing/test_safe_browsing_service.cc
index 745e369..6e90411 100644
--- a/chrome/browser/safe_browsing/test_safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/test_safe_browsing_service.cc
@@ -76,7 +76,6 @@
 
 void TestSafeBrowsingService::SetUIManager(
     TestSafeBrowsingUIManager* ui_manager) {
-  ui_manager->SetSafeBrowsingService(this);
   ui_manager_ = ui_manager;
 }
 
@@ -202,15 +201,6 @@
 // TestSafeBrowsingUIManager functions:
 TestSafeBrowsingUIManager::TestSafeBrowsingUIManager()
     : SafeBrowsingUIManager(
-          nullptr,
-          std::make_unique<ChromeSafeBrowsingUIManagerDelegate>(),
-          std::make_unique<ChromeSafeBrowsingBlockingPageFactory>(),
-          GURL(chrome::kChromeUINewTabURL)) {}
-
-TestSafeBrowsingUIManager::TestSafeBrowsingUIManager(
-    const scoped_refptr<SafeBrowsingService>& service)
-    : SafeBrowsingUIManager(
-          service,
           std::make_unique<ChromeSafeBrowsingUIManagerDelegate>(),
           std::make_unique<ChromeSafeBrowsingBlockingPageFactory>(),
           GURL(chrome::kChromeUINewTabURL)) {}
@@ -218,16 +208,10 @@
 TestSafeBrowsingUIManager::TestSafeBrowsingUIManager(
     std::unique_ptr<SafeBrowsingBlockingPageFactory> blocking_page_factory)
     : SafeBrowsingUIManager(
-          nullptr,
           std::make_unique<ChromeSafeBrowsingUIManagerDelegate>(),
           std::move(blocking_page_factory),
           GURL(chrome::kChromeUINewTabURL)) {}
 
-void TestSafeBrowsingUIManager::SetSafeBrowsingService(
-    SafeBrowsingService* sb_service) {
-  sb_service_ = sb_service;
-}
-
 void TestSafeBrowsingUIManager::SendSerializedThreatDetails(
     content::BrowserContext* browser_context,
     const std::string& serialized) {
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_service.h b/chrome/browser/safe_browsing/test_safe_browsing_service.h
index 2719b9e9..846795e 100644
--- a/chrome/browser/safe_browsing/test_safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/test_safe_browsing_service.h
@@ -147,12 +147,9 @@
  public:
   TestSafeBrowsingUIManager();
   explicit TestSafeBrowsingUIManager(
-      const scoped_refptr<SafeBrowsingService>& service);
-  explicit TestSafeBrowsingUIManager(
       std::unique_ptr<SafeBrowsingBlockingPageFactory> blocking_page_factory);
   void SendSerializedThreatDetails(content::BrowserContext* browser_context,
                                    const std::string& serialized) override;
-  void SetSafeBrowsingService(SafeBrowsingService* sb_service);
   std::list<std::string>* GetThreatDetails();
 
  protected:
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
index f063226..fdbcd3c 100644
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -165,7 +165,6 @@
   // The safe browsing UI manager does not need a service for this test.
   MockSafeBrowsingUIManager()
       : SafeBrowsingUIManager(
-            nullptr,
             std::make_unique<ChromeSafeBrowsingUIManagerDelegate>(),
             std::make_unique<ChromeSafeBrowsingBlockingPageFactory>(),
             GURL(chrome::kChromeUINewTabURL)),
diff --git a/chrome/browser/safe_browsing/ui_manager.cc b/chrome/browser/safe_browsing/ui_manager.cc
index bd3a299..9b62d36 100644
--- a/chrome/browser/safe_browsing/ui_manager.cc
+++ b/chrome/browser/safe_browsing/ui_manager.cc
@@ -10,7 +10,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
-#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/safe_browsing_subresource_tab_helper.h"
 #include "components/no_state_prefetch/browser/no_state_prefetch_contents.h"
 #include "components/prefs/pref_service.h"
@@ -23,6 +22,7 @@
 #include "components/security_interstitials/content/security_interstitial_tab_helper.h"
 #include "components/security_interstitials/content/unsafe_resource_util.h"
 #include "components/security_interstitials/core/unsafe_resource.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_entry.h"
@@ -40,12 +40,10 @@
 namespace safe_browsing {
 
 SafeBrowsingUIManager::SafeBrowsingUIManager(
-    const scoped_refptr<SafeBrowsingService>& service,
     std::unique_ptr<Delegate> delegate,
     std::unique_ptr<SafeBrowsingBlockingPageFactory> blocking_page_factory,
     const GURL& default_safe_page)
-    : sb_service_(service),
-      delegate_(std::move(delegate)),
+    : delegate_(std::move(delegate)),
       blocking_page_factory_(std::move(blocking_page_factory)),
       default_safe_page_(default_safe_page) {}
 
@@ -56,12 +54,6 @@
 
   if (shutdown) {
     shut_down_ = true;
-
-    // Tests require this variable to be nulled out to avoid errors due to mocks
-    // being leaked.
-    // TODO(crbug.com/1226567): Eliminate the need for this as part of
-    // eliminating this class' dependence on SafeBrowsingService altogether.
-    sb_service_ = nullptr;
   }
 }
 
@@ -178,14 +170,14 @@
 
   // The service may delete the ping manager (i.e. when user disabling service,
   // etc). This happens on the IO thread.
-  if (shut_down_ || !sb_service_->ping_manager())
+  if (shut_down_ || !delegate_->GetPingManagerIfExists())
     return;
 
   DVLOG(1) << "ReportSafeBrowsingHit: " << hit_report.malicious_url << " "
            << hit_report.page_url << " " << hit_report.referrer_url << " "
            << hit_report.is_subresource << " " << hit_report.threat_type;
-  sb_service_->ping_manager()->ReportSafeBrowsingHit(
-      sb_service_->GetURLLoaderFactory(web_contents->GetBrowserContext()),
+  delegate_->GetPingManagerIfExists()->ReportSafeBrowsingHit(
+      delegate_->GetURLLoaderFactory(web_contents->GetBrowserContext()),
       hit_report);
 }
 
@@ -270,13 +262,13 @@
 
   // The service may delete the ping manager (i.e. when user disabling service,
   // etc). This happens on the IO thread.
-  if (shut_down_ || !sb_service_->ping_manager())
+  if (shut_down_ || !delegate_->GetPingManagerIfExists())
     return;
 
   if (!serialized.empty()) {
     DVLOG(1) << "Sending serialized threat details.";
-    sb_service_->ping_manager()->ReportThreatDetails(
-        sb_service_->GetURLLoaderFactory(browser_context), serialized);
+    delegate_->GetPingManagerIfExists()->ReportThreatDetails(
+        delegate_->GetURLLoaderFactory(browser_context), serialized);
   }
 }
 
diff --git a/chrome/browser/safe_browsing/ui_manager.h b/chrome/browser/safe_browsing/ui_manager.h
index d1fa2a65..fad28ae 100644
--- a/chrome/browser/safe_browsing/ui_manager.h
+++ b/chrome/browser/safe_browsing/ui_manager.h
@@ -14,7 +14,6 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
-#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "components/safe_browsing/content/browser/base_ui_manager.h"
 #include "components/safe_browsing/content/browser/safe_browsing_blocking_page_factory.h"
 #include "components/security_interstitials/core/unsafe_resource.h"
@@ -36,6 +35,7 @@
 namespace safe_browsing {
 
 class BaseBlockingPage;
+class PingManager;
 
 struct HitReport;
 
@@ -108,12 +108,19 @@
     virtual history::HistoryService* GetHistoryService(
         content::BrowserContext* browser_context) = 0;
 
+    // Gets the PingManager. This may be null.
+    virtual PingManager* GetPingManagerIfExists() = 0;
+
+    // Gets the URLLoaderFactory attached to |browser_context|. Guaranteed to be
+    // non-null if GetPingManagerIfExists() is non-null.
+    virtual scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory(
+        content::BrowserContext* browser_context) = 0;
+
     // Returns true if metrics reporting is enabled.
     virtual bool IsMetricsAndCrashReportingEnabled() = 0;
   };
 
   SafeBrowsingUIManager(
-      const scoped_refptr<SafeBrowsingService>& service,
       std::unique_ptr<Delegate> delegate,
       std::unique_ptr<SafeBrowsingBlockingPageFactory> blocking_page_factory,
       const GURL& default_safe_page);
@@ -195,9 +202,6 @@
       const GURL& blocked_url,
       const UnsafeResource& unsafe_resource) override;
 
-  // Safebrowsing service.
-  scoped_refptr<SafeBrowsingService> sb_service_;
-
   std::unique_ptr<Delegate> delegate_;
 
   std::unique_ptr<SafeBrowsingBlockingPageFactory> blocking_page_factory_;
diff --git a/chrome/browser/safe_browsing/ui_manager_unittest.cc b/chrome/browser/safe_browsing/ui_manager_unittest.cc
index 33b37d7..3a95ac18 100644
--- a/chrome/browser/safe_browsing/ui_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/ui_manager_unittest.cc
@@ -8,28 +8,19 @@
 #include "base/callback_helpers.h"
 #include "base/run_loop.h"
 #include "base/values.h"
-#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/net/system_network_context_manager.h"
-#include "chrome/browser/password_manager/password_store_factory.h"
-#include "chrome/browser/safe_browsing/chrome_safe_browsing_blocking_page_factory.h"
-#include "chrome/browser/safe_browsing/safe_browsing_metrics_collector_factory.h"
-#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager_factory.h"
-#include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/scoped_testing_local_state.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/password_manager/core/browser/mock_password_store.h"
-#include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/safe_browsing/content/browser/safe_browsing_blocking_page.h"
 #include "components/safe_browsing/content/browser/safe_browsing_blocking_page_factory.h"
+#include "components/safe_browsing/content/browser/safe_browsing_controller_client.h"
 #include "components/safe_browsing/core/browser/db/util.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #include "components/security_interstitials/content/security_interstitial_controller_client.h"
+#include "components/security_interstitials/content/settings_page_helper.h"
 #include "components/security_interstitials/content/unsafe_resource_util.h"
 #include "components/security_interstitials/core/base_safe_browsing_error_ui.h"
+#include "components/security_interstitials/core/metrics_helper.h"
 #include "components/security_interstitials/core/unsafe_resource.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -42,6 +33,7 @@
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/web_contents_tester.h"
+#include "services/network/public/cpp/cross_thread_pending_shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -103,10 +95,16 @@
             web_contents,
             main_frame_url,
             unsafe_resources,
-            ChromeSafeBrowsingBlockingPageFactory::CreateControllerClient(
+            std::make_unique<safe_browsing::SafeBrowsingControllerClient>(
                 web_contents,
-                unsafe_resources,
-                manager),
+                std::make_unique<security_interstitials::MetricsHelper>(
+                    unsafe_resources[0].url,
+                    BaseBlockingPage::GetReportingInfo(unsafe_resources),
+                    /*history_service=*/nullptr),
+                /*prefs=*/nullptr,
+                manager->app_locale(),
+                manager->default_safe_page(),
+                /*settings_helper=*/nullptr),
             BaseSafeBrowsingErrorUI::SBErrorDisplayOptions(
                 BaseBlockingPage::IsMainPageLoadBlocked(unsafe_resources),
                 false,                 // is_extended_reporting_opt_in_allowed
@@ -121,14 +119,10 @@
                 false,                 // is_safe_browsing_managed
                 "cpn_safe_browsing"),  // help_center_article_link
             true,                      // should_trigger_reporting
-            HistoryServiceFactory::GetForProfile(
-                Profile::FromBrowserContext(web_contents->GetBrowserContext()),
-                ServiceAccessType::EXPLICIT_ACCESS),
-            SafeBrowsingNavigationObserverManagerFactory::GetForBrowserContext(
-                web_contents->GetBrowserContext()),
-            SafeBrowsingMetricsCollectorFactory::GetForProfile(
-                Profile::FromBrowserContext(web_contents->GetBrowserContext())),
-            g_browser_process->safe_browsing_service()->trigger_manager()) {
+            /*history_service=*/nullptr,
+            /*navigation_observer_manager=*/nullptr,
+            /*metrics_collector=*/nullptr,
+            /*trigger_manager=*/nullptr) {
     // Don't delay details at all for the unittest.
     SetThreatDetailsProceedDelayForTesting(0);
     DontCreateViewForTesting();
@@ -188,6 +182,11 @@
       content::BrowserContext* browser_context) override {
     return nullptr;
   }
+  PingManager* GetPingManagerIfExists() override { return nullptr; }
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory(
+      content::BrowserContext* browser_context) override {
+    return nullptr;
+  }
   bool IsMetricsAndCrashReportingEnabled() override { return false; }
 
   void set_is_hosting_extension(bool is_hosting_extension) {
@@ -202,13 +201,12 @@
 
 class SafeBrowsingUIManagerTest : public ChromeRenderViewHostTestHarness {
  public:
-  SafeBrowsingUIManagerTest()
-      : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()) {
+  SafeBrowsingUIManagerTest() {
     auto ui_manager_delegate =
         std::make_unique<TestSafeBrowsingUIManagerDelegate>();
     raw_ui_manager_delegate_ = ui_manager_delegate.get();
     ui_manager_ = new SafeBrowsingUIManager(
-        nullptr, std::move(ui_manager_delegate),
+        std::move(ui_manager_delegate),
         std::make_unique<TestSafeBrowsingBlockingPageFactory>(),
         GURL("chrome://new-tab-page/"));
   }
@@ -218,35 +216,6 @@
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
     SafeBrowsingUIManager::CreateAllowlistForTesting(web_contents());
-
-    safe_browsing::TestSafeBrowsingServiceFactory sb_service_factory;
-    auto* safe_browsing_service =
-        sb_service_factory.CreateSafeBrowsingService();
-    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(
-        safe_browsing_service);
-    g_browser_process->safe_browsing_service()->Initialize();
-    // A profile was created already but SafeBrowsingService wasn't around to
-    // get notified of it, so include that notification now.
-    safe_browsing_service->OnProfileAdded(
-        Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
-    content::BrowserThread::RunAllPendingTasksOnThreadForTesting(
-        content::BrowserThread::IO);
-    PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse(
-        profile(),
-        base::BindRepeating(
-            &password_manager::BuildPasswordStore<
-                content::BrowserContext, password_manager::MockPasswordStore>));
-  }
-
-  void TearDown() override {
-    TestingBrowserProcess::GetGlobal()->safe_browsing_service()->ShutDown();
-    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(nullptr);
-
-    // Depends on LocalState from ChromeRenderViewHostTestHarness.
-    if (SystemNetworkContextManager::GetInstance())
-      SystemNetworkContextManager::DeleteInstance();
-
-    ChromeRenderViewHostTestHarness::TearDown();
   }
 
   bool IsAllowlisted(security_interstitials::UnsafeResource resource) {
@@ -309,7 +278,6 @@
  private:
   scoped_refptr<SafeBrowsingUIManager> ui_manager_;
   TestSafeBrowsingUIManagerDelegate* raw_ui_manager_delegate_ = nullptr;
-  ScopedTestingLocalState scoped_testing_local_state_;
 };
 
 TEST_F(SafeBrowsingUIManagerTest, Allowlist) {
diff --git a/chrome/browser/safe_browsing/user_interaction_observer.cc b/chrome/browser/safe_browsing/user_interaction_observer.cc
index 80c222c..644b22aaa 100644
--- a/chrome/browser/safe_browsing/user_interaction_observer.cc
+++ b/chrome/browser/safe_browsing/user_interaction_observer.cc
@@ -11,10 +11,12 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/omnibox/browser/omnibox_prefs.h"
 #include "components/prefs/pref_service.h"
+#include "components/safe_browsing/buildflags.h"
 #include "components/safe_browsing/core/common/features.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/buildflags/buildflags.h"
 #include "third_party/blink/public/common/input/web_mouse_event.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 
diff --git a/chrome/browser/sharesheet/sharesheet_service.cc b/chrome/browser/sharesheet/sharesheet_service.cc
index 84832ef..876a5209 100644
--- a/chrome/browser/sharesheet/sharesheet_service.cc
+++ b/chrome/browser/sharesheet/sharesheet_service.cc
@@ -149,6 +149,7 @@
     delegate->OnActionLaunched();
     share_action->LaunchAction(delegate, share_action_view, std::move(intent));
   } else if (type == TargetType::kArcApp || type == TargetType::kWebApp) {
+    DCHECK(intent);
     LaunchApp(target_name, std::move(intent));
     delegate->CloseSharesheet(SharesheetResult::kSuccess);
   }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 5fe3d69..0ea370da 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2328,6 +2328,8 @@
       "webui/chromeos/emoji/emoji_page_handler.h",
       "webui/chromeos/emoji/emoji_ui.cc",
       "webui/chromeos/emoji/emoji_ui.h",
+      "webui/chromeos/enterprise_casting/enterprise_casting_ui.cc",
+      "webui/chromeos/enterprise_casting/enterprise_casting_ui.h",
       "webui/chromeos/image_source.cc",
       "webui/chromeos/image_source.h",
       "webui/chromeos/in_session_password_change/base_lock_dialog.cc",
@@ -2761,6 +2763,7 @@
       "//chrome/browser/ui/webui/app_management:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/add_supervision:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/crostini_upgrader:mojo_bindings",
+      "//chrome/browser/ui/webui/chromeos/enterprise_casting:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/launcher_internals:mojo_bindings",
       "//chrome/browser/ui/webui/chromeos/vm:mojo_bindings",
       "//chrome/browser/ui/webui/nearby_share:mojom",
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
index 8d2fa19..25a984c 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -51,6 +51,7 @@
 #include "components/arc/metrics/arc_metrics_service.h"
 #include "components/arc/mojom/intent_helper.mojom.h"
 #include "components/arc/session/arc_bridge_service.h"
+#include "components/full_restore/full_restore_utils.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
@@ -373,7 +374,13 @@
       }
     }
 
-    arc::ArcBootPhaseMonitorBridge::RecordFirstAppLaunchDelayUMA(context);
+    // App launched by user rather than full restore.
+    if (window_info &&
+        window_info->window_id <=
+            full_restore::kArcSessionIdOffsetForRestoredLaunching) {
+      arc::ArcBootPhaseMonitorBridge::RecordFirstAppLaunchDelayUMA(context);
+    }
+
     ChromeShelfController* chrome_controller =
         ChromeShelfController::instance();
     // chrome_controller may be null in tests.
diff --git a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc
index 742bb463..722193e 100644
--- a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc
+++ b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc
@@ -29,6 +29,7 @@
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/ui/vector_icons/vector_icons.h"
+#include "components/url_formatter/url_formatter.h"
 #include "storage/browser/file_system/file_system_context.h"
 #include "storage/browser/file_system/file_system_url.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -392,7 +393,21 @@
       text_fields.push_back(base::UTF8ToUTF16(extracted_text));
 
     if (extracted_url.is_valid()) {
-      text_fields.push_back(base::ASCIIToUTF16(extracted_url.spec()));
+      // We format the URL to match the location bar so the user is not
+      // surprised by what is being shared. This means:
+      // - International characters are unescaped (human readable) where safe.
+      // - Characters representing emojis are unescaped.
+      // - No elisions that change the meaning of the URL.
+      // - Spaces are not unescaped. We cannot share a URL with unescaped spaces
+      // as the receiving program may think the URL ends at the space. Hence we
+      // align the preview with the content to be shared.
+      const auto format_types = url_formatter::kFormatUrlOmitDefaults &
+                                ~url_formatter::kFormatUrlOmitHTTP;
+      const auto formatted_text = url_formatter::FormatUrl(
+          extracted_url, format_types, net::UnescapeRule::NORMAL,
+          /*new_parsed=*/nullptr,
+          /*prefix_end=*/nullptr, /*offset_for_adjustment=*/nullptr);
+      text_fields.push_back(formatted_text);
       text_icon_ = TextPlaceholderIcon::kLink;
     }
   }
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index 294a50ab..7586f9e 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -249,6 +249,39 @@
 }
 }  // namespace
 
+class DownloadItemView::ContextMenuButton : public views::ImageButton {
+ public:
+  METADATA_HEADER(ContextMenuButton);
+
+  explicit ContextMenuButton(DownloadItemView* owner)
+      : views::ImageButton(
+            base::BindRepeating(&DownloadItemView::DropdownButtonPressed,
+                                base::Unretained(owner))),
+        owner_(owner) {
+    views::ConfigureVectorImageButton(this);
+    SetAccessibleName(l10n_util::GetStringUTF16(
+        IDS_DOWNLOAD_ITEM_DROPDOWN_BUTTON_ACCESSIBLE_TEXT));
+    SetBorder(views::CreateEmptyBorder(gfx::Insets(10)));
+    SetHasInkDropActionOnClick(false);
+  }
+
+  bool OnMousePressed(const ui::MouseEvent& event) override {
+    suppress_button_release_ = owner_->GetDropdownPressed();
+    return ImageButton::OnMousePressed(event);
+  }
+
+  bool IsTriggerableEvent(const ui::Event& event) override {
+    return !event.IsMouseEvent() || !suppress_button_release_;
+  }
+
+ private:
+  DownloadItemView* const owner_;
+  bool suppress_button_release_ = false;
+};
+
+BEGIN_METADATA(DownloadItemView, ContextMenuButton, views::ImageButton)
+END_METADATA
+
 DownloadItemView::DownloadItemView(DownloadUIModel::DownloadUIModelPtr model,
                                    DownloadShelfView* shelf,
                                    views::View* accessible_alert)
@@ -326,14 +359,7 @@
                           base::Unretained(this)),
       l10n_util::GetStringUTF16(IDS_REVIEW_DOWNLOAD)));
 
-  dropdown_button_ =
-      AddChildView(views::CreateVectorImageButton(base::BindRepeating(
-          &DownloadItemView::DropdownButtonPressed, base::Unretained(this))));
-  dropdown_button_->SetAccessibleName(l10n_util::GetStringUTF16(
-      IDS_DOWNLOAD_ITEM_DROPDOWN_BUTTON_ACCESSIBLE_TEXT));
-  dropdown_button_->SetBorder(views::CreateEmptyBorder(gfx::Insets(10)));
-  dropdown_button_->SetHasInkDropActionOnClick(false);
-  dropdown_button_->SizeToPreferredSize();
+  dropdown_button_ = AddChildView(std::make_unique<ContextMenuButton>(this));
 
   complete_animation_.SetSlideDuration(base::TimeDelta::FromMilliseconds(2500));
   complete_animation_.SetTweenType(gfx::Tween::LINEAR);
@@ -1221,6 +1247,7 @@
       dropdown_pressed_ ? vector_icons::kCaretDownIcon
                         : vector_icons::kCaretUpIcon,
       GetThemeProvider()->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT));
+  dropdown_button_->SizeToPreferredSize();
 }
 
 void DownloadItemView::OpenButtonPressed() {
@@ -1340,15 +1367,22 @@
   static_cast<views::internal::RootView*>(GetWidget()->GetRootView())
       ->SetMouseAndGestureHandler(nullptr);
 
-  const auto release_dropdown = [](DownloadItemView* view) {
-    view->SetDropdownPressed(false);
+  const auto release_dropdown = [](base::WeakPtr<DownloadItemView> view) {
     // Make sure any new status from activating a context menu option is read.
     view->announce_accessible_alert_soon_ = true;
+
+    // The context menu is destroyed before the button's MousePressed()
+    // function (which wants to know if the button was already pressed) is
+    // reached -- so delay marking the button as "released" until the callstack
+    // unwinds.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&DownloadItemView::SetDropdownPressed,
+                                  std::move(view), false));
   };
 
-  context_menu_.Run(
-      GetWidget()->GetTopLevelWidget(), rect, source_type,
-      base::BindRepeating(std::move(release_dropdown), base::Unretained(this)));
+  context_menu_.Run(GetWidget()->GetTopLevelWidget(), rect, source_type,
+                    base::BindRepeating(std::move(release_dropdown),
+                                        weak_ptr_factory_.GetWeakPtr()));
 }
 
 void DownloadItemView::OpenDownloadDuringAsyncScanning() {
diff --git a/chrome/browser/ui/views/download/download_item_view.h b/chrome/browser/ui/views/download/download_item_view.h
index 406c8b0..29eb3ba 100644
--- a/chrome/browser/ui/views/download/download_item_view.h
+++ b/chrome/browser/ui/views/download/download_item_view.h
@@ -121,6 +121,8 @@
                                   float new_device_scale_factor) override;
 
  private:
+  class ContextMenuButton;
+
   // Sets the current mode to |mode| and updates UI appropriately.
   void SetMode(download::DownloadItemMode mode);
   download::DownloadItemMode GetMode() const;
diff --git a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
index 9137581..48c552a 100644
--- a/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
+++ b/chrome/browser/ui/views/file_system_access/file_system_access_browsertest.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/file_system_access/file_system_access_permission_request_manager.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index 6a44e6d..006c2c6 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
@@ -614,6 +614,7 @@
     }
   }
   title_label_->SetText(title, is_filename);
+  domain_label_->SetText(domain, absl::nullopt);
 
   const bool alternate_layout = UseAlternateHoverCardFormat();
   if (alert_state_ != old_alert_state) {
@@ -652,13 +653,6 @@
       thumbnail_view_->SetRoundedCorners(corners, corner_radius_.value_or(0));
     }
   }
-
-  domain_label_->SetText(domain, absl::nullopt);
-
-  // Because we may have changed the card's contents, if the card has yet to be
-  // shown, ensure that it starts at the correct size.
-  if (!GetWidget()->IsVisible())
-    SizeToContents();
 }
 
 void TabHoverCardBubbleView::SetTextFade(double percent) {
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
index 3146bcb..8a582c2 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
@@ -277,6 +277,7 @@
   if (update_type == TabController::HoverCardUpdateType::kTabDataChanged) {
     DCHECK(IsHoverCardShowingForTab(tab));
     UpdateCardContent(tab);
+    slide_animator_->UpdateTargetBounds();
     return;
   }
 
@@ -332,6 +333,7 @@
 
   CreateHoverCard(target_tab_);
   UpdateCardContent(target_tab_);
+  slide_animator_->UpdateTargetBounds();
   MaybeStartThumbnailObservation(target_tab_, is_initial);
 
   // Ensure the hover card Widget assumes the highest z-order to avoid occlusion
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index ad830a7..42ce95c 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -856,20 +856,22 @@
   return menu_runner_.get() && menu_runner_->IsRunning();
 }
 
-void AppMenu::GetLabelStyle(int command_id, LabelStyle* style) const {
-  if (IsRecentTabsCommand(command_id)) {
-    const gfx::FontList* font_list =
-        recent_tabs_menu_model_delegate_->GetLabelFontListForCommandId(
-            command_id);
-    // Only fill in |*color| if there's a font list - otherwise this method will
-    // override the color for every recent tab item, not just the header.
-    if (font_list) {
-      // TODO(ellyjones): Use CONTEXT_MENU instead of CONTEXT_LABEL.
-      style->foreground = views::style::GetColor(
-          *root_, views::style::CONTEXT_LABEL, views::style::STYLE_PRIMARY);
-      style->font_list = *font_list;
-    }
-  }
+const gfx::FontList* AppMenu::GetLabelFontList(int command_id) const {
+  return IsRecentTabsCommand(command_id)
+             ? recent_tabs_menu_model_delegate_->GetLabelFontListForCommandId(
+                   command_id)
+             : nullptr;
+}
+
+absl::optional<SkColor> AppMenu::GetLabelColor(int command_id) const {
+  // Only return a color if there's a font list - otherwise this method will
+  // return a color for every recent tab item, not just the header.
+  // TODO(ellyjones): Use CONTEXT_MENU instead of CONTEXT_LABEL.
+  return GetLabelFontList(command_id)
+             ? absl::optional<SkColor>(
+                   views::style::GetColor(*root_, views::style::CONTEXT_LABEL,
+                                          views::style::STYLE_PRIMARY))
+             : absl::nullopt;
 }
 
 std::u16string AppMenu::GetTooltipText(int command_id,
diff --git a/chrome/browser/ui/views/toolbar/app_menu.h b/chrome/browser/ui/views/toolbar/app_menu.h
index 494e0ba..ac575e0 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.h
+++ b/chrome/browser/ui/views/toolbar/app_menu.h
@@ -56,7 +56,8 @@
   views::MenuItemView* root_menu_item() { return root_; }
 
   // MenuDelegate overrides:
-  void GetLabelStyle(int command_id, LabelStyle* style) const override;
+  const gfx::FontList* GetLabelFontList(int command_id) const override;
+  absl::optional<SkColor> GetLabelColor(int command_id) const override;
   std::u16string GetTooltipText(int command_id,
                                 const gfx::Point& p) const override;
   bool IsTriggerableEvent(views::MenuItemView* menu,
diff --git a/chrome/browser/ui/web_applications/web_app_launch_manager.cc b/chrome/browser/ui/web_applications/web_app_launch_manager.cc
index d168606..359f0b0 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_manager.cc
+++ b/chrome/browser/ui/web_applications/web_app_launch_manager.cc
@@ -182,6 +182,13 @@
   return false;
 }
 
+WebAppLaunchManager::OpenApplicationCallback&
+GetOpenApplicationCallbackForTesting() {
+  static base::NoDestructor<WebAppLaunchManager::OpenApplicationCallback>
+      callback;
+  return *callback;
+}
+
 }  // namespace
 
 Browser* CreateWebApplicationWindow(Profile* profile,
@@ -237,8 +244,8 @@
   if (params.container == apps::mojom::LaunchContainer::kLaunchContainerWindow)
     RecordAppWindowLaunch(profile_, params.app_id);
 
-  if (GetOpenApplicationCallback())
-    return GetOpenApplicationCallback().Run(std::move(params));
+  if (GetOpenApplicationCallbackForTesting())
+    return GetOpenApplicationCallbackForTesting().Run(std::move(params));
 
   // Determine the launch URL.
   bool is_share_intent =
@@ -444,7 +451,7 @@
 // static
 void WebAppLaunchManager::SetOpenApplicationCallbackForTesting(
     OpenApplicationCallback callback) {
-  GetOpenApplicationCallback() = std::move(callback);
+  GetOpenApplicationCallbackForTesting() = std::move(callback);
 }
 
 void WebAppLaunchManager::LaunchWebApplication(
@@ -473,14 +480,6 @@
   std::move(callback).Run(browser, container);
 }
 
-// static
-WebAppLaunchManager::OpenApplicationCallback&
-WebAppLaunchManager::GetOpenApplicationCallback() {
-  static base::NoDestructor<OpenApplicationCallback> callback;
-
-  return *callback;
-}
-
 void RecordAppWindowLaunch(Profile* profile, const std::string& app_id) {
   WebAppProvider* provider = WebAppProvider::Get(profile);
   if (!provider)
diff --git a/chrome/browser/ui/web_applications/web_app_launch_manager.h b/chrome/browser/ui/web_applications/web_app_launch_manager.h
index a23ab7e..484b501 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_manager.h
+++ b/chrome/browser/ui/web_applications/web_app_launch_manager.h
@@ -67,8 +67,6 @@
                               apps::mojom::LaunchContainer container)>
           callback);
 
-  static OpenApplicationCallback& GetOpenApplicationCallback();
-
   Profile* const profile_;
   WebAppProvider* const provider_;
 
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index ee35f2a..b834729 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -206,6 +206,7 @@
 #include "chrome/browser/ui/webui/chromeos/cryptohome_ui.h"
 #include "chrome/browser/ui/webui/chromeos/drive_internals_ui.h"
 #include "chrome/browser/ui/webui/chromeos/emoji/emoji_ui.h"
+#include "chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting_ui.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_network_ui.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h"
@@ -800,6 +801,9 @@
     return &NewWebUI<chromeos::DriveInternalsUI>;
   if (url.host_piece() == chrome::kChromeUILauncherInternalsHost)
     return &NewWebUI<chromeos::LauncherInternalsUI>;
+  if (base::FeatureList::IsEnabled(features::kEnterpriseCastingUI) &&
+      url.host_piece() == chrome::kChromeUIEnterpriseCastingHost)
+    return &NewWebUI<chromeos::EnterpriseCastingUI>;
   if (url.host_piece() == chromeos::kChromeUIHelpAppHost)
     return &NewComponentUI<chromeos::HelpAppUI, ChromeHelpAppUIDelegate>;
   if (url.host_piece() == chrome::kChromeUIMobileSetupHost)
diff --git a/chrome/browser/ui/webui/chromeos/enterprise_casting/BUILD.gn b/chrome/browser/ui/webui/chromeos/enterprise_casting/BUILD.gn
new file mode 100644
index 0000000..1a73667
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/enterprise_casting/BUILD.gn
@@ -0,0 +1,12 @@
+# Copyright 2021 The Chromium 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("//mojo/public/tools/bindings/mojom.gni")
+
+assert(is_chromeos, "EnterpriseCasting is Chrome OS only.")
+
+mojom("mojo_bindings") {
+  sources = [ "enterprise_casting.mojom" ]
+  webui_module_path = "/"
+}
diff --git a/chrome/browser/ui/webui/chromeos/enterprise_casting/OWNERS b/chrome/browser/ui/webui/chromeos/enterprise_casting/OWNERS
new file mode 100644
index 0000000..57d67b8
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/enterprise_casting/OWNERS
@@ -0,0 +1,7 @@
+gbj@google.com
+bmalcolm@google.com
+bzielinski@google.com
+jacqueli@google.com
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting.mojom b/chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting.mojom
new file mode 100644
index 0000000..6b5b694
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting.mojom
@@ -0,0 +1,11 @@
+// Copyright 2021 The Chromium 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 enterprise_casting.mojom;
+
+// Interface for creating enterprise_casting handlers. Implemented by the WebUI
+// controller and used by chrome://enterprise-casting.
+interface PageHandlerFactory {
+  // TODO(b/193421383): Add a CreatePageHandler method.
+};
diff --git a/chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting_ui.cc b/chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting_ui.cc
new file mode 100644
index 0000000..cebd129
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting_ui.cc
@@ -0,0 +1,42 @@
+// Copyright 2021 The Chromium 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/chromeos/enterprise_casting/enterprise_casting_ui.h"
+
+#include "base/containers/span.h"
+#include "chrome/browser/ui/webui/webui_util.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/enterprise_casting_resources.h"
+#include "chrome/grit/enterprise_casting_resources_map.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui_data_source.h"
+
+namespace chromeos {
+
+EnterpriseCastingUI::EnterpriseCastingUI(content::WebUI* web_ui)
+    : MojoWebUIController(web_ui) {
+  auto source = base::WrapUnique(
+      content::WebUIDataSource::Create(chrome::kChromeUIEnterpriseCastingHost));
+  webui::SetupWebUIDataSource(source.get(),
+                              base::make_span(kEnterpriseCastingResources,
+                                              kEnterpriseCastingResourcesSize),
+                              IDR_ENTERPRISE_CASTING_INDEX_HTML);
+
+  content::BrowserContext* browser_context =
+      web_ui->GetWebContents()->GetBrowserContext();
+  content::WebUIDataSource::Add(browser_context, source.release());
+}
+
+EnterpriseCastingUI::~EnterpriseCastingUI() = default;
+
+void EnterpriseCastingUI::BindInterface(
+    mojo::PendingReceiver<enterprise_casting::mojom::PageHandlerFactory>
+        receiver) {
+  factory_receiver_.reset();
+  factory_receiver_.Bind(std::move(receiver));
+}
+
+WEB_UI_CONTROLLER_TYPE_IMPL(EnterpriseCastingUI)
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting_ui.h b/chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting_ui.h
new file mode 100644
index 0000000..92ecb6b1
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting_ui.h
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium 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_CHROMEOS_ENTERPRISE_CASTING_ENTERPRISE_CASTING_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_ENTERPRISE_CASTING_ENTERPRISE_CASTING_UI_H_
+
+#include "chrome/browser/ui/webui/chromeos/enterprise_casting/enterprise_casting.mojom.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 "ui/webui/mojo_web_ui_controller.h"
+
+namespace chromeos {
+
+// The WebUI controller for chrome://enterprise-casting.
+class EnterpriseCastingUI
+    : public ui::MojoWebUIController,
+      public enterprise_casting::mojom::PageHandlerFactory {
+ public:
+  explicit EnterpriseCastingUI(content::WebUI* web_ui);
+  ~EnterpriseCastingUI() override;
+
+  EnterpriseCastingUI(const EnterpriseCastingUI&) = delete;
+  EnterpriseCastingUI& operator=(const EnterpriseCastingUI&) = delete;
+
+  void BindInterface(
+      mojo::PendingReceiver<enterprise_casting::mojom::PageHandlerFactory>
+          receiver);
+
+ private:
+  mojo::Receiver<enterprise_casting::mojom::PageHandlerFactory>
+      factory_receiver_{this};
+
+  WEB_UI_CONTROLLER_TYPE_DECL();
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_ENTERPRISE_CASTING_ENTERPRISE_CASTING_UI_H_
diff --git a/chrome/browser/ui/webui/management/management_ui_handler.cc b/chrome/browser/ui/webui/management/management_ui_handler.cc
index 90aa7b0..1f923b1 100644
--- a/chrome/browser/ui/webui/management/management_ui_handler.cc
+++ b/chrome/browser/ui/webui/management/management_ui_handler.cc
@@ -53,10 +53,10 @@
 #include "chrome/browser/ash/policy/networking/policy_cert_service_factory.h"
 #include "chrome/browser/ash/policy/status_collector/device_status_collector.h"
 #include "chrome/browser/ash/policy/status_collector/status_collector.h"
+#include "chrome/browser/ash/policy/uploading/status_uploader.h"
+#include "chrome/browser/ash/policy/uploading/system_log_uploader.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
-#include "chrome/browser/chromeos/policy/uploading/status_uploader.h"
-#include "chrome/browser/chromeos/policy/uploading/system_log_uploader.h"
 #include "chrome/browser/ui/webui/management/management_ui_handler_chromeos.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/grit/chromium_strings.h"
diff --git a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
index 806d18af..4c0038e 100644
--- a/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/management/management_ui_handler_unittest.cc
@@ -52,10 +52,10 @@
 #include "chrome/browser/ash/policy/enrollment/device_cloud_policy_initializer.h"
 #include "chrome/browser/ash/policy/status_collector/device_status_collector.h"
 #include "chrome/browser/ash/policy/status_collector/status_collector.h"
+#include "chrome/browser/ash/policy/uploading/status_uploader.h"
+#include "chrome/browser/ash/policy/uploading/system_log_uploader.h"
 #include "chrome/browser/ash/settings/device_settings_test_helper.h"
 #include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
-#include "chrome/browser/chromeos/policy/uploading/status_uploader.h"
-#include "chrome/browser/chromeos/policy/uploading/system_log_uploader.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/ui/webui/realbox/realbox_handler.cc b/chrome/browser/ui/webui/realbox/realbox_handler.cc
index d6fe3bb..6cd7f31 100644
--- a/chrome/browser/ui/webui/realbox/realbox_handler.cc
+++ b/chrome/browser/ui/webui/realbox/realbox_handler.cc
@@ -68,7 +68,7 @@
     "realbox/icons/drive_folder.svg";
 constexpr char kDriveFormIconResourceName[] = "realbox/icons/drive_form.svg";
 constexpr char kDriveImageIconResourceName[] = "realbox/icons/drive_image.svg";
-constexpr char kDriveLogoIconResourceName[] = "realbox/icons/drive_logo.svg";
+constexpr char kDriveLogoIconResourceName[] = "icons/drive_logo.svg";
 constexpr char kDrivePdfIconResourceName[] = "realbox/icons/drive_pdf.svg";
 constexpr char kDriveSheetsIconResourceName[] =
     "realbox/icons/drive_sheets.svg";
diff --git a/chrome/browser/web_applications/components/web_app_protocol_handler_registration_win.cc b/chrome/browser/web_applications/components/web_app_protocol_handler_registration_win.cc
index c88665f..3ff9ea9 100644
--- a/chrome/browser/web_applications/components/web_app_protocol_handler_registration_win.cc
+++ b/chrome/browser/web_applications/components/web_app_protocol_handler_registration_win.cc
@@ -102,7 +102,8 @@
 
   // Remove protocol associations from the Windows registry.
   ShellUtil::RemoveAppProtocolAssociations(
-      web_app::GetProgIdForApp(profile_path, app_id));
+      web_app::GetProgIdForApp(profile_path, app_id),
+      /*elevate_if_not_admin=*/true);
 }
 
 }  // namespace
diff --git a/chrome/browser/web_applications/os_integration_manager.cc b/chrome/browser/web_applications/os_integration_manager.cc
index 83d2a20..5c03b88 100644
--- a/chrome/browser/web_applications/os_integration_manager.cc
+++ b/chrome/browser/web_applications/os_integration_manager.cc
@@ -396,6 +396,8 @@
   // Disable protocol handler unregistration on Win7 due to bad interactions
   // between preinstalled app scenarios and the need for elevation to unregister
   // protocol handlers on that platform. See crbug.com/1224327 for context.
+  // TODO(crbug.com/1224747): remove this check and remove Win7 protocol handler
+  // support in Shell classes.
 #if defined(OS_WIN)
   if (base::win::GetVersion() == base::win::Version::WIN7) {
     std::move(callback).Run(true);
@@ -538,6 +540,8 @@
   // Disable protocol handler unregistration on Win7 due to bad interactions
   // between preinstalled app scenarios and the need for elevation to unregister
   // protocol handlers on that platform. See crbug.com/1224327 for context.
+  // TODO(crbug.com/1224747): remove this check and remove Win7 protocol handler
+  // support in Shell classes.
 #if defined(OS_WIN)
   if (base::win::GetVersion() == base::win::Version::WIN7) {
     std::move(callback).Run(true);
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 7b81197..f872878 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -203,6 +203,7 @@
         "$root_gen_dir/chrome/bluetooth_pairing_dialog_resources.pak",
         "$root_gen_dir/chrome/browser/supervised_user/supervised_user_unscaled_resources.pak",
         "$root_gen_dir/chrome/emoji_picker_resources.pak",
+        "$root_gen_dir/chrome/enterprise_casting_resources.pak",
         "$root_gen_dir/chrome/internet_config_dialog_resources.pak",
         "$root_gen_dir/chrome/internet_detail_dialog_resources.pak",
         "$root_gen_dir/chrome/launcher_internals_resources.pak",
@@ -244,6 +245,7 @@
         "//chrome/browser/resources:internet_detail_dialog_resources",
         "//chrome/browser/resources/chromeos:multidevice_setup_resources",
         "//chrome/browser/resources/chromeos/emoji_picker:resources",
+        "//chrome/browser/resources/chromeos/enterprise_casting:resources",
         "//chrome/browser/resources/chromeos/launcher_internals:resources",
         "//chrome/browser/resources/chromeos/login:modulized_resources",
         "//chrome/browser/resources/chromeos/login:resources",
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl
index 5f266ac..58d30d1 100644
--- a/chrome/common/extensions/api/autotest_private.idl
+++ b/chrome/common/extensions/api/autotest_private.idl
@@ -501,6 +501,8 @@
     HotseatSwipeDescriptor swipeUp;
     HotseatState state;
     boolean isAnimating;
+    // Whether the shelf is hidden with auto-hide enabled.
+    boolean isAutoHidden;
   };
 
   // The ui information of shelf components, including hotseat and
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 8c48088..1ec4a1d 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -73,6 +73,8 @@
 const char kChromeUIEDUCoexistenceLoginURLV1[] = "chrome://chrome-signin/edu";
 const char kChromeUIEDUCoexistenceLoginURLV2[] =
     "chrome://chrome-signin/edu-coexistence";
+const char kChromeUIEnterpriseCastingHost[] = "enterprise-casting";
+const char kChromeUIEnterpriseCastingURL[] = "chrome://enterprise-casting/";
 const char kChromeUIExtensionIconHost[] = "extension-icon";
 const char kChromeUIExtensionIconURL[] = "chrome://extension-icon/";
 const char kChromeUIExtensionsHost[] = "extensions";
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index f41a17d25..0855b9e 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -75,6 +75,8 @@
 extern const char kChromeUIDriveInternalsHost[];
 extern const char kChromeUIEDUCoexistenceLoginURLV1[];
 extern const char kChromeUIEDUCoexistenceLoginURLV2[];
+extern const char kChromeUIEnterpriseCastingHost[];
+extern const char kChromeUIEnterpriseCastingURL[];
 extern const char kChromeUIExtensionIconHost[];
 extern const char kChromeUIExtensionIconURL[];
 extern const char kChromeUIExtensionsHost[];
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index 7fb6bcd..b5f65de 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -35,6 +35,7 @@
 #include "base/process/process.h"
 #include "base/process/process_metrics.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -924,6 +925,38 @@
               chrome_exe, suffix, protocol_associations.value(), false)) {
         status = installer::IN_USE_UPDATED;
       }
+    } else if (cmd_line.HasSwitch(
+                   installer::switches::kRegisterWebAppURLProtocols)) {
+      const std::wstring switch_value = cmd_line.GetSwitchValueNative(
+          installer::switches::kRegisterWebAppURLProtocols);
+      std::vector<std::wstring> switch_parts = base::SplitString(
+          switch_value, L":", base::WhitespaceHandling::TRIM_WHITESPACE,
+          base::SplitResult::SPLIT_WANT_NONEMPTY);
+
+      if (switch_parts.size() == 2) {
+        std::wstring prog_id = switch_parts[0];
+        std::vector<std::wstring> protocols = base::SplitString(
+            switch_parts[1], L",", base::WhitespaceHandling::TRIM_WHITESPACE,
+            base::SplitResult::SPLIT_WANT_NONEMPTY);
+
+        // ShellUtil::RegisterChromeForProtocol performs all registration
+        // done by ShellUtil::RegisterChromeBrowser, as well as registering
+        // with Windows as capable of handling the supplied protocols.
+        if (!protocols.empty() && !prog_id.empty() &&
+            ShellUtil::RegisterApplicationForProtocols(protocols, prog_id,
+                                                       chrome_exe, false)) {
+          status = installer::IN_USE_UPDATED;
+        }
+      }
+    } else if (cmd_line.HasSwitch(
+                   installer::switches::kUnregisterWebAppProgId)) {
+      const std::wstring prog_id = cmd_line.GetSwitchValueNative(
+          installer::switches::kUnregisterWebAppProgId);
+
+      if (!prog_id.empty() &&
+          ShellUtil::RemoveAppProtocolAssociations(prog_id, false)) {
+        status = installer::IN_USE_UPDATED;
+      }
     } else {
       if (ShellUtil::RegisterChromeBrowser(chrome_exe, suffix,
                                            /*elevate_if_not_admin=*/false))
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index e22ef8b..5b1d1c9 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -1484,6 +1484,13 @@
   return std::make_unique<RegistryEntry>(user_choice_path.c_str(), kRegProgId);
 }
 
+// Checks if the current user has selected a default handler for |protocol|.
+bool DoesProtocolHaveUserChoiceHandler(const std::wstring& protocol) {
+  std::vector<std::unique_ptr<RegistryEntry>> entries;
+  entries.push_back(GetProtocolUserChoiceEntry(protocol));
+  return AreEntriesAsDesired(entries, RegistryEntry::LOOK_IN_HKCU);
+}
+
 // Gets a ProtocolAssociations instance containing a single association where
 // |protocol| is handled by the default HTML browser handler.
 ShellUtil::ProtocolAssociations GetBrowserProtocolAssociation(
@@ -1596,61 +1603,6 @@
                                        best_effort_no_rollback);
 }
 
-// Registers a set of protocols for a particular application in the Windows
-// registry.
-//
-// This method is not supported and should not be called in Windows versions
-// prior to Win8, where write access to HKLM is required.
-//
-// |protocols| is the set of protocols to register. Must not be empty.
-// |prog_id| is the ProgId used by Windows for protocol associations with this
-// application. Must not be empty or start with a '.'.
-// |chrome_exe|: the full path to chrome.exe.
-bool RegisterApplicationForProtocols(const std::vector<std::wstring>& protocols,
-                                     const std::wstring& prog_id,
-                                     const base::FilePath& chrome_exe) {
-  DCHECK_GT(base::win::GetVersion(), base::win::Version::WIN7);
-
-  std::vector<std::unique_ptr<RegistryEntry>> entries;
-  ShellUtil::ApplicationInfo app_info =
-      ShellUtil::GetApplicationInfoForProgId(prog_id);
-
-  // Build the Windows Default Programs capabilities key for the app.
-  // "HKEY_CURRENT_USER\Software\[CompanyPathName\]ProductPathName[install_suffix]\AppProtocolHandlers\|prog_id|\Capabilities".
-  std::wstring capabilities_path = base::StrCat(
-      {install_static::GetRegistryPath(), ShellUtil::kRegAppProtocolHandlers,
-       kFilePathSeparator, prog_id, L"\\Capabilities"});
-
-  entries.push_back(std::make_unique<RegistryEntry>(
-      capabilities_path, ShellUtil::kRegApplicationName,
-      app_info.application_name));
-
-  // Use name as app description if description from |prog_id| registration is
-  // empty.
-  std::wstring app_description = app_info.application_description.empty()
-                                     ? app_info.application_name
-                                     : app_info.application_description;
-  entries.push_back(std::make_unique<RegistryEntry>(
-      capabilities_path, ShellUtil::kRegApplicationDescription,
-      app_description));
-
-  // Create URLAssociations
-  const std::wstring url_associations =
-      base::StrCat({std::wstring(capabilities_path), L"\\URLAssociations"});
-
-  for (const auto& protocol : protocols) {
-    entries.push_back(
-        std::make_unique<RegistryEntry>(url_associations, protocol, prog_id));
-  }
-
-  // Add the |prog_id| value to HKEY_CURRENT_USER\RegisteredApplications.
-  entries.push_back(std::make_unique<RegistryEntry>(
-      ShellUtil::kRegRegisteredApplications, prog_id, capabilities_path));
-
-  return AreEntriesAsDesired(entries, RegistryEntry::LOOK_IN_HKCU) ||
-         ShellUtil::AddRegistryEntries(HKEY_CURRENT_USER, entries);
-}
-
 }  // namespace
 
 const wchar_t* ShellUtil::kRegAppProtocolHandlers = L"\\AppProtocolHandlers";
@@ -2694,14 +2646,12 @@
     const std::vector<std::wstring>& protocols,
     const std::wstring& prog_id) {
   base::FilePath chrome_exe;
-  DCHECK_GT(base::win::GetVersion(), base::win::Version::WIN7);
-
   if (!base::PathService::Get(base::FILE_EXE, &chrome_exe)) {
     NOTREACHED();
     return false;
   }
 
-  if (!RegisterApplicationForProtocols(protocols, prog_id, chrome_exe)) {
+  if (!RegisterApplicationForProtocols(protocols, prog_id, chrome_exe, true)) {
     return false;
   }
 
@@ -2719,6 +2669,27 @@
     if (!AddRegistryEntries(HKEY_CURRENT_USER, entries))
       success = false;
 
+    // On Windows 7, set this protocol as default for uncontested protocols.
+    // This is necessary to cause Windows to recognize this protocol
+    // in "Default Apps" Windows UI. This is not required for contested
+    // protocols as Windows has already recognized those protocols in
+    // Windows UI, and we don't wish to override existing defaults.
+    if (base::win::GetVersion() == base::win::Version::WIN7 &&
+        !DoesProtocolHaveUserChoiceHandler(protocol)) {
+      Microsoft::WRL::ComPtr<IApplicationAssociationRegistration> registration;
+      HRESULT hr =
+          ::CoCreateInstance(CLSID_ApplicationAssociationRegistration, nullptr,
+                             CLSCTX_INPROC, IID_PPV_ARGS(&registration));
+
+      if (FAILED(hr) || !registration)
+        success = false;
+
+      hr = registration->SetAppAsDefault(prog_id.c_str(), protocol.c_str(),
+                                         AT_URLPROTOCOL);
+      if (FAILED(hr))
+        success = false;
+    }
+
     // On Windows 10, removing the existing user choice for a given protocol
     // forces Windows to present a disambiguation dialog the next time this
     // protocol is invoked from the OS.
@@ -2737,23 +2708,115 @@
 }
 
 // static
-bool ShellUtil::RemoveAppProtocolAssociations(const std::wstring& prog_id) {
-  DCHECK_GT(base::win::GetVersion(), base::win::Version::WIN7);
+bool ShellUtil::RegisterApplicationForProtocols(
+    const std::vector<std::wstring>& protocols,
+    const std::wstring& prog_id,
+    const base::FilePath& chrome_exe,
+    bool elevate_if_not_admin) {
+  HKEY root = base::win::GetVersion() == base::win::Version::WIN7
+                  ? HKEY_LOCAL_MACHINE
+                  : HKEY_CURRENT_USER;
 
-  // Delete the |prog_id| value from HKEY_CURRENT_USER\RegisteredApplications.
-  InstallUtil::DeleteRegistryValue(HKEY_CURRENT_USER,
-                                   ShellUtil::kRegRegisteredApplications,
-                                   WorkItem::kWow64Default, prog_id);
+  // Register directly if we can, otherwise elevate and use the installer.
+  if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) {
+    std::vector<std::unique_ptr<RegistryEntry>> entries;
 
-  // Delete the key
-  // HKEY_CURRENT_USER\Software\[CompanyPathName\]ProductPathName[install_suffix]\AppProtocolHandlers\|prog_id|.
-  std::wstring app_key_path(install_static::GetRegistryPath());
-  app_key_path.append(ShellUtil::kRegAppProtocolHandlers);
-  app_key_path.push_back(base::FilePath::kSeparators[0]);
-  app_key_path.append(prog_id);
+    ShellUtil::ApplicationInfo app_info = GetApplicationInfoForProgId(prog_id);
 
-  return InstallUtil::DeleteRegistryKey(HKEY_CURRENT_USER, app_key_path,
-                                        WorkItem::kWow64Default);
+    // Build the Windows Default Programs capabilities key for the app.
+    // "<root_hkey>\Software\[CompanyPathName\]ProductPathName[install_suffix]\AppProtocolHandlers\|prog_id|\Capabilities".
+    std::wstring capabilities_path = base::StrCat(
+        {install_static::GetRegistryPath(), ShellUtil::kRegAppProtocolHandlers,
+         kFilePathSeparator, prog_id, L"\\Capabilities"});
+
+    entries.push_back(std::make_unique<RegistryEntry>(
+        capabilities_path, ShellUtil::kRegApplicationName,
+        app_info.application_name));
+
+    // Use name as app description if description from |prog_id| registration is
+    // empty. The description is required for the app to show in various places
+    // of Windows 7.
+    std::wstring app_description = app_info.application_description.empty()
+                                       ? app_info.application_name
+                                       : app_info.application_description;
+    entries.push_back(std::make_unique<RegistryEntry>(
+        capabilities_path, ShellUtil::kRegApplicationDescription,
+        app_description));
+
+    // Create URLAssociations
+    const std::wstring url_associations =
+        base::StrCat({std::wstring(capabilities_path), L"\\URLAssociations"});
+
+    for (const auto& protocol : protocols) {
+      entries.push_back(
+          std::make_unique<RegistryEntry>(url_associations, protocol, prog_id));
+    }
+
+    // Add the |prog_id| value to <root hkey>\RegisteredApplications.
+    entries.push_back(std::make_unique<RegistryEntry>(
+        ShellUtil::kRegRegisteredApplications, prog_id, capabilities_path));
+
+    uint32_t look_for_in = root == HKEY_CURRENT_USER
+                               ? RegistryEntry::LOOK_IN_HKCU
+                               : RegistryEntry::LOOK_IN_HKLM;
+
+    return AreEntriesAsDesired(entries, look_for_in) ||
+           ShellUtil::AddRegistryEntries(root, entries);
+  }
+
+  // Admin rights are required to modify system-level protocol associations.
+  if (!elevate_if_not_admin)
+    return false;
+
+  // Elevate to do the whole job
+  std::wstring protocols_switch_value = base::JoinString(protocols, L",");
+  base::CommandLine::SwitchMap switches{
+      {installer::switches::kRegisterWebAppURLProtocols,
+       prog_id + L":" + protocols_switch_value}};
+  std::wstring suffix;
+
+  return GetInstallationSpecificSuffix(chrome_exe, &suffix) &&
+         ElevateAndRegisterChrome(chrome_exe, suffix, &switches);
+}
+
+bool ShellUtil::RemoveAppProtocolAssociations(const std::wstring& prog_id,
+                                              bool elevate_if_not_admin) {
+  HKEY root = base::win::GetVersion() == base::win::Version::WIN7
+                  ? HKEY_LOCAL_MACHINE
+                  : HKEY_CURRENT_USER;
+
+  if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) {
+    // Delete the |prog_id| value from <root hkey>\RegisteredApplications.
+    InstallUtil::DeleteRegistryValue(root,
+                                     ShellUtil::kRegRegisteredApplications,
+                                     WorkItem::kWow64Default, prog_id);
+
+    // Delete the key
+    // <root_hkey>\Software\[CompanyPathName\]ProductPathName[install_suffix]\AppProtocolHandlers\|prog_id|.
+    std::wstring app_key_path = base::StrCat(
+        {install_static::GetRegistryPath(), ShellUtil::kRegAppProtocolHandlers,
+         kFilePathSeparator, prog_id});
+
+    return InstallUtil::DeleteRegistryKey(root, app_key_path,
+                                          WorkItem::kWow64Default);
+  }
+
+  // Admin rights are required to modify system-level protocol associations.
+  if (!elevate_if_not_admin)
+    return false;
+
+  base::FilePath chrome_exe;
+  if (!base::PathService::Get(base::FILE_EXE, &chrome_exe))
+    return false;
+
+  std::wstring suffix;
+  if (!GetInstallationSpecificSuffix(chrome_exe, &suffix))
+    return false;
+
+  // Elevate to do the whole job.
+  base::CommandLine::SwitchMap switches{
+      {installer::switches::kUnregisterWebAppProgId, prog_id}};
+  return ElevateAndRegisterChrome(chrome_exe, suffix, &switches);
 }
 
 // static
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
index df911a9..5a7bb0a3 100644
--- a/chrome/installer/util/shell_util.h
+++ b/chrome/installer/util/shell_util.h
@@ -795,19 +795,39 @@
   // designated as the non-default handler for the corresponding protocol. For
   // protocols uncontested by other handlers on the OS, the app will be
   // promoted to default handler.
-  //
-  // This method is not supported and should not be called in Windows versions
-  // prior to Win8, where write access to HKLM is required.
   static bool AddAppProtocolAssociations(
       const std::vector<std::wstring>& protocols,
       const std::wstring& prog_id);
 
-  // Removes all protocol associations for a particular web app from the Windows
+  // Registers a set of protocols for a particular application in the Windows
   // registry.
   //
-  // This method is not supported and should not be called in Windows versions
-  // prior to Win8, where write access to HKLM is required.
-  static bool RemoveAppProtocolAssociations(const std::wstring& prog_id);
+  // This method requires write access to HKLM (prior to Win8).
+  // If write to HKLM is required, but fails, and:
+  // - |elevate_if_not_admin| is true:
+  //   tries to launch setup.exe with admin privileges (by prompting the user
+  //   with a UAC) to do these tasks.
+  // - |elevate_if_not_admin| is false:
+  //   adds the ProgId entries to HKCU. These entries will not make the app show
+  //   in Default Programs but they are still useful because the app can be
+  //   registered to run when the user clicks on a protocol link.
+  //
+  // |protocols| is the set of protocols to register. Must not be empty.
+  // |prog_id| is the ProgId used by Windows for protocol associations with this
+  // application. Must not be empty or start with a '.'.
+  // |chrome_exe|: the full path to chrome.exe.
+  // |elevate_if_not_admin| if true will make this method try alternate methods
+  // as described above.
+  static bool RegisterApplicationForProtocols(
+      const std::vector<std::wstring>& protocols,
+      const std::wstring& prog_id,
+      const base::FilePath& chrome_exe,
+      bool elevate_if_not_admin);
+
+  // Removes all protocol associations for a particular web app from the Windows
+  // registry.
+  static bool RemoveAppProtocolAssociations(const std::wstring& prog_id,
+                                            bool elevate_if_not_admin);
 
   // Returns the browser's ProgId for the current install.
   static std::wstring GetProgIdForBrowser(const base::FilePath& chrome_exe);
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index 7ad5516..abb9a39 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -1398,7 +1398,7 @@
   ASSERT_TRUE(ShellUtil::AddAppProtocolAssociations(app_protocols, app_progid));
 
   // Delete associations and ensure that the protocol entry does not exist.
-  EXPECT_TRUE(ShellUtil::RemoveAppProtocolAssociations(app_progid));
+  EXPECT_TRUE(ShellUtil::RemoveAppProtocolAssociations(app_progid, false));
 
   // Ensure that the software registration key was removed.
   // "<root_hkey>\Software\[CompanyPathName\]ProductPathName[install_suffix]\AppProtocolHandlers\|prog_id|".
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
index 69e0e20..8bc66950 100644
--- a/chrome/installer/util/util_constants.cc
+++ b/chrome/installer/util/util_constants.cc
@@ -133,6 +133,11 @@
 // in addition to the standard set of protocols.
 const char kRegisterURLProtocol[] = "register-url-protocol";
 
+// Specifies a comma-separated list of protocols to add as protocol associations
+// for a web application, preceded by the prog_id of that web application.
+// --register-web-app-url-protocols=<progid>:<protocol>,<protocol>,<protocol>..]
+const char kRegisterWebAppURLProtocols[] = "register-web-app-url-protocols";
+
 // Removes Chrome registration from current machine. Requires admin rights.
 const char kRemoveChromeRegistration[] = "remove-chrome-registration";
 
@@ -172,6 +177,10 @@
 // path given by --new-setup-exe.
 const char kUpdateSetupExe[] = "update-setup-exe";
 
+// Switch to pass the ProdId of a web application to be unregistered for
+// protocol handling.
+const char kUnregisterWebAppProgId[] = "unregister-web-app-prog-id";
+
 // Enable verbose logging (info level).
 const char kVerboseLogging[] = "verbose-logging";
 
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index dec1a69..1445a9e 100644
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -183,6 +183,7 @@
 extern const char kRegisterChromeBrowserSuffix[];
 extern const char kRegisterDevChrome[];
 extern const char kRegisterURLProtocol[];
+extern const char kRegisterWebAppURLProtocols[];
 extern const char kRemoveChromeRegistration[];
 extern const char kRenameChromeExe[];
 extern const char kRunAsAdmin[];
@@ -194,6 +195,7 @@
 extern const char kUncompressedArchive[];
 extern const char kUninstall[];
 extern const char kUpdateSetupExe[];
+extern const char kUnregisterWebAppProgId[];
 extern const char kVerboseLogging[];
 
 }  // namespace switches
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 221ce04..96b454a 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -6405,9 +6405,43 @@
           "SAMLOfflineSigninTimeLimit": 0
         },
         "prefs": {
-          "saml.offline_signin_time_limit": {}
+          "saml.offline_signin_time_limit": {
+            "value": 0
+          }
+        }
+      },
+      {
+        "note": "Minimum value",
+        "policies": {
+          "SAMLOfflineSigninTimeLimit": -1
+        },
+        "prefs": {
+          "saml.offline_signin_time_limit": {
+            "value": -1
+          }
+        }
+      },
+      {
+        "note": "Value below minimum should be clamped to minimum",
+        "policies": {
+          "SAMLOfflineSigninTimeLimit": -2
+        },
+        "prefs": {
+          "saml.offline_signin_time_limit": {
+            "value": -1
+          }
+        }
+      },
+      {
+        "note": "Default value (14 days)",
+        "policies": {},
+        "prefs": {
+          "saml.offline_signin_time_limit": {
+            "default_value": 1209600
+          }
         }
       }
+
     ]
   },
   "GaiaLockScreenOfflineSigninTimeLimitDays": {
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/BUILD.gn b/chrome/test/data/webui/chromeos/shimless_rma/BUILD.gn
index a46c487..50c687f 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/shimless_rma/BUILD.gn
@@ -20,6 +20,7 @@
     ":onboarding_select_components_page_test",
     ":onboarding_update_page_test",
     ":onboarding_wait_for_manual_wp_disable_page_test",
+    ":reimaging_accelerometer_calibration_page_test",
     ":reimaging_device_information_page_test",
     ":reimaging_firmware_update_page_test",
     ":reimaging_provisioning_page_test",
@@ -158,6 +159,14 @@
   externs_list = [ "$externs_path/mocha-2.5.js" ]
 }
 
+js_library("reimaging_accelerometer_calibration_page_test") {
+  deps = [
+    "../..:chai_assert",
+    "//ash/webui/shimless_rma/resources:reimaging_accelerometer_calibration_page",
+  ]
+  externs_list = [ "$externs_path/mocha-2.5.js" ]
+}
+
 js_library("reimaging_provisioning_page_test") {
   deps = [
     "../..:chai_assert",
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/reimaging_accelerometer_calibration_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_accelerometer_calibration_page_test.js
new file mode 100644
index 0000000..9c059b7
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_accelerometer_calibration_page_test.js
@@ -0,0 +1,105 @@
+// Copyright 2021 The Chromium 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 {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
+import {FakeShimlessRmaService} from 'chrome://shimless-rma/fake_shimless_rma_service.js';
+import {setShimlessRmaServiceForTesting} from 'chrome://shimless-rma/mojo_interface_provider.js';
+import {ReimagingAccelerometerCalibrationPageElement} from 'chrome://shimless-rma/reimaging_accelerometer_calibration_page.js';
+import {CalibrationComponent} from 'chrome://shimless-rma/shimless_rma_types.js';
+
+import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
+import {flushTasks} from '../../test_util.m.js';
+
+export function reimagingAccelerometerCalibrationPageTest() {
+  /** @type {?ReimagingAccelerometerCalibrationPageElement} */
+  let component = null;
+
+  /** @type {?FakeShimlessRmaService} */
+  let service = null;
+
+  suiteSetup(() => {
+    service = new FakeShimlessRmaService();
+    setShimlessRmaServiceForTesting(service);
+  });
+
+  setup(() => {
+    document.body.innerHTML = '';
+  });
+
+  teardown(() => {
+    component.remove();
+    component = null;
+    service.reset();
+  });
+
+  /**
+   * @return {!Promise}
+   */
+  function initializeCalibrationPage() {
+    assertFalse(!!component);
+
+    component = /** @type {!ReimagingAccelerometerCalibrationPageElement} */ (
+        document.createElement('reimaging-accelerometer-calibration-page'));
+    assertTrue(!!component);
+    document.body.appendChild(component);
+
+    return flushTasks();
+  }
+
+  test('Initializes', async () => {
+    await initializeCalibrationPage();
+    const preCalibration =
+        component.shadowRoot.querySelector('#preCalibration');
+    const Calibration = component.shadowRoot.querySelector('#calibration');
+    assertTrue(Calibration.hidden);
+    assertFalse(preCalibration.hidden);
+  });
+
+  test('NextButtonTriggersCalibration', async () => {
+    await initializeCalibrationPage();
+    component.onNextButtonClick().catch((err) => void 0);
+
+    const preCalibration =
+        component.shadowRoot.querySelector('#preCalibration');
+    const Calibration = component.shadowRoot.querySelector('#calibration');
+    assertFalse(Calibration.hidden);
+    assertTrue(preCalibration.hidden);
+  });
+
+  test('CalibrationComplete', async () => {
+    await initializeCalibrationPage();
+    component.onNextButtonClick().catch((err) => void 0);
+    await flushTasks();
+
+    service.triggerCalibrationObserver(
+        CalibrationComponent.kAccelerometer, 100, 0);
+    await flushTasks();
+
+    let savedResult;
+    let savedError;
+    component.onNextButtonClick()
+        .then((result) => savedResult = result)
+        .catch((error) => savedError = error);
+    await flushTasks();
+
+    assertTrue(!!savedResult);
+  });
+
+  test('CalibrationInProgress', async () => {
+    await initializeCalibrationPage();
+    component.onNextButtonClick().catch((err) => void 0);
+    await flushTasks();
+
+    let savedResult;
+    let savedError;
+    component.onNextButtonClick()
+        .then((result) => savedResult = result)
+        .catch((error) => savedError = error);
+    await flushTasks();
+
+    assertTrue(savedError instanceof Error);
+    assertEquals(savedError.message, 'Calibration is not complete.');
+    assertEquals(savedResult, undefined);
+  });
+}
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_browsertest.js b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_browsertest.js
index 6217660..59e764a 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_browsertest.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_browsertest.js
@@ -48,6 +48,7 @@
   'OnboardingSelectComponentsPageTest',
   'OnboardingUpdatePageTest',
   'OnboardingWaitForManualWpDisablePageTest',
+  'ReimagingAccelerometerCalibrationPageTest',
   'ReimagingFirmwareUpdatePageTest',
   'ReimagingDeviceInformationPageTest',
   'ReimagingProvisioningPageTest',
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_unified_test.js b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_unified_test.js
index e33110d8..65939291 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_unified_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/shimless_rma_unified_test.js
@@ -13,6 +13,7 @@
 import {onboardingSelectComponentsPageTest} from './onboarding_select_components_page_test.js';
 import {onboardingUpdatePageTest} from './onboarding_update_page_test.js';
 import {onboardingWaitForManualWpDisablePageTest} from './onboarding_wait_for_manual_wp_disable_page_test.js';
+import {reimagingAccelerometerCalibrationPageTest} from './reimaging_accelerometer_calibration_page_test.js';
 import {reimagingDeviceInformationPageTest} from './reimaging_device_information_page_test.js';
 import {reimagingFirmwareUpdatePageTest} from './reimaging_firmware_update_page_test.js';
 import {reimagingProvisioningPageTest} from './reimaging_provisioning_page_test.js';
@@ -43,6 +44,9 @@
 runSuite(
     'OnboardingWaitForManualWpDisablePageTest',
     onboardingWaitForManualWpDisablePageTest);
+runSuite(
+    'ReimagingAccelerometerCalibrationPageTest',
+    reimagingAccelerometerCalibrationPageTest);
 runSuite('ReimagingFirmwareUpdatePageTest', reimagingFirmwareUpdatePageTest);
 runSuite(
     'ReimagingDeviceInformationPageTest', reimagingDeviceInformationPageTest);
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn b/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn
index 89e11398..14eaa77 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn
@@ -13,6 +13,7 @@
                   ]
   deps = [
     ":accelerator_edit_dialog_test",
+    ":accelerator_edit_view_test",
     ":accelerator_row_test",
     ":accelerator_view_test",
     ":shortcut_customization_test",
@@ -54,3 +55,11 @@
   ]
   externs_list = [ "$externs_path/mocha-2.5.js" ]
 }
+
+js_library("accelerator_edit_view_test") {
+  deps = [
+    "../..:chai_assert",
+    "//ash/webui/shortcut_customization_ui/resources:accelerator_edit_view",
+  ]
+  externs_list = [ "$externs_path/mocha-2.5.js" ]
+}
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.js
index ee61c723..d136a75 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.js
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.js
@@ -41,13 +41,15 @@
     await flush();
     const dialog = viewElement.shadowRoot.querySelector('cr-dialog');
     assertTrue(dialog.open);
-    const acceleratorElements = dialog.querySelectorAll('accelerator-view');
+    const acceleratorElements =
+        dialog.querySelectorAll('accelerator-edit-view');
     assertEquals(2, acceleratorElements.length);
     assertEquals(
         description, dialog.querySelector('#dialogTitle').textContent.trim());
 
-    const keys1 =
-        acceleratorElements[0].shadowRoot.querySelectorAll('input-key');
+    const accelView1 =
+        acceleratorElements[0].shadowRoot.querySelector('accelerator-view');
+    const keys1 = accelView1.shadowRoot.querySelectorAll('input-key');
     // SHIFT + CONTROL + g
     assertEquals(3, keys1.length);
     assertEquals(
@@ -57,8 +59,9 @@
     assertEquals(
         'g', keys1[2].shadowRoot.querySelector('#key').textContent.trim());
 
-    const keys2 =
-        acceleratorElements[1].shadowRoot.querySelectorAll('input-key');
+    const accelView2 =
+        acceleratorElements[1].shadowRoot.querySelector('accelerator-view');
+    const keys2 = accelView2.shadowRoot.querySelectorAll('input-key');
     // CONTROL + c
     assertEquals(2, keys2.length);
     assertEquals(
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.js
new file mode 100644
index 0000000..cb73185
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_view_test.js
@@ -0,0 +1,65 @@
+// Copyright 2021 The Chromium 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 {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {AcceleratorEditViewElement} from 'chrome://shortcut-customization/accelerator_edit_view.js';
+import {ModifierKeys} from 'chrome://shortcut-customization/accelerator_view.js';
+
+import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
+
+export function acceleratorEditViewTest() {
+  /** @type {?AcceleratorEditViewElement} */
+  let editViewElement = null;
+
+  setup(() => {
+    editViewElement = /** @type {!AcceleratorEditViewElement} */ (
+        document.createElement('accelerator-edit-view'));
+    document.body.appendChild(editViewElement);
+  });
+
+  teardown(() => {
+    editViewElement.remove();
+    editViewElement = null;
+  });
+
+  test('LoadsBasicEditView', async () => {
+    // TODO(jimmyxgong): Update the type of the test accelerator with the mojom
+    // version.
+    const accelerator = {
+      modifiers: ModifierKeys.SHIFT | ModifierKeys.CONTROL,
+      key: 'g',
+      rawKey: 0x0
+    };
+
+    editViewElement.accelerator = accelerator;
+    await flush();
+
+    // Check that the edit buttons are visible.
+    assertFalse(
+        editViewElement.shadowRoot.querySelector('#editButtonsContainer')
+            .hidden);
+    assertTrue(
+        editViewElement.shadowRoot.querySelector('#cancelButtonContainer')
+            .hidden);
+
+    // Click on the edit button.
+    editViewElement.shadowRoot.querySelector('#editButton').click();
+
+    // Only the Cancel button should now be visible.
+    assertTrue(editViewElement.shadowRoot.querySelector('#editButtonsContainer')
+                   .hidden);
+    assertFalse(
+        editViewElement.shadowRoot.querySelector('#cancelButtonContainer')
+            .hidden);
+
+    // Click on the Cancel button and expect the edit buttons to be available.
+    editViewElement.shadowRoot.querySelector('#cancelButton').click();
+    assertFalse(
+        editViewElement.shadowRoot.querySelector('#editButtonsContainer')
+            .hidden);
+    assertTrue(
+        editViewElement.shadowRoot.querySelector('#cancelButtonContainer')
+            .hidden);
+  });
+}
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_browsertest.js b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_browsertest.js
index 978fbac..c206c09 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_browsertest.js
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_browsertest.js
@@ -42,6 +42,7 @@
 // although technically is not necessary.
 const debug_suites_list = [
   'ShortcutCustomizationApp',
+  'AcceleratorEditViewTest',
   'AcceleratorViewTest',
   'AcceleratorRowTest',
   'AcceleratorEditDialogTest',
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_unified_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_unified_test.js
index 3fb8dc7..c6218cd 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_unified_test.js
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_unified_test.js
@@ -5,6 +5,7 @@
 import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 
 import {acceleratorEditDialogTest} from './accelerator_edit_dialog_test.js';
+import {acceleratorEditViewTest} from './accelerator_edit_view_test.js';
 import {acceleratorRowTest} from './accelerator_row_test.js';
 import {acceleratorViewTest} from './accelerator_view_test.js';
 import {shortcutCustomizationAppTest} from './shortcut_customization_test.js';
@@ -17,6 +18,7 @@
 }
 
 runSuite('ShortcutCustomizationApp', shortcutCustomizationAppTest);
+runSuite('AcceleratorEditViewTest', acceleratorEditViewTest);
 runSuite('AcceleratorViewTest', acceleratorViewTest);
 runSuite('AcceleratorRowTest', acceleratorRowTest);
 runSuite('AcceleratorEditDialogTest', acceleratorEditDialogTest);
\ No newline at end of file
diff --git a/chrome/test/data/webui/new_tab_page/modules/drive_v2/module_test.js b/chrome/test/data/webui/new_tab_page/modules/drive_v2/module_test.js
index a2652a2..8602ab4 100644
--- a/chrome/test/data/webui/new_tab_page/modules/drive_v2/module_test.js
+++ b/chrome/test/data/webui/new_tab_page/modules/drive_v2/module_test.js
@@ -81,7 +81,7 @@
     assertTrue(!module);
   });
 
-  test('module has height of 56 with only one file', async () => {
+  test('module has height of 86 with only one file', async () => {
     const data = {
       files: [
         {
@@ -96,10 +96,10 @@
     await testProxy.handler.whenCalled('getFiles');
     module.$.fileRepeat.render();
 
-    assertEquals(56, module.offsetHeight);
+    assertEquals(86, module.offsetHeight);
   });
 
-  test('module has height of 112 with two files', async () => {
+  test('module has height of 142 with two files', async () => {
     const data = {
       files: [
         {
@@ -117,10 +117,10 @@
     await testProxy.handler.whenCalled('getFiles');
     module.$.fileRepeat.render();
 
-    assertEquals(112, module.offsetHeight);
+    assertEquals(142, module.offsetHeight);
   });
 
-  test('module has height of 168 with 3 files', async () => {
+  test('module has height of 198 with 3 files', async () => {
     const data = {
       files: [
         {
@@ -141,6 +141,6 @@
     await testProxy.handler.whenCalled('getFiles');
     module.$.fileRepeat.render();
 
-    assertEquals(168, module.offsetHeight);
+    assertEquals(198, module.offsetHeight);
   });
 });
diff --git a/chrome/test/data/webui/new_tab_page/modules/module_header_test.js b/chrome/test/data/webui/new_tab_page/modules/module_header_test.js
index e2abc7d7..bf3d5c0 100644
--- a/chrome/test/data/webui/new_tab_page/modules/module_header_test.js
+++ b/chrome/test/data/webui/new_tab_page/modules/module_header_test.js
@@ -38,6 +38,7 @@
     moduleHeader.showDismissButton = true;
     moduleHeader.dismissText = 'baz';
     moduleHeader.disableText = 'abc';
+    moduleHeader.showInfoButtonDropdown = true;
     render(moduleHeader);
 
     // Assert.
@@ -45,6 +46,9 @@
     assertEquals('bar', $$(moduleHeader, '#description').textContent.trim());
     assertEquals('baz', $$(moduleHeader, '#dismissButton').textContent.trim());
     assertEquals('abc', $$(moduleHeader, '#disableButton').textContent.trim());
+    assertEquals(
+        'Why am I seeing this?',
+        $$(moduleHeader, '#infoButton').textContent.trim());
   });
 
   test('clicking buttons sends events', () => {
@@ -78,4 +82,15 @@
     $$(moduleHeader, '#disableButton').click();
     assertFalse($$(moduleHeader, '#actionMenu').open);
   });
+
+  test('module icon appears', () => {
+    // Act.
+    moduleHeader.iconSrc = 'icons/module_logo.svg';
+    render(moduleHeader);
+
+    // Assert.
+    assertEquals(
+        'chrome://new-tab-page/icons/module_logo.svg',
+        $$(moduleHeader, '.module-icon').src);
+  });
 });
diff --git a/chrome/updater/mac/mac_util.mm b/chrome/updater/mac/mac_util.mm
index 29bc4db..c4b5bcd 100644
--- a/chrome/updater/mac/mac_util.mm
+++ b/chrome/updater/mac/mac_util.mm
@@ -4,6 +4,7 @@
 
 #import "chrome/updater/mac/mac_util.h"
 
+#include <sys/stat.h>
 #include <pwd.h>
 #include <unistd.h>
 
diff --git a/chromeos/components/BUILD.gn b/chromeos/components/BUILD.gn
index 2c61974..4255fb4 100644
--- a/chromeos/components/BUILD.gn
+++ b/chromeos/components/BUILD.gn
@@ -82,7 +82,6 @@
 
   if (!is_official_build) {
     deps += [
-      "//chromeos/components/demo_mode_app_ui:closure_compile",
       "//chromeos/components/sample_system_web_app_ui:closure_compile",
       "//chromeos/components/telemetry_extension_ui:closure_compile",
     ]
diff --git a/chromeos/components/camera_app_ui/resources/css/main.css b/chromeos/components/camera_app_ui/resources/css/main.css
index e8c1bf7f..66574c4 100644
--- a/chromeos/components/camera_app_ui/resources/css/main.css
+++ b/chromeos/components/camera_app_ui/resources/css/main.css
@@ -192,8 +192,6 @@
 }
 
 #shutters-group {
-  --shutter-size: 60px;
-
   bottom: var(--shutter-vertical-center);
   display: flex;
   flex-direction: column;
@@ -287,8 +285,9 @@
 }
 
 #confirm-result-groups>button {
-  flex: 0 0 76px;
   height: 72px;
+  margin-bottom: 2px;
+  margin-top: 2px;
   width: 72px;
 }
 
diff --git a/chromeos/components/camera_app_ui/resources/views/main.html b/chromeos/components/camera_app_ui/resources/views/main.html
index 69f6e8b..3025014 100644
--- a/chromeos/components/camera_app_ui/resources/views/main.html
+++ b/chromeos/components/camera_app_ui/resources/views/main.html
@@ -259,7 +259,7 @@
         <div id="paused-msg" i18n-text="record_video_paused_msg"></div>
         <div id="record-time-msg"></div>
       </div>
-      <div class="top-stripe right-stripe buttons">
+      <div class="top-stripe right-stripe circle buttons">
         <input id="toggle-mic" type="checkbox" tabindex="0"
                i18n-label="toggle_mic_button" data-state="mic"
                data-key="toggleMic" checked>
diff --git a/chromeos/components/demo_mode_app_ui/BUILD.gn b/chromeos/components/demo_mode_app_ui/BUILD.gn
index fd9c1eb..ae0d1c2 100644
--- a/chromeos/components/demo_mode_app_ui/BUILD.gn
+++ b/chromeos/components/demo_mode_app_ui/BUILD.gn
@@ -3,8 +3,6 @@
 # found in the LICENSE file.
 
 import("//chrome/test/base/js2gtest.gni")
-import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/grit/preprocess_if_expr.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
 assert(is_chromeos, "Demo Mode App is Chrome OS only")
@@ -14,31 +12,17 @@
   sources = [
     "demo_mode_app_ui.cc",
     "demo_mode_app_ui.h",
-    "demo_mode_page_handler.cc",
-    "demo_mode_page_handler.h",
     "url_constants.cc",
     "url_constants.h",
   ]
 
   deps = [
-    "//chromeos/components/demo_mode_app_ui/mojom",
     "//chromeos/resources:demo_mode_app_resources",
     "//content/public/browser",
-    "//ui/views",
     "//ui/webui",
   ]
 }
 
-js_type_check("closure_compile") {
-  deps = [ ":app" ]
-  closure_flags = default_closure_args + mojom_js_args
-}
-
-js_library("app") {
-  sources = [ "resources/page_handler.js" ]
-  deps = [ "//chromeos/components/demo_mode_app_ui/mojom:mojom_webui_js" ]
-}
-
 js2gtest("browser_tests_js") {
   test_type = "mojo_lite_webui"
 
@@ -47,27 +31,14 @@
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 }
 
-grd_prefix = "chromeos_demo_mode_app"
-mojo_grdp_file = "$target_gen_dir/demo_mode_app_mojo_resources.grdp"
-
-generate_grd("build_mojo_grdp") {
-  out_grd = mojo_grdp_file
-  grd_prefix = grd_prefix
-  deps = [ "//chromeos/components/demo_mode_app_ui/mojom:mojom_webui_js" ]
-  input_files = [ "chromeos/components/demo_mode_app_ui/mojom/demo_mode_app_ui.mojom-webui.js" ]
-  input_files_base_dir = rebase_path("$root_gen_dir/mojom-webui", "//")
-}
-
 generate_grd("build_grd") {
   input_files_base_dir = rebase_path("resources", "//")
-  deps = [ ":build_mojo_grdp" ]
   input_files = [
     "app_icon_192.png",
     "demo_mode_app.js",
     "demo_mode_app.html",
-    "page_handler.js",
   ]
-  grd_prefix = grd_prefix
+  manifest_files = []
+  grd_prefix = "chromeos_demo_mode_app"
   out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  grdp_files = [ mojo_grdp_file ]
 }
diff --git a/chromeos/components/demo_mode_app_ui/DEPS b/chromeos/components/demo_mode_app_ui/DEPS
index 20ecbdc..e3c2f2c 100644
--- a/chromeos/components/demo_mode_app_ui/DEPS
+++ b/chromeos/components/demo_mode_app_ui/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "+chromeos/grit/chromeos_demo_mode_app_resources.h",
   "+content/public/browser",
-  "+ui/views",
   "+ui/webui",
 ]
\ No newline at end of file
diff --git a/chromeos/components/demo_mode_app_ui/demo_mode_app_ui.cc b/chromeos/components/demo_mode_app_ui/demo_mode_app_ui.cc
index b6d415d..864d59a 100644
--- a/chromeos/components/demo_mode_app_ui/demo_mode_app_ui.cc
+++ b/chromeos/components/demo_mode_app_ui/demo_mode_app_ui.cc
@@ -3,14 +3,11 @@
 // found in the LICENSE file.
 
 #include "chromeos/components/demo_mode_app_ui/demo_mode_app_ui.h"
-#include "chromeos/components/demo_mode_app_ui/demo_mode_page_handler.h"
 #include "chromeos/components/demo_mode_app_ui/url_constants.h"
 #include "chromeos/grit/chromeos_demo_mode_app_resources.h"
 #include "chromeos/grit/chromeos_demo_mode_app_resources_map.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui_data_source.h"
-#include "services/network/public/mojom/content_security_policy.mojom.h"
-#include "ui/views/widget/widget.h"
 
 namespace chromeos {
 
@@ -34,22 +31,6 @@
 
 DemoModeAppUI::~DemoModeAppUI() = default;
 
-void DemoModeAppUI::BindInterface(
-    mojo::PendingReceiver<mojom::demo_mode::PageHandlerFactory> factory) {
-  if (demo_mode_page_factory_.is_bound()) {
-    demo_mode_page_factory_.reset();
-  }
-  demo_mode_page_factory_.Bind(std::move(factory));
-}
-
-void DemoModeAppUI::CreatePageHandler(
-    mojo::PendingReceiver<mojom::demo_mode::PageHandler> handler) {
-  views::Widget* widget = views::Widget::GetWidgetForNativeWindow(
-      web_ui()->GetWebContents()->GetTopLevelNativeWindow());
-  demo_mode_page_handler_ =
-      std::make_unique<DemoModePageHandler>(std::move(handler), widget);
-}
-
 WEB_UI_CONTROLLER_TYPE_IMPL(DemoModeAppUI)
 
 }  // namespace chromeos
diff --git a/chromeos/components/demo_mode_app_ui/demo_mode_app_ui.h b/chromeos/components/demo_mode_app_ui/demo_mode_app_ui.h
index 86801a6..9b7a24d 100644
--- a/chromeos/components/demo_mode_app_ui/demo_mode_app_ui.h
+++ b/chromeos/components/demo_mode_app_ui/demo_mode_app_ui.h
@@ -5,16 +5,11 @@
 #ifndef CHROMEOS_COMPONENTS_DEMO_MODE_APP_UI_DEMO_MODE_APP_UI_H_
 #define CHROMEOS_COMPONENTS_DEMO_MODE_APP_UI_DEMO_MODE_APP_UI_H_
 
-#include "chromeos/components/demo_mode_app_ui/mojom/demo_mode_app_ui.mojom.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 "ui/webui/mojo_web_ui_controller.h"
 
 namespace chromeos {
 // The WebUI for chrome://demo-mode-app
-class DemoModeAppUI : public ui::MojoWebUIController,
-                      public mojom::demo_mode::PageHandlerFactory {
+class DemoModeAppUI : public ui::MojoWebUIController {
  public:
   explicit DemoModeAppUI(content::WebUI* web_ui);
   ~DemoModeAppUI() override;
@@ -22,19 +17,7 @@
   DemoModeAppUI(const DemoModeAppUI&) = delete;
   DemoModeAppUI& operator=(const DemoModeAppUI&) = delete;
 
-  void BindInterface(
-      mojo::PendingReceiver<mojom::demo_mode::PageHandlerFactory> factory);
-
  private:
-  // mojom::DemoModePageHandlerFactory
-  void CreatePageHandler(
-      mojo::PendingReceiver<mojom::demo_mode::PageHandler> handler) override;
-
-  mojo::Receiver<mojom::demo_mode::PageHandlerFactory> demo_mode_page_factory_{
-      this};
-
-  std::unique_ptr<mojom::demo_mode::PageHandler> demo_mode_page_handler_;
-
   WEB_UI_CONTROLLER_TYPE_DECL();
 };
 
diff --git a/chromeos/components/demo_mode_app_ui/demo_mode_page_handler.cc b/chromeos/components/demo_mode_app_ui/demo_mode_page_handler.cc
deleted file mode 100644
index afe95dc6..0000000
--- a/chromeos/components/demo_mode_app_ui/demo_mode_page_handler.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2021 The Chromium 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/components/demo_mode_app_ui/demo_mode_page_handler.h"
-
-namespace chromeos {
-DemoModePageHandler::DemoModePageHandler(
-    mojo::PendingReceiver<mojom::demo_mode::PageHandler> pending_receiver,
-    views::Widget* widget)
-    : receiver_(this, std::move(pending_receiver)), widget_(widget) {}
-
-DemoModePageHandler::~DemoModePageHandler() = default;
-
-void DemoModePageHandler::ToggleFullscreen() {
-  widget_->SetFullscreen(!widget_->IsFullscreen());
-}
-}  // namespace chromeos
diff --git a/chromeos/components/demo_mode_app_ui/demo_mode_page_handler.h b/chromeos/components/demo_mode_app_ui/demo_mode_page_handler.h
deleted file mode 100644
index aa33befb..0000000
--- a/chromeos/components/demo_mode_app_ui/demo_mode_page_handler.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_COMPONENTS_DEMO_MODE_APP_UI_DEMO_MODE_PAGE_HANDLER_H_
-#define CHROMEOS_COMPONENTS_DEMO_MODE_APP_UI_DEMO_MODE_PAGE_HANDLER_H_
-
-#include "chromeos/components/demo_mode_app_ui/mojom/demo_mode_app_ui.mojom.h"
-
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "ui/views/widget/widget.h"
-
-namespace chromeos {
-
-class DemoModePageHandler : public mojom::demo_mode::PageHandler {
- public:
-  DemoModePageHandler(
-      mojo::PendingReceiver<mojom::demo_mode::PageHandler> pending_receiver,
-      views::Widget* widget);
-  ~DemoModePageHandler() override;
-
-  DemoModePageHandler(const PageHandler&) = delete;
-  DemoModePageHandler& operator=(const PageHandler&) = delete;
-
- private:
-  // Switch between fullscreen and not-fullscreen
-  void ToggleFullscreen() override;
-
-  mojo::Receiver<mojom::demo_mode::PageHandler> receiver_;
-
-  views::Widget* widget_;
-};
-}  // namespace chromeos
-#endif  // CHROMEOS_COMPONENTS_DEMO_MODE_APP_UI_DEMO_MODE_PAGE_HANDLER_H_
diff --git a/chromeos/components/demo_mode_app_ui/mojom/BUILD.gn b/chromeos/components/demo_mode_app_ui/mojom/BUILD.gn
deleted file mode 100644
index 39044af..0000000
--- a/chromeos/components/demo_mode_app_ui/mojom/BUILD.gn
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2021 The Chromium 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("//mojo/public/tools/bindings/mojom.gni")
-
-assert(is_chromeos, "Demo Mode App is Chrome OS only")
-assert(!is_official_build, "Demo Mode App is only built for unofficial builds")
-
-mojom("mojom") {
-  sources = [ "demo_mode_app_ui.mojom" ]
-  public_deps = [ "//mojo/public/mojom/base" ]
-  webui_module_path = "/chromeos/components/demo_mode_app_ui/mojom/"
-}
diff --git a/chromeos/components/demo_mode_app_ui/mojom/OWNERS b/chromeos/components/demo_mode_app_ui/mojom/OWNERS
deleted file mode 100644
index 61b5e28..0000000
--- a/chromeos/components/demo_mode_app_ui/mojom/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
\ No newline at end of file
diff --git a/chromeos/components/demo_mode_app_ui/mojom/demo_mode_app_ui.mojom b/chromeos/components/demo_mode_app_ui/mojom/demo_mode_app_ui.mojom
deleted file mode 100644
index 8a5be1f..0000000
--- a/chromeos/components/demo_mode_app_ui/mojom/demo_mode_app_ui.mojom
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2021 The Chromium 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 chromeos.mojom.demo_mode;
-
-// Implemented in the browser process. Interface for the Demo Mode WebUI to
-// retrieve an endpoint to the PageHandler interface, and to provide its own
-// Page endpoint to receive notifications.
-interface PageHandlerFactory {
-  // Create a page handler to provide one-way message passing between the WebUI
-  // and browser process
-  CreatePageHandler(pending_receiver<PageHandler> handler);
-};
-
-// Implemented in the Browser process. Interface for sending ToggleFullscreen()
-// commands from the Web UI to the browser process.
-interface PageHandler {
-  // Fire-and-forget command to trigger enter or exit fullscreen on a native
-  // window. Used for when we need to enter fullscreen without user interaction.
-  ToggleFullscreen();
-};
\ No newline at end of file
diff --git a/chromeos/components/demo_mode_app_ui/resources/demo_mode_app.html b/chromeos/components/demo_mode_app_ui/resources/demo_mode_app.html
index aadf7431..28ea452 100644
--- a/chromeos/components/demo_mode_app_ui/resources/demo_mode_app.html
+++ b/chromeos/components/demo_mode_app_ui/resources/demo_mode_app.html
@@ -8,14 +8,9 @@
   <title>Demo Mode App Title</title>
 </head>
 <body>
-  <h1 id="header">Demo Mode App</h1>
-  <button id="toggle-fullscreen">Toggle Fullscreen</button>
-  <button id="enter-fullscreen">Enter Fullscreen</button>
-  <button id="exit-fullscreen">Exit Fullscreen</button>
-  <!-- Test button that changes color of header if the Web Platform fullscreen state is active.
-    Its purpose is to show that the native window fullscreen (triggered via Mojo API) and the standard
-    element.requestFullscreen() are different -->
-  <button id="change-color">Change Color if WP Fullscreen Enabled</button>
+  <h1 id="header">Hello World</h1>
 </body>
-<script src="demo_mode_app.js" type="module"></script>
+  <script src="demo_mode_app.js" type="module"></script>
+<!-- Below mojo script required to run browser tests -->
+<script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script>
 </html>
\ No newline at end of file
diff --git a/chromeos/components/demo_mode_app_ui/resources/demo_mode_app.js b/chromeos/components/demo_mode_app_ui/resources/demo_mode_app.js
index e24a066b..20caad15 100644
--- a/chromeos/components/demo_mode_app_ui/resources/demo_mode_app.js
+++ b/chromeos/components/demo_mode_app_ui/resources/demo_mode_app.js
@@ -2,41 +2,5 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {pageHandler} from './page_handler.js';
-
-
-// Function to make arbitrary visible UI change only when
-// document.fullscreenElement is present - to help demonstrate the difference
-// between the two fullscreen methods (probably better to do this through data
-// binding).
-function changeColor() {
-  let header = document.getElementById("header");
-  if (document.fullscreenElement) {
-    if (header.style.color === "blue") {
-      header.style.color = "red";
-    } else {
-      header.style.color = "blue";
-    }
-  }
-}
-
-document.addEventListener('DOMContentLoaded', function () {
-  window.pageHandler = pageHandler;
-  // Mojo API triggering native widget RequestFullscreen()
-  const toggleFullscreenButton = document.getElementById('toggle-fullscreen');
-  toggleFullscreenButton.addEventListener('click',
-      () => pageHandler.toggleFullscreen());
-
-  // Web platform standard way of entering and exiting fullscreen
-  const enterFullscreenButton = document.getElementById('enter-fullscreen');
-  enterFullscreenButton.addEventListener('click',
-      () => document.documentElement.requestFullscreen());
-  const exitFullscreenButton = document.getElementById('exit-fullscreen');
-  exitFullscreenButton.addEventListener('click',
-      () => document.exitFullscreen());
-
-  const changeColorButton = document.getElementById('change-color');
-  changeColorButton.addEventListener('click', () => changeColor());
-
-  pageHandler.toggleFullscreen();
-});
+var header = document.getElementById('header');
+header.textContent = 'Demo Mode App';
diff --git a/chromeos/components/demo_mode_app_ui/resources/page_handler.js b/chromeos/components/demo_mode_app_ui/resources/page_handler.js
deleted file mode 100644
index 263e2ad..0000000
--- a/chromeos/components/demo_mode_app_ui/resources/page_handler.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2021 The Chromium 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 {PageHandlerFactory, PageHandlerRemote} from '/chromeos/components/demo_mode_app_ui/mojom/demo_mode_app_ui.mojom-webui.js';
-
-/**
- * Provides interfaces for sending and receiving messages to/from the browser
- * process via Mojo APIs.
- */
-class PageHandler {
-  constructor() {
-    this.handler = new PageHandlerRemote();
-
-    const factoryRemote = PageHandlerFactory.getRemote();
-    factoryRemote.createPageHandler(
-        this.handler.$.bindNewPipeAndPassReceiver());
-  }
-
-  toggleFullscreen() {
-    this.handler.toggleFullscreen();
-  }
-}
-
-export const pageHandler = new PageHandler();
diff --git a/chromeos/components/personalization_app/resources/common/styles.js b/chromeos/components/personalization_app/resources/common/styles.js
index 11dcd6e..7f6abd7 100644
--- a/chromeos/components/personalization_app/resources/common/styles.js
+++ b/chromeos/components/personalization_app/resources/common/styles.js
@@ -19,35 +19,6 @@
 
       /* copied from |AshColorProvider| |kSecondToneOpacity| constant. */
       --personalization-app-second-tone-opacity: 0.3;
-
-      --personalization-app-font-google-sans: 'Google Sans', 'Noto Sans',
-          sans-serif;
-      --personalization-app-font-roboto: Roboto, 'Noto Sans', sans-serif;
-
-      --personalization-app-typeface-headline-1: {
-        font-family: var(--personalization-app-font-google-sans);
-        font-weight: 500;
-        font-size: 15px;
-        line-height: 22px;
-      };
-      --personalization-app-typeface-body-2: {
-        font-family: var(--personalization-app-font-roboto);
-        font-weight: 400;
-        font-size: 13px;
-        line-height: 20px;
-      };
-      --personalization-app-typeface-display-6: {
-        font-family: var(--personalization-app-font-google-sans);
-        font-weight: 500;
-        font-size: 22px;
-        line-height: 28px;
-      };
-      --personalization-app-typeface-annotation-2: {
-        font-family: var(--personalization-app-font-roboto);
-        font-weight: 400;
-        font-size: 11px;
-        line-height: 16px;
-      };
     }
     iron-list {
       height: 100%;
@@ -133,8 +104,8 @@
       z-index: 2;
     }
     .photo-text-container > p {
-      @apply --personalization-app-typeface-annotation-2;
       color: white;
+      font: var(--cros-annotation-2-font);
       margin: 0;
       max-width: 100%;
       overflow: hidden;
@@ -144,7 +115,7 @@
       white-space: nowrap;
     }
     .photo-text-container > p:first-child {
-      @apply --personalization-app-typeface-headline-1;
+      font: var(--cros-headline-1-font);
     }
     .photo-gradient-mask {
       border-radius: 12px;
diff --git a/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.html b/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.html
index f606230..e7e6925 100644
--- a/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.html
+++ b/chromeos/components/personalization_app/resources/trusted/wallpaper_breadcrumb_element.html
@@ -14,12 +14,12 @@
   }
 
   #textContainer {
-    @apply --personalization-app-typeface-headline-1;
     color: var(--cros-text-color-secondary);
     align-items: center;
     box-sizing: border-box;
     display: flex;
     flex-flow: row nowrap;
+    font: var(--cros-headline-1-font);
     height: 100%;
   }
 
diff --git a/chromeos/components/personalization_app/resources/trusted/wallpaper_selected_element.html b/chromeos/components/personalization_app/resources/trusted/wallpaper_selected_element.html
index f2bfa3e2b..380d85a7 100644
--- a/chromeos/components/personalization_app/resources/trusted/wallpaper_selected_element.html
+++ b/chromeos/components/personalization_app/resources/trusted/wallpaper_selected_element.html
@@ -41,13 +41,13 @@
   }
 
   #textContainer > p:first-child {
-    @apply --personalization-app-typeface-body-2;
     color: var(--cros-text-color-secondary);
+    font: var(--cros-body-2-font);
   }
 
   #textContainer > p:nth-child(2) {
-    @apply --personalization-app-typeface-display-6;
     color: var(--cros-text-color-primary);
+    font: var(--cros-display-6-font);
   }
 
   #textContainer > p:nth-child(n+3) {
diff --git a/chromeos/network/device_state.cc b/chromeos/network/device_state.cc
index e0937552..698fa88c 100644
--- a/chromeos/network/device_state.cc
+++ b/chromeos/network/device_state.cc
@@ -6,8 +6,6 @@
 
 #include <memory>
 
-#include "ash/constants/ash_features.h"
-#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/values.h"
@@ -37,13 +35,6 @@
     return GetBooleanValue(key, value, &scanning_);
   } else if (key == shill::kSupportNetworkScanProperty) {
     return GetBooleanValue(key, value, &support_network_scan_);
-  } else if ((base::FeatureList::IsEnabled(
-                  ash::features::kCellularAllowPerNetworkRoaming) &&
-              key == shill::kCellularPolicyAllowRoamingProperty) ||
-             (!base::FeatureList::IsEnabled(
-                  ash::features::kCellularAllowPerNetworkRoaming) &&
-              key == shill::kCellularAllowRoamingProperty)) {
-    return GetBooleanValue(key, value, &allow_roaming_);
   } else if (key == shill::kProviderRequiresRoamingProperty) {
     return GetBooleanValue(key, value, &provider_requires_roaming_);
   } else if (key == shill::kHomeProviderProperty) {
diff --git a/chromeos/network/device_state.h b/chromeos/network/device_state.h
index d025331..d0f0d0c 100644
--- a/chromeos/network/device_state.h
+++ b/chromeos/network/device_state.h
@@ -41,7 +41,6 @@
   // Cellular specific accessors
   const std::string& operator_name() const { return operator_name_; }
   const std::string& country_code() const { return country_code_; }
-  bool allow_roaming() const { return allow_roaming_; }
   bool provider_requires_roaming() const { return provider_requires_roaming_; }
   bool support_network_scan() const { return support_network_scan_; }
   const std::string& technology_family() const { return technology_family_; }
@@ -104,7 +103,6 @@
   // Cellular specific properties
   std::string operator_name_;
   std::string country_code_;
-  bool allow_roaming_ = false;
   bool provider_requires_roaming_ = false;
   bool support_network_scan_ = false;
   bool scanning_ = false;
diff --git a/chromeos/network/network_device_handler_impl.cc b/chromeos/network/network_device_handler_impl.cc
index 509366e..ae34021b 100644
--- a/chromeos/network/network_device_handler_impl.cc
+++ b/chromeos/network/network_device_handler_impl.cc
@@ -291,17 +291,11 @@
   for (NetworkStateHandler::DeviceStateList::const_iterator it = list.begin();
        it != list.end(); ++it) {
     const DeviceState* device_state = *it;
-    bool current_allow_roaming = device_state->allow_roaming();
 
     // If roaming is required by the provider, always try to set to true.
     bool new_device_value =
         device_state->provider_requires_roaming() || cellular_allow_roaming_;
 
-    // Only set the value if the current value is different from
-    // |new_device_value|.
-    if (new_device_value == current_allow_roaming)
-      continue;
-
     SetDevicePropertyInternal(
         device_state->path(),
         base::FeatureList::IsEnabled(
diff --git a/chromeos/services/ime/public/proto/messages.proto b/chromeos/services/ime/public/proto/messages.proto
index 062a14b..f26c9be 100644
--- a/chromeos/services/ime/public/proto/messages.proto
+++ b/chromeos/services/ime/public/proto/messages.proto
@@ -21,264 +21,8 @@
   }
 }
 
-// Public messages between IME service and the shared library.
-// Each 'oneof' submessage represents a Mojo call / response.
+// Deprecated. Only private messages are supported now.
+// TODO(b/151884011): Remove this as part of the physical keyboard code rewrite.
 message PublicMessage {
-  optional int32 seq_id = 1;
-
-  oneof param {
-    OnFocus on_focus = 2;
-    OnKeyEvent on_key_event = 3;
-    OnKeyEventReply on_key_event_reply = 4;
-    OnSurroundingTextChanged on_surrounding_text_changed = 5;
-    OnBlur on_blur = 6;
-    OnCompositionCanceled on_composition_canceled = 7;
-    OnInputMethodChanged on_input_method_changed = 8;
-    CommitText commit_text = 9;
-    SetComposition set_composition = 10;
-    SetCompositionRange set_composition_range = 11;
-    FinishComposition finish_composition = 12;
-    DeleteSurroundingText delete_surrounding_text = 13;
-    HandleAutocorrect handle_autocorrect = 14;
-    SuggestionsRequest suggestions_request = 15;
-    SuggestionsResponse suggestions_response = 16;
-    DisplaySuggestions display_suggestions = 17;
-    RecordUkm record_ukm = 18;
-  }
-}
-
-// Protobuf version of the reply from InputEngine::InputFieldInfo in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message InputFieldInfo {
-  enum InputFieldType {
-    INPUT_FIELD_TYPE_UNSPECIFIED = 0;  // Reserved
-    INPUT_FIELD_TYPE_NO_IME = 1;
-    INPUT_FIELD_TYPE_TEXT = 2;
-    INPUT_FIELD_TYPE_SEARCH = 3;
-    INPUT_FIELD_TYPE_TELEPHONE = 4;
-    INPUT_FIELD_TYPE_URL = 5;
-    INPUT_FIELD_TYPE_EMAIL = 6;
-    INPUT_FIELD_TYPE_NUMBER = 7;
-    INPUT_FIELD_TYPE_PASSWORD = 8;
-  }
-
-  enum AutocorrectMode {
-    AUTOCORRECT_MODE_UNSPECIFIED = 0;  // Reserved
-    AUTOCORRECT_MODE_DISABLED = 1;
-    AUTOCORRECT_MODE_ENABLED = 2;
-  }
-
-  enum PersonalizationMode {
-    PERSONALIZATION_MODE_UNSPECIFIED = 0;  // Reserved
-    PERSONALIZATION_MODE_DISABLED = 1;
-    PERSONALIZATION_MODE_ENABLED = 2;
-  }
-
-  optional InputFieldType type = 1;
-  optional AutocorrectMode autocorrect = 2;
-  optional PersonalizationMode personalization = 3;
-}
-
-// Protobuf version of InputEngine::OnInputMethodChanged in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message OnInputMethodChanged {
-  optional string engine_id = 1;
-}
-
-// Protobuf version of InputEngine::OnFocus in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message OnFocus {
-  optional InputFieldInfo info = 1;
-}
-
-// Protobuf version of InputEngine::OnBlur in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message OnBlur {}
-
-// Protobuf version of InputEngine::OnKeyEvent in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message OnKeyEvent {
-  optional PhysicalKeyEvent key_event = 1;
-}
-
-// Protobuf version of the reply from InputEngine::OnKeyEvent in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message OnKeyEventReply {
-  optional bool consumed = 1;
-}
-
-// Protobuf version of InputEngine::PhysicalKeyEvent in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message PhysicalKeyEvent {
-  enum EventType {
-    EVENT_TYPE_UNSPECIFIED = 0;
-    EVENT_TYPE_KEY_DOWN = 1;
-    EVENT_TYPE_KEY_UP = 2;
-  }
-
-  optional EventType type = 1;
-  optional string code = 2;
-  optional string key = 3;
-  optional ModifierState modifier_state = 4;
-}
-
-// Protobuf version of InputEngine::PhysicalKeyEvent in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message ModifierState {
-  optional bool alt = 1;
-  optional bool alt_graph = 2;
-  optional bool caps_lock = 3;
-  optional bool control = 4;
-  optional bool meta = 5;
-  optional bool shift = 6;
-}
-
-// Protobuf version of InputEngine::SelectionRange in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message SelectionRange {
-  optional uint32 anchor = 1;
-  optional uint32 focus = 2;
-}
-
-// Protobuf version of gfx.mojom.Range in
-// ui/gfx/range/mojom/range.mojom
-message Range {
-  optional uint32 start = 1;
-  optional uint32 end = 2;
-}
-
-// Protobuf version of InputEngine::AutocorrectSpan in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message AutocorrectSpan {
-  optional Range autocorrect_range = 1;
-  optional string original_text = 2;
-  optional string current_text = 3;
-};
-
-// Protobuf version of InputEngine::OnSurroundingTextChanged in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message OnSurroundingTextChanged {
-  optional string text = 1;
-  optional uint32 offset = 2;
-  optional SelectionRange selection_range = 3;
-}
-
-// Protobuf version of InputEngine::OnCompositionCanceled in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message OnCompositionCanceled {}
-
-// Protobuf version of InputEngine::CommitTextCursorBehavior in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-enum CommitTextCursorBehavior {
-  COMMIT_TEXT_CURSOR_BEHAVIOR_UNSPECIFIED = 0;  // Reserved
-  COMMIT_TEXT_CURSOR_BEHAVIOR_MOVE_CURSOR_AFTER_TEXT = 1;
-  COMMIT_TEXT_CURSOR_BEHAVIOR_MOVE_CURSOR_BEFORE_TEXT = 2;
-}
-
-// Protobuf version of InputEngine::CommitText in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message CommitText {
-  optional string text = 1;
-  optional CommitTextCursorBehavior cursor_behavior = 2;
-}
-
-// Protobuf version of InputEngine::SetComposition in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message SetComposition {
-  optional string text = 1;
-}
-
-// Protobuf version of InputEngine::SetCompositionRange in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message SetCompositionRange {
-  optional uint32 start_byte_index = 1;
-  optional uint32 end_byte_index = 2;
-}
-
-// Protobuf version of InputEngine::FinishComposition in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message FinishComposition {}
-
-// Protobuf version of InputEngine::DeleteSurroundingText in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message DeleteSurroundingText {
-  optional uint32 num_bytes_before_cursor = 1;
-  optional uint32 num_bytes_after_cursor = 2;
-}
-
-// Protobuf version of InputEngine::HandleAutocorrect in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message HandleAutocorrect {
-  optional AutocorrectSpan autocorrect_span = 1;
-}
-
-// Protobuf version of CompletionCandidate in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message CompletionCandidate {
-  optional string text = 1;
-  optional float normalized_score = 2;
-}
-
-// Protobuf version of SuggestionMode in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-enum SuggestionMode {
-  SUGGESTION_MODE_UNSPECIFIED = 0;
-  SUGGESTION_MODE_COMPLETION = 1;
-  SUGGESTION_MODE_PREDICTION = 2;
-}
-
-// Protobuf version of SuggestionType in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-enum SuggestionType {
-  SUGGESTION_TYPE_UNSPECIFIED = 0;
-  SUGGESTION_TYPE_ASSISTIVE_PERSONAL_INFO = 1;
-  SUGGESTION_TYPE_ASSISTIVE_EMOJI = 2;
-  SUGGESTION_TYPE_MULTI_WORD = 3;
-}
-
-// Protobuf version of SuggestionsRequest in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message SuggestionsRequest {
-  optional string text = 1;
-  repeated CompletionCandidate completion_candidates = 2;
-  optional SuggestionMode suggestion_mode = 3;
-}
-
-// Protobuf version of SuggestionCandidate in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message SuggestionCandidate {
-  optional SuggestionMode mode = 1;
-  optional SuggestionType type = 2;
-  optional string text = 3;
-}
-
-// Protobuf version of SuggestionsResponse in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message SuggestionsResponse {
-  repeated SuggestionCandidate candidates = 1;
-}
-
-// Protobuf version of DisplaySuggestions in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message DisplaySuggestions {
-  repeated SuggestionCandidate candidates = 1;
-}
-
-// Protobuf version of InputEngine::RecordUkm in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message RecordUkm {
-  oneof entry { NonCompliantApiMetric non_compliant_api = 1; }
-}
-
-// Protobuf version of NonCompliantApiMetric in
-// chromeos/services/ime/public/mojom/input_engine.mojom
-message NonCompliantApiMetric {
-  enum InputMethodApiOperation {
-    OPERATION_UNSPECIFIED = 0;  // Reserved
-    OPERATION_COMMIT_TEXT = 1;
-    OPERATION_SET_COMPOSITION_TEXT = 2;
-    OPERATION_DELETE_SURROUNDING_TEXT = 3;
-  }
-
-  optional InputMethodApiOperation non_compliant_operation = 1;
+  reserved 1 to 18;
 }
diff --git a/components/autofill_assistant/browser/action_value.proto b/components/autofill_assistant/browser/action_value.proto
index eee0976..807947d 100644
--- a/components/autofill_assistant/browser/action_value.proto
+++ b/components/autofill_assistant/browser/action_value.proto
@@ -31,6 +31,11 @@
       // A plain text.
       string text = 2;
     }
+
+    // If the chunk fully matches the key, it will be replaced. When used
+    // in a regular expression context, the key needs to be quoted. Similarly,
+    // the replacement will be substituted as is, without being quoted.
+    map<string, string> replacements = 3;
   }
   repeated Chunk chunk = 1;
 }
diff --git a/components/autofill_assistant/browser/field_formatter.cc b/components/autofill_assistant/browser/field_formatter.cc
index 11ffed0..b0590df 100644
--- a/components/autofill_assistant/browser/field_formatter.cc
+++ b/components/autofill_assistant/browser/field_formatter.cc
@@ -18,6 +18,8 @@
 #include "third_party/re2/src/re2/re2.h"
 #include "third_party/re2/src/re2/stringpiece.h"
 
+namespace autofill_assistant {
+namespace field_formatter {
 namespace {
 // Regex to find placeholders of the form ${key}, where key is an arbitrary
 // string that does not contain curly braces. The first capture group is for
@@ -81,10 +83,17 @@
   }
 }
 
-}  // namespace
+std::string ApplyChunkReplacement(
+    const google::protobuf::Map<std::string, std::string>& replacements,
+    const std::string& value) {
+  const auto& it = replacements.find(value);
+  if (it != replacements.end()) {
+    return it->second;
+  }
+  return value;
+}
 
-namespace autofill_assistant {
-namespace field_formatter {
+}  // namespace
 
 absl::optional<std::string> FormatString(
     const std::string& pattern,
@@ -125,9 +134,10 @@
     std::string* out_value) {
   out_value->clear();
   for (const auto& chunk : value_expression.chunk()) {
+    std::string chunk_value;
     switch (chunk.chunk_case()) {
       case ValueExpression::Chunk::kText:
-        out_value->append(chunk.text());
+        chunk_value = chunk.text();
         break;
       case ValueExpression::Chunk::kKey: {
         auto rewrite_value =
@@ -136,15 +146,16 @@
           return ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE);
         }
         if (quote_meta) {
-          out_value->append(re2::RE2::QuoteMeta(*rewrite_value));
+          chunk_value = re2::RE2::QuoteMeta(*rewrite_value);
         } else {
-          out_value->append(*rewrite_value);
+          chunk_value = *rewrite_value;
         }
         break;
       }
       case ValueExpression::Chunk::CHUNK_NOT_SET:
         return ClientStatus(INVALID_ACTION);
     }
+    out_value->append(ApplyChunkReplacement(chunk.replacements(), chunk_value));
   }
 
   return OkClientStatus();
diff --git a/components/autofill_assistant/browser/field_formatter_unittest.cc b/components/autofill_assistant/browser/field_formatter_unittest.cc
index 951a625..fc358946 100644
--- a/components/autofill_assistant/browser/field_formatter_unittest.cc
+++ b/components/autofill_assistant/browser/field_formatter_unittest.cc
@@ -35,6 +35,12 @@
 using ::testing::Eq;
 using ::testing::IsSupersetOf;
 
+void AddReplacement(ValueExpression::Chunk* chunk,
+                    const std::string& match,
+                    const std::string& replacement) {
+  (*chunk->mutable_replacements())[match] = replacement;
+}
+
 class FieldFormatterStateMapTest : public ::testing::Test {
  public:
   FieldFormatterStateMapTest() = default;
@@ -263,6 +269,46 @@
   EXPECT_EQ(std::string(), result);
 }
 
+TEST(FieldFormatterTest, FormatExpressionWithReplacements) {
+  std::map<std::string, std::string> mappings = {
+      {"1", "A"}, {"2", "B"}, {"3", "+41"}};
+  std::string result;
+
+  ValueExpression value_expression;
+  auto* static_chunk = value_expression.add_chunk();
+  static_chunk->set_text("static");
+  AddReplacement(static_chunk, "static", "replacement1");
+  auto* match_chunk = value_expression.add_chunk();
+  match_chunk->set_key(1);
+  AddReplacement(match_chunk, "a", "replacement2");
+  AddReplacement(match_chunk, "A", "replacement3");
+  auto* no_match_chunk = value_expression.add_chunk();
+  no_match_chunk->set_key(2);
+  AddReplacement(no_match_chunk, "b", "replacement4");
+  EXPECT_EQ(ACTION_APPLIED, FormatExpression(value_expression, mappings,
+                                             /* quote_meta= */ false, &result)
+                                .proto_status());
+  EXPECT_EQ("replacement1replacement3B", result);
+
+  ValueExpression value_expression_regexp;
+  auto* regexp_chunk = value_expression_regexp.add_chunk();
+  regexp_chunk->set_key(3);
+  AddReplacement(regexp_chunk, "+41", "+0041");
+  EXPECT_EQ(ACTION_APPLIED, FormatExpression(value_expression_regexp, mappings,
+                                             /* quote_meta= */ false, &result)
+                                .proto_status());
+  EXPECT_EQ("+0041", result);
+  EXPECT_EQ(ACTION_APPLIED, FormatExpression(value_expression_regexp, mappings,
+                                             /* quote_meta= */ true, &result)
+                                .proto_status());
+  EXPECT_EQ("\\+41", result);
+  AddReplacement(regexp_chunk, "\\+41", "\\+0041");
+  EXPECT_EQ(ACTION_APPLIED, FormatExpression(value_expression_regexp, mappings,
+                                             /* quote_meta= */ true, &result)
+                                .proto_status());
+  EXPECT_EQ("\\+0041", result);
+}
+
 TEST(FieldFormatterTest, GetHumanReadableValueExpression) {
   ValueExpression value_expression;
   value_expression.add_chunk()->set_text("+");
diff --git a/components/browser_ui/widget/android/BUILD.gn b/components/browser_ui/widget/android/BUILD.gn
index e36d4878..4365efa 100644
--- a/components/browser_ui/widget/android/BUILD.gn
+++ b/components/browser_ui/widget/android/BUILD.gn
@@ -183,10 +183,10 @@
     "java/res/drawable/async_image_view_waiting.xml",
     "java/res/drawable/bottom_sheet_background.xml",
     "java/res/drawable/hairline_border_card_background.xml",
-    "java/res/drawable/hairline_border_card_dark_transparent_bg.xml",
     "java/res/drawable/ic_check_googblue_24dp_animated.xml",
     "java/res/drawable/ic_offline_pin_blue_white.xml",
     "java/res/drawable/ic_settings_gear_24dp.xml",
+    "java/res/drawable/incognito_card_bg.xml",
     "java/res/drawable/list_item_icon_modern_bg.xml",
     "java/res/drawable/modern_toolbar_text_box_background.xml",
     "java/res/drawable/query_tile_overlay.xml",
diff --git a/components/browser_ui/widget/android/java/res/drawable/hairline_border_card_dark_transparent_bg.xml b/components/browser_ui/widget/android/java/res/drawable/incognito_card_bg.xml
similarity index 60%
rename from components/browser_ui/widget/android/java/res/drawable/hairline_border_card_dark_transparent_bg.xml
rename to components/browser_ui/widget/android/java/res/drawable/incognito_card_bg.xml
index ce7444e4..713761d 100644
--- a/components/browser_ui/widget/android/java/res/drawable/hairline_border_card_dark_transparent_bg.xml
+++ b/components/browser_ui/widget/android/java/res/drawable/incognito_card_bg.xml
@@ -6,7 +6,6 @@
 <shape
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle" >
-    <solid android:color="@android:color/transparent" />
-    <stroke android:width="1dp" android:color="@color/hairline_stroke_color_dark"/>
-    <corners android:radius="@dimen/default_rounded_corner_radius" />
+    <solid android:color="@color/incognito_card_bg_color" />
+    <corners android:radius="@dimen/card_rounded_corner_radius" />
 </shape>
diff --git a/components/browser_ui/widget/android/java/res/layout/promo_card_view_compact.xml b/components/browser_ui/widget/android/java/res/layout/promo_card_view_compact.xml
index 5c4b05d..bf4b52f 100644
--- a/components/browser_ui/widget/android/java/res/layout/promo_card_view_compact.xml
+++ b/components/browser_ui/widget/android/java/res/layout/promo_card_view_compact.xml
@@ -8,7 +8,6 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    app:cardElevation="@dimen/default_elevation_1"
     style="@style/MaterialCardStyle">
 
   <LinearLayout
diff --git a/components/browser_ui/widget/android/java/res/layout/promo_card_view_large.xml b/components/browser_ui/widget/android/java/res/layout/promo_card_view_large.xml
index 44d824f..cfae058 100644
--- a/components/browser_ui/widget/android/java/res/layout/promo_card_view_large.xml
+++ b/components/browser_ui/widget/android/java/res/layout/promo_card_view_large.xml
@@ -8,7 +8,6 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    app:cardElevation="@dimen/default_elevation_1"
     style="@style/MaterialCardStyle">
 
   <LinearLayout
diff --git a/components/browser_ui/widget/android/java/res/layout/promo_card_view_slim.xml b/components/browser_ui/widget/android/java/res/layout/promo_card_view_slim.xml
index a1ca1b4..79aba69 100644
--- a/components/browser_ui/widget/android/java/res/layout/promo_card_view_slim.xml
+++ b/components/browser_ui/widget/android/java/res/layout/promo_card_view_slim.xml
@@ -8,7 +8,6 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    app:cardElevation="@dimen/default_elevation_1"
     style="@style/MaterialCardStyle">
 
   <LinearLayout
diff --git a/components/browser_ui/widget/android/java/res/values/dimens.xml b/components/browser_ui/widget/android/java/res/values/dimens.xml
index 02702a48..19b1cdc 100644
--- a/components/browser_ui/widget/android/java/res/values/dimens.xml
+++ b/components/browser_ui/widget/android/java/res/values/dimens.xml
@@ -9,6 +9,7 @@
     <dimen name="card_padding">16dp</dimen>
     <dimen name="clear_text_button_end_padding">10dp</dimen>
     <dimen name="default_rounded_corner_radius">8dp</dimen>
+    <dimen name="card_rounded_corner_radius">16dp</dimen>
 
     <!-- DualControlLayout -->
     <dimen name="dual_control_margin_between_items">8dp</dimen>
diff --git a/components/browser_ui/widget/android/java/res/values/styles.xml b/components/browser_ui/widget/android/java/res/values/styles.xml
index dbe9a60..7c50f4a 100644
--- a/components/browser_ui/widget/android/java/res/values/styles.xml
+++ b/components/browser_ui/widget/android/java/res/values/styles.xml
@@ -6,7 +6,7 @@
 <resources>
     <!-- Card styles -->
     <style name="CardTransparentForDark">
-        <item name="android:background">@drawable/hairline_border_card_dark_transparent_bg</item>
+        <item name="android:background">@drawable/incognito_card_bg</item>
     </style>
 
     <style name="MaterialCardStyle" parent="Widget.MaterialComponents.CardView">
@@ -15,7 +15,7 @@
     </style>
 
     <style name="MaterialCardShape" parent="ShapeAppearance.MaterialComponents.MediumComponent">
-        <item name="cornerSize">16dp</item>
+        <item name="cornerSize">@dimen/card_rounded_corner_radius</item>
     </style>
 
     <style name="ListActionButton" parent="@style/TextButton">
diff --git a/components/policy/proto/chrome_device_policy.proto b/components/policy/proto/chrome_device_policy.proto
index 5b711a0..3cb0a2a 100644
--- a/components/policy/proto/chrome_device_policy.proto
+++ b/components/policy/proto/chrome_device_policy.proto
@@ -1763,7 +1763,7 @@
 // Setting that controls whether system-wide trace collection using the Perfetto
 // system tracing service is allowed.
 message DeviceSystemWideTracingEnabledProto {
-  optional bool enabled = 1 [default = true];
+  optional bool enabled = 1 [default = false];
 }
 
 // Setting that controls whether data access is enabled for Thunderbolt/USB4
diff --git a/components/services/app_service/public/mojom/types.mojom b/components/services/app_service/public/mojom/types.mojom
index aac5e06..f740a40 100644
--- a/components/services/app_service/public/mojom/types.mojom
+++ b/components/services/app_service/public/mojom/types.mojom
@@ -126,6 +126,10 @@
 };
 
 // How the app was installed.
+// This should be kept in sync with histogram.xml, and InstallSource in
+// enums.xml.
+// Note the enumeration is used in UMA histogram so entries should not be
+// re-ordered or removed. New entries should be added at the bottom.
 enum InstallSource {
   kUnknown = 0,
   kSystem,     // Installed with the system and is considered a part of the OS.
diff --git a/components/translate/core/browser/translate_metrics_logger_impl.cc b/components/translate/core/browser/translate_metrics_logger_impl.cc
index 55cfb58b..b36b189 100644
--- a/components/translate/core/browser/translate_metrics_logger_impl.cc
+++ b/components/translate/core/browser/translate_metrics_logger_impl.cc
@@ -7,6 +7,8 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/metrics_hashes.h"
 #include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
+#include "components/prefs/pref_service.h"
 #include "components/translate/core/browser/translate_manager.h"
 #include "services/metrics/public/cpp/metrics_utils.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
@@ -61,10 +63,55 @@
 const char kTranslatePageLoadTriggerDecision[] =
     "Translate.PageLoad.TriggerDecision";
 
+// Application frequency UMA histograms.
+const char kTranslateApplicationStartAlwaysTranslateLanguage[] =
+    "Translate.ApplicationStart.AlwaysTranslateLanguage";
+const char kTranslateApplicationStartAlwaysTranslateLanguageCount[] =
+    "Translate.ApplicationStart.AlwaysTranslateLanguage.Count";
+const char kTranslateApplicationStartNeverTranslateLanguage[] =
+    "Translate.ApplicationStart.NeverTranslateLanguage";
+const char kTranslateApplicationStartNeverTranslateLanguageCount[] =
+    "Translate.ApplicationStart.NeverTranslateLanguage.Count";
+const char kTranslateApplicationStartNeverTranslateSiteCount[] =
+    "Translate.ApplicationStart.NeverTranslateSite.Count";
+
 TranslationType NullTranslateMetricsLogger::GetNextManualTranslationType() {
   return TranslationType::kUninitialized;
 }
 
+void TranslateMetricsLoggerImpl::LogApplicationStartMetrics(
+    std::unique_ptr<TranslatePrefs> translate_prefs) {
+  // TODO(1229371): These histograms are only recorded when Chrome starts up
+  // using the preferences of whatever profile is logged in at the time. This
+  // information should be recroded each time a profile logs in.
+
+  std::vector<std::string> always_translate_languages =
+      translate_prefs->GetAlwaysTranslateLanguages();
+  for (const auto& always_translate_language : always_translate_languages) {
+    base::UmaHistogramSparse(kTranslateApplicationStartAlwaysTranslateLanguage,
+                             base::HashMetricName(always_translate_language));
+  }
+  base::UmaHistogramCounts100(
+      kTranslateApplicationStartAlwaysTranslateLanguageCount,
+      always_translate_languages.size());
+
+  std::vector<std::string> never_translate_languages =
+      translate_prefs->GetNeverTranslateLanguages();
+  for (const auto& never_translate_language : never_translate_languages) {
+    base::UmaHistogramSparse(kTranslateApplicationStartNeverTranslateLanguage,
+                             base::HashMetricName(never_translate_language));
+  }
+  base::UmaHistogramCounts100(
+      kTranslateApplicationStartNeverTranslateLanguageCount,
+      never_translate_languages.size());
+
+  std::vector<std::string> never_translate_sites =
+      translate_prefs->GetNeverPromptSitesBetween(base::Time::UnixEpoch(),
+                                                  base::Time::Now());
+  base::UmaHistogramCounts100(kTranslateApplicationStartNeverTranslateSiteCount,
+                              never_translate_sites.size());
+}
+
 TranslateMetricsLoggerImpl::TranslateMetricsLoggerImpl(
     base::WeakPtr<TranslateManager> translate_manager)
     : translate_manager_(translate_manager),
diff --git a/components/translate/core/browser/translate_metrics_logger_impl.h b/components/translate/core/browser/translate_metrics_logger_impl.h
index 29827cf..ceb1080 100644
--- a/components/translate/core/browser/translate_metrics_logger_impl.h
+++ b/components/translate/core/browser/translate_metrics_logger_impl.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "components/translate/core/browser/translate_metrics_logger.h"
+#include "components/translate/core/browser/translate_prefs.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
@@ -49,6 +50,13 @@
 extern const char kTranslatePageLoadRankerVersion[];
 extern const char kTranslatePageLoadTriggerDecision[];
 
+// Session frequency UMA histograms.
+extern const char kTranslateApplicationStartAlwaysTranslateLanguage[];
+extern const char kTranslateApplicationStartAlwaysTranslateLanguageCount[];
+extern const char kTranslateApplicationStartNeverTranslateLanguage[];
+extern const char kTranslateApplicationStartNeverTranslateLanguageCount[];
+extern const char kTranslateApplicationStartNeverTranslateSiteCount[];
+
 class NullTranslateMetricsLogger : public TranslateMetricsLogger {
  public:
   NullTranslateMetricsLogger() = default;
@@ -107,6 +115,9 @@
   TranslateMetricsLoggerImpl& operator=(const TranslateMetricsLoggerImpl&) =
       delete;
 
+  static void LogApplicationStartMetrics(
+      std::unique_ptr<TranslatePrefs> translate_prefs);
+
   // Overrides the clock used to track the time of certain actions. Should only
   // be used for testing purposes.
   void SetInternalClockForTesting(base::TickClock* clock);
diff --git a/components/translate/core/browser/translate_metrics_logger_impl_unittest.cc b/components/translate/core/browser/translate_metrics_logger_impl_unittest.cc
index e39e740..d27f861 100644
--- a/components/translate/core/browser/translate_metrics_logger_impl_unittest.cc
+++ b/components/translate/core/browser/translate_metrics_logger_impl_unittest.cc
@@ -12,6 +12,8 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/task_environment.h"
+#include "components/language/core/browser/language_prefs.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "services/metrics/public/cpp/metrics_utils.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
@@ -1460,6 +1462,60 @@
                                         UIInteraction::kCloseUILostFocus, 1);
 }
 
+TEST_F(TranslateMetricsLoggerImplTest, LogApplicationStartMetrics) {
+  // Make the TranslatePrefs for this test.
+  sync_preferences::TestingPrefServiceSyncable pref_service;
+  language::LanguagePrefs::RegisterProfilePrefs(pref_service.registry());
+  TranslatePrefs::RegisterProfilePrefs(pref_service.registry());
+  std::unique_ptr<TranslatePrefs> translate_prefs =
+      std::make_unique<TranslatePrefs>(&pref_service);
+
+  // Add values to always translate language, never translate language, and
+  // never translate site.
+  translate_prefs->AddLanguagePairToAlwaysTranslateList("es", "x");
+  translate_prefs->AddLanguagePairToAlwaysTranslateList("de", "x");
+
+  translate_prefs->BlockLanguage("en");
+  translate_prefs->BlockLanguage("fr");
+
+  translate_prefs->AddSiteToNeverPromptList("a");
+  translate_prefs->AddSiteToNeverPromptList("b");
+  translate_prefs->AddSiteToNeverPromptList("c");
+  translate_prefs->AddSiteToNeverPromptList("d");
+
+  // Record the session start metrics
+  TranslateMetricsLoggerImpl::LogApplicationStartMetrics(
+      std::move(translate_prefs));
+
+  // Check that the expected values were recorded to each histogram
+  histogram_tester()->ExpectTotalCount(
+      kTranslateApplicationStartAlwaysTranslateLanguage, 2);
+  histogram_tester()->ExpectBucketCount(
+      kTranslateApplicationStartAlwaysTranslateLanguage,
+      base::HashMetricName("es"), 1);
+  histogram_tester()->ExpectBucketCount(
+      kTranslateApplicationStartAlwaysTranslateLanguage,
+      base::HashMetricName("de"), 1);
+
+  histogram_tester()->ExpectUniqueSample(
+      kTranslateApplicationStartAlwaysTranslateLanguageCount, 2, 1);
+
+  histogram_tester()->ExpectTotalCount(
+      kTranslateApplicationStartNeverTranslateLanguage, 2);
+  histogram_tester()->ExpectBucketCount(
+      kTranslateApplicationStartNeverTranslateLanguage,
+      base::HashMetricName("en"), 1);
+  histogram_tester()->ExpectBucketCount(
+      kTranslateApplicationStartNeverTranslateLanguage,
+      base::HashMetricName("fr"), 1);
+
+  histogram_tester()->ExpectUniqueSample(
+      kTranslateApplicationStartNeverTranslateLanguageCount, 2, 1);
+
+  histogram_tester()->ExpectUniqueSample(
+      kTranslateApplicationStartNeverTranslateSiteCount, 4, 1);
+}
+
 }  // namespace testing
 
 }  // namespace translate
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index cada6b8..3a0c4ef 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -11843,10 +11843,20 @@
   }
 };
 
+// TODO(https://crbug.com/1231849): flaky on Cast Linux.
+#if defined(OS_LINUX)
+#define MAYBE_PagesWithCacheControlNoStoreEnterBfcacheAndEvicted \
+  DISABLED_PagesWithCacheControlNoStoreEnterBfcacheAndEvicted
+#else
+#define MAYBE_PagesWithCacheControlNoStoreEnterBfcacheAndEvicted \
+  PagesWithCacheControlNoStoreEnterBfcacheAndEvicted
+#endif
+
 // Test that a page with cache-control:no-store enters bfcache with the flag on,
 // but does not get restored and gets evicted.
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestAllowCacheControlNoStore,
-                       PagesWithCacheControlNoStoreEnterBfcacheAndEvicted) {
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestAllowCacheControlNoStore,
+    MAYBE_PagesWithCacheControlNoStoreEnterBfcacheAndEvicted) {
   net::test_server::ControllableHttpResponse response(embedded_test_server(),
                                                       "/main_document");
   net::test_server::ControllableHttpResponse response2(embedded_test_server(),
@@ -12356,11 +12366,21 @@
   }
 };
 
+// TODO(https://crbug.com/1231849): flaky on Cast Linux.
+#if defined(OS_LINUX)
+#define MAYBE_PagesWithCacheControlNoStoreRestoreFromBackForwardCache \
+  DISABLED_PagesWithCacheControlNoStoreRestoreFromBackForwardCache
+#else
+#define MAYBE_PagesWithCacheControlNoStoreRestoreFromBackForwardCache \
+  PagesWithCacheControlNoStoreRestoreFromBackForwardCache
+#endif
+
+
 // Test that a page with cache-control:no-store enters bfcache with the flag on,
 // and gets restored if cookies do not change.
 IN_PROC_BROWSER_TEST_F(
     BackForwardCacheBrowserTestRestoreCacheControlNoStoreUnlessCookieChange,
-    PagesWithCacheControlNoStoreRestoreFromBackForwardCache) {
+    MAYBE_PagesWithCacheControlNoStoreRestoreFromBackForwardCache) {
   net::test_server::ControllableHttpResponse response(embedded_test_server(),
                                                       "/main_document");
   net::test_server::ControllableHttpResponse response2(embedded_test_server(),
diff --git a/content/browser/devtools/service_worker_devtools_agent_host.cc b/content/browser/devtools/service_worker_devtools_agent_host.cc
index 7d56b58..580a896 100644
--- a/content/browser/devtools/service_worker_devtools_agent_host.cc
+++ b/content/browser/devtools/service_worker_devtools_agent_host.cc
@@ -272,6 +272,8 @@
 ServiceWorkerDevToolsAgentHost::CreateNetworkFactoryParamsForDevTools() {
   RenderProcessHost* rph = RenderProcessHost::FromID(worker_process_id_);
   const url::Origin origin = url::Origin::Create(url_);
+  // TODO(crbug.com/1231019): make sure client_security_state is no longer
+  // nullptr anywhere.
   auto factory = URLLoaderFactoryParamsHelper::CreateForWorker(
       rph, origin,
       net::IsolationInfo::Create(net::IsolationInfo::RequestType::kOther,
@@ -281,6 +283,7 @@
       static_cast<StoragePartitionImpl*>(rph->GetStoragePartition())
           ->CreateAuthCertObserverForServiceWorker(),
       NetworkServiceDevToolsObserver::MakeSelfOwned(GetId()),
+      /*client_security_state=*/nullptr,
       /*debug_tag=*/"SWDTAH::CreateNetworkFactoryParamsForDevTools");
   return {url::Origin::Create(GetURL()), net::SiteForCookies::FromUrl(GetURL()),
           std::move(factory)};
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 19e8a93..243cd34 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -784,6 +784,8 @@
   mojo::PendingReceiver<network::mojom::URLLoaderFactory>
       default_factory_receiver = factory_bundle->pending_default_factory()
                                      .InitWithNewPipeAndPassReceiver();
+  // TODO(crbug.com/1231019): make sure client_security_state is no longer
+  // nullptr anywhere.
   network::mojom::URLLoaderFactoryParamsPtr factory_params =
       URLLoaderFactoryParamsHelper::CreateForWorker(
           rph, origin,
@@ -794,6 +796,7 @@
           static_cast<StoragePartitionImpl*>(rph->GetStoragePartition())
               ->CreateAuthCertObserverForServiceWorker(),
           NetworkServiceDevToolsObserver::MakeSelfOwned(devtools_worker_token),
+          /*client_security_state=*/nullptr,
           "EmbeddedWorkerInstance::CreateFactoryBundle");
   bool bypass_redirect_checks = false;
 
diff --git a/content/browser/url_loader_factory_params_helper.cc b/content/browser/url_loader_factory_params_helper.cc
index 7e1cd98..e7517afb 100644
--- a/content/browser/url_loader_factory_params_helper.cc
+++ b/content/browser/url_loader_factory_params_helper.cc
@@ -194,6 +194,8 @@
 }
 
 // static
+// TODO(crbug.com/1231019): make sure client_security_state is no longer nullptr
+// anywhere.
 network::mojom::URLLoaderFactoryParamsPtr
 URLLoaderFactoryParamsHelper::CreateForWorker(
     RenderProcessHost* process,
@@ -204,6 +206,7 @@
     mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
         url_loader_network_observer,
     mojo::PendingRemote<network::mojom::DevToolsObserver> devtools_observer,
+    network::mojom::ClientSecurityStatePtr client_security_state,
     base::StringPiece debug_tag) {
   return CreateParams(
       process,
@@ -211,8 +214,7 @@
       request_initiator,  // request_initiator_origin_lock
       false,              // is_trusted
       absl::nullopt,      // top_frame_token
-      isolation_info,
-      nullptr,  // client_security_state
+      isolation_info, std::move(client_security_state),
       std::move(coep_reporter),
       false,  // allow_universal_access_from_file_urls
       false,  // is_for_isolated_world
diff --git a/content/browser/url_loader_factory_params_helper.h b/content/browser/url_loader_factory_params_helper.h
index c6a8e96..80496c84 100644
--- a/content/browser/url_loader_factory_params_helper.h
+++ b/content/browser/url_loader_factory_params_helper.h
@@ -85,6 +85,7 @@
       mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
           url_loader_network_observer,
       mojo::PendingRemote<network::mojom::DevToolsObserver> devtools_observer,
+      network::mojom::ClientSecurityStatePtr client_security_state,
       base::StringPiece debug_tag);
 
   // Creates URLLoaderFactoryParams for Early Hints preload.
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index 9d2cf34..a7f73cd 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -326,8 +326,6 @@
       default_factory_receiver =
           pending_default_factory.InitWithNewPipeAndPassReceiver();
 
-  // TODO(https://crbug.com/1060832): Implement COEP reporter for shared
-  // workers.
   network::mojom::URLLoaderFactoryParamsPtr factory_params =
       CreateNetworkFactoryParamsForSubresources();
   url::Origin origin = url::Origin::Create(instance_.url());
@@ -343,7 +341,6 @@
   devtools_instrumentation::WillCreateURLLoaderFactoryForSharedWorker(
       this, &factory_params->factory_override);
 
-  // TODO(yhirano): Support COEP.
   GetProcessHost()->CreateURLLoaderFactory(std::move(default_factory_receiver),
                                            std::move(factory_params));
 
@@ -353,14 +350,19 @@
 network::mojom::URLLoaderFactoryParamsPtr
 SharedWorkerHost::CreateNetworkFactoryParamsForSubresources() {
   url::Origin origin = GetStorageKey().origin();
-
   mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
       coep_reporter;
-  if (coep_reporter_) {
-    DCHECK(base::FeatureList::IsEnabled(blink::features::kCOEPForSharedWorker));
-    coep_reporter_->Clone(coep_reporter.InitWithNewPipeAndPassReceiver());
+  network::mojom::ClientSecurityStatePtr client_security_state;
+  if (base::FeatureList::IsEnabled(blink::features::kCOEPForSharedWorker)) {
+    // TODO(crbug.com/1231019): make sure client_security_state is no longer
+    // nullptr anywhere.
+    client_security_state = network::mojom::ClientSecurityState::New();
+    client_security_state->cross_origin_embedder_policy =
+        cross_origin_embedder_policy();
+    if (coep_reporter_) {
+      coep_reporter_->Clone(coep_reporter.InitWithNewPipeAndPassReceiver());
+    }
   }
-
   network::mojom::URLLoaderFactoryParamsPtr factory_params =
       URLLoaderFactoryParamsHelper::CreateForWorker(
           GetProcessHost(), origin,
@@ -370,8 +372,9 @@
           std::move(coep_reporter),
           /*url_loader_network_observer=*/mojo::NullRemote(),
           /*devtools_observer=*/mojo::NullRemote(),
-          /*debug_tag=*/"SharedWorkerHost::CreateNetworkFactoryForSubresource");
-  // TODO(lyf): support COEP.
+          std::move(client_security_state),
+          /*debug_tag=*/
+          "SharedWorkerHost::CreateNetworkFactoryForSubresource");
   return factory_params;
 }
 
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index 770c0c28..645ea83 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -359,12 +359,14 @@
     const url::Origin& request_initiator = *resource_request->request_initiator;
     // TODO(https://crbug.com/1060837): Pass the Mojo remote which is connected
     // to the COEP reporter in DedicatedWorkerHost.
+    // TODO(crbug.com/1231019): make sure client_security_state is no longer
+    // nullptr anywhere.
     network::mojom::URLLoaderFactoryParamsPtr factory_params =
         URLLoaderFactoryParamsHelper::CreateForWorker(
             factory_process, request_initiator, trusted_isolation_info,
             /*coep_reporter=*/mojo::NullRemote(),
             std::move(url_loader_network_observer),
-            std::move(devtools_observer),
+            std::move(devtools_observer), /*client_security_state=*/nullptr,
             /*debug_tag=*/"WorkerScriptFetchInitiator::CreateScriptLoader");
 
     mojo::PendingReceiver<network::mojom::URLLoaderFactory>
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index d739480b..940b5e37 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -419,6 +419,9 @@
 # Flaky on Android, haven't investigated why yet.
 crbug.com/1221258 [ android ] Pixel_OffscreenCanvas2DResizeOnWorker [ Failure ]
 
+# Pixel tests are flakily asserting in GPU process on SkiaRenderer/Vulkan
+crbug.com/1230743 [ linux skia-renderer-vulkan ] Pixel_* [ RetryOnFailure ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index f28037b..0b631bc 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -868,7 +868,6 @@
     "updater/safe_manifest_parser_unittest.cc",
     "updater/update_data_provider_unittest.cc",
     "updater/update_service_unittest.cc",
-    "value_store/leveldb_scoped_database_unittest.cc",
     "value_store/leveldb_value_store_unittest.cc",
     "value_store/testing_value_store_unittest.cc",
     "value_store/value_store_change_unittest.cc",
diff --git a/extensions/browser/value_store/BUILD.gn b/extensions/browser/value_store/BUILD.gn
index 8e444da..33ce66b8 100644
--- a/extensions/browser/value_store/BUILD.gn
+++ b/extensions/browser/value_store/BUILD.gn
@@ -13,8 +13,6 @@
     "lazy_leveldb.h",
     "legacy_value_store_factory.cc",
     "legacy_value_store_factory.h",
-    "leveldb_scoped_database.cc",
-    "leveldb_scoped_database.h",
     "leveldb_value_store.cc",
     "leveldb_value_store.h",
     "settings_namespace.cc",
@@ -23,11 +21,14 @@
     "value_store.h",
     "value_store_change.cc",
     "value_store_change.h",
+    "value_store_client_id.h",
     "value_store_factory.h",
     "value_store_factory_impl.cc",
     "value_store_factory_impl.h",
     "value_store_frontend.cc",
     "value_store_frontend.h",
+    "value_store_task_runner.cc",
+    "value_store_task_runner.h",
   ]
 
   deps = [
diff --git a/extensions/browser/value_store/lazy_leveldb.cc b/extensions/browser/value_store/lazy_leveldb.cc
index c51f681..0288dfc 100644
--- a/extensions/browser/value_store/lazy_leveldb.cc
+++ b/extensions/browser/value_store/lazy_leveldb.cc
@@ -61,12 +61,13 @@
 
 LazyLevelDb::LazyLevelDb(const std::string& uma_client_name,
                          const base::FilePath& path)
-    : db_path_(path), open_options_(leveldb_env::Options()) {
+    : db_path_(path) {
   open_options_.create_if_missing = true;
   open_options_.paranoid_checks = true;
 
   read_options_.verify_checksums = true;
 
+  // TODO(crbug.com/1226956): Remove reference to extensions.
   // Used in lieu of UMA_HISTOGRAM_ENUMERATION because the histogram name is
   // not a constant.
   open_histogram_ = base::LinearHistogram::FactoryGet(
diff --git a/extensions/browser/value_store/lazy_leveldb.h b/extensions/browser/value_store/lazy_leveldb.h
index 1beadaf..5b3f285 100644
--- a/extensions/browser/value_store/lazy_leveldb.h
+++ b/extensions/browser/value_store/lazy_leveldb.h
@@ -27,6 +27,9 @@
 // calling any other *protected* method.
 class LazyLevelDb {
  public:
+  LazyLevelDb(const LazyLevelDb&) = delete;
+  LazyLevelDb& operator=(const LazyLevelDb&) = delete;
+
   // Creates a new database iterator. This iterator *must* be deleted before
   // this database is closed.
   ValueStore::Status CreateIterator(
@@ -95,8 +98,6 @@
   base::HistogramBase* open_histogram_ = nullptr;
   base::HistogramBase* db_restore_histogram_ = nullptr;
   base::HistogramBase* value_restore_histogram_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(LazyLevelDb);
 };
 
 #endif  // EXTENSIONS_BROWSER_VALUE_STORE_LAZY_LEVELDB_H_
diff --git a/extensions/browser/value_store/legacy_value_store_factory.cc b/extensions/browser/value_store/legacy_value_store_factory.cc
index c5f52c6..f6032bde 100644
--- a/extensions/browser/value_store/legacy_value_store_factory.cc
+++ b/extensions/browser/value_store/legacy_value_store_factory.cc
@@ -10,12 +10,14 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "extensions/browser/value_store/leveldb_value_store.h"
+#include "extensions/browser/value_store/value_store_client_id.h"
 #include "extensions/common/constants.h"
 
 using base::AutoLock;
 
 namespace {
 
+// TODO(crbug.com/1226956): Update extensions specific UMA logging.
 // Statistics are logged to UMA with these strings as part of histogram name.
 // They can all be found under Extensions.Database.Open.<client>. Changing this
 // needs to synchronize with histograms.xml, AND will also become incompatible
@@ -41,23 +43,23 @@
     : data_path_(data_path) {}
 
 base::FilePath LegacyValueStoreFactory::ModelSettings::GetDBPath(
-    const ExtensionId& extension_id) const {
-  return data_path_.AppendASCII(extension_id);
+    const ValueStoreClientId& id) const {
+  return data_path_.AppendASCII(id);
 }
 
 bool LegacyValueStoreFactory::ModelSettings::DeleteData(
-    const ExtensionId& extension_id) {
-  return base::DeletePathRecursively(GetDBPath(extension_id));
+    const ValueStoreClientId& id) {
+  return base::DeletePathRecursively(GetDBPath(id));
 }
 
 bool LegacyValueStoreFactory::ModelSettings::DataExists(
-    const ExtensionId& extension_id) const {
-  return ValidDBExists(GetDBPath(extension_id));
+    const ValueStoreClientId& id) const {
+  return ValidDBExists(GetDBPath(id));
 }
 
-std::set<ExtensionId>
+std::set<ValueStoreClientId>
 LegacyValueStoreFactory::ModelSettings::GetKnownExtensionIDs() const {
-  std::set<ExtensionId> result;
+  std::set<ValueStoreClientId> result;
 
   // Leveldb databases are directories inside |base_path_|.
   base::FileEnumerator extension_dirs(data_path_, false,
@@ -123,7 +125,7 @@
   return nullptr;
 }
 
-std::set<ExtensionId>
+std::set<ValueStoreClientId>
 LegacyValueStoreFactory::SettingsRoot::GetKnownExtensionIDs(
     ModelType model_type) const {
   switch (model_type) {
@@ -135,7 +137,7 @@
       return extensions_->GetKnownExtensionIDs();
   }
   NOTREACHED();
-  return std::set<ExtensionId>();
+  return std::set<ValueStoreClientId>();
 }
 
 //
@@ -177,39 +179,39 @@
 std::unique_ptr<ValueStore> LegacyValueStoreFactory::CreateSettingsStore(
     settings_namespace::Namespace settings_namespace,
     ModelType model_type,
-    const ExtensionId& extension_id) {
+    const ValueStoreClientId& id) {
   const ModelSettings* settings_root =
       GetSettingsRoot(settings_namespace).GetModel(model_type);
   DCHECK(settings_root != nullptr);
-  return std::make_unique<LeveldbValueStore>(
-      kSettingsDatabaseUMAClientName, settings_root->GetDBPath(extension_id));
+  return std::make_unique<LeveldbValueStore>(kSettingsDatabaseUMAClientName,
+                                             settings_root->GetDBPath(id));
 }
 
 void LegacyValueStoreFactory::DeleteSettings(
     settings_namespace::Namespace settings_namespace,
     ModelType model_type,
-    const ExtensionId& extension_id) {
+    const ValueStoreClientId& id) {
   ModelSettings* model_settings =
       GetSettingsRoot(settings_namespace).GetModel(model_type);
   if (model_settings == nullptr) {
     NOTREACHED();
     return;
   }
-  model_settings->DeleteData(extension_id);
+  model_settings->DeleteData(id);
 }
 
 bool LegacyValueStoreFactory::HasSettings(
     settings_namespace::Namespace settings_namespace,
     ModelType model_type,
-    const ExtensionId& extension_id) {
+    const ValueStoreClientId& id) {
   const ModelSettings* model_settings =
       GetSettingsRoot(settings_namespace).GetModel(model_type);
   if (model_settings == nullptr)
     return false;
-  return model_settings->DataExists(extension_id);
+  return model_settings->DataExists(id);
 }
 
-std::set<ExtensionId> LegacyValueStoreFactory::GetKnownExtensionIDs(
+std::set<ValueStoreClientId> LegacyValueStoreFactory::GetKnownExtensionIDs(
     settings_namespace::Namespace settings_type,
     ModelType model_type) const {
   return GetSettingsRoot(settings_type).GetKnownExtensionIDs(model_type);
diff --git a/extensions/browser/value_store/legacy_value_store_factory.h b/extensions/browser/value_store/legacy_value_store_factory.h
index 2e57657..a594594 100644
--- a/extensions/browser/value_store/legacy_value_store_factory.h
+++ b/extensions/browser/value_store/legacy_value_store_factory.h
@@ -12,17 +12,23 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "extensions/browser/value_store/value_store.h"
+#include "extensions/browser/value_store/value_store_client_id.h"
 #include "extensions/browser/value_store/value_store_factory.h"
-#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
 // A factory to create legacy ValueStore instances for storing extension
 // state/rules/settings. "legacy" refers to the initial storage implementation
-// which created a settings database per extension.
+// which created a settings database per extension. This factory was created as
+// part of a refactoring for crbug.com/453946 which was never finished. Because
+// it was never finished, this is the only implementation of ValueStoreFactory.
+// TODO(crbug.com/453946): Finish this refactoring or merge
+// legacy_value_store_factory with value_store_factory_impl.
 class LegacyValueStoreFactory : public ValueStoreFactory {
  public:
   explicit LegacyValueStoreFactory(const base::FilePath& profile_path);
+  LegacyValueStoreFactory(const LegacyValueStoreFactory&) = delete;
+  LegacyValueStoreFactory& operator=(const LegacyValueStoreFactory&) = delete;
 
   bool RulesDBExists() const;
   bool StateDBExists() const;
@@ -33,15 +39,15 @@
   std::unique_ptr<ValueStore> CreateSettingsStore(
       settings_namespace::Namespace settings_namespace,
       ModelType model_type,
-      const ExtensionId& extension_id) override;
+      const ValueStoreClientId& id) override;
 
   void DeleteSettings(settings_namespace::Namespace settings_namespace,
                       ModelType model_type,
-                      const ExtensionId& extension_id) override;
+                      const ValueStoreClientId& id) override;
   bool HasSettings(settings_namespace::Namespace settings_namespace,
                    ModelType model_type,
-                   const ExtensionId& extension_id) override;
-  std::set<ExtensionId> GetKnownExtensionIDs(
+                   const ValueStoreClientId& id) override;
+  std::set<ValueStoreClientId> GetKnownExtensionIDs(
       settings_namespace::Namespace settings_namespace,
       ModelType model_type) const override;
 
@@ -53,17 +59,17 @@
   class ModelSettings {
    public:
     explicit ModelSettings(const base::FilePath& data_path);
+    ModelSettings(const ModelSettings&) = delete;
+    ModelSettings& operator=(const ModelSettings&) = delete;
 
-    base::FilePath GetDBPath(const ExtensionId& extension_id) const;
-    bool DeleteData(const ExtensionId& extension_id);
-    bool DataExists(const ExtensionId& extension_id) const;
-    std::set<ExtensionId> GetKnownExtensionIDs() const;
+    base::FilePath GetDBPath(const ValueStoreClientId& id) const;
+    bool DeleteData(const ValueStoreClientId& id);
+    bool DataExists(const ValueStoreClientId& id) const;
+    std::set<ValueStoreClientId> GetKnownExtensionIDs() const;
 
    private:
     // The path containing all settings databases under this root.
     const base::FilePath data_path_;
-
-    DISALLOW_COPY_AND_ASSIGN(ModelSettings);
   };
 
   // Manages two collections of legacy settings databases (apps & extensions)
@@ -76,16 +82,18 @@
                  const std::string& extension_dirname,
                  const std::string& app_dirname);
     ~SettingsRoot();
+    SettingsRoot(const SettingsRoot&) = delete;
+    SettingsRoot& operator=(const SettingsRoot&) = delete;
 
-    std::set<ExtensionId> GetKnownExtensionIDs(ModelType model_type) const;
+    std::set<ValueStoreClientId> GetKnownExtensionIDs(
+        ModelType model_type) const;
     const ModelSettings* GetModel(ModelType model_type) const;
     ModelSettings* GetModel(ModelType model_type);
 
    private:
+    // TODO(crbug.com/1226956): Remove references to extensions and Chrome Apps.
     std::unique_ptr<ModelSettings> extensions_;
     std::unique_ptr<ModelSettings> apps_;
-
-    DISALLOW_COPY_AND_ASSIGN(SettingsRoot);
   };
 
   ~LegacyValueStoreFactory() override;
@@ -102,8 +110,6 @@
   SettingsRoot local_settings_;
   SettingsRoot sync_settings_;
   SettingsRoot managed_settings_;
-
-  DISALLOW_COPY_AND_ASSIGN(LegacyValueStoreFactory);
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/value_store/leveldb_scoped_database.cc b/extensions/browser/value_store/leveldb_scoped_database.cc
deleted file mode 100644
index cffb507b..0000000
--- a/extensions/browser/value_store/leveldb_scoped_database.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/browser/value_store/leveldb_scoped_database.h"
-
-#include <utility>
-
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
-
-namespace {
-
-// Note: Changing the delimiter will change the database schema.
-const char kKeyDelimiter = ':';  // delimits scope and key
-const char kCannotSerialize[] = "Cannot serialize value to JSON";
-const char kInvalidJson[] = "Invalid JSON";
-const char kInvalidScope[] = "Invalid scope";
-
-}  // namespace
-
-bool LeveldbScopedDatabase::SplitKey(const std::string& full_key,
-                                     std::string* scope,
-                                     std::string* key) {
-  size_t pos = full_key.find(kKeyDelimiter);
-  if (pos == std::string::npos)
-    return false;
-  if (pos == 0)
-    return false;
-  *scope = full_key.substr(0, pos);
-  *key = full_key.substr(pos + 1);
-  return true;
-}
-
-bool LeveldbScopedDatabase::CreateKey(const std::string& scope,
-                                      const std::string& key,
-                                      std::string* scoped_key) {
-  if (scope.empty() || scope.find(kKeyDelimiter) != std::string::npos)
-    return false;
-  *scoped_key = scope + kKeyDelimiter + key;
-  return true;
-}
-
-LeveldbScopedDatabase::LeveldbScopedDatabase(const std::string& uma_client_name,
-                                             const base::FilePath& path)
-    : LazyLevelDb(uma_client_name, path) {}
-
-LeveldbScopedDatabase::~LeveldbScopedDatabase() {}
-
-ValueStore::Status LeveldbScopedDatabase::Read(
-    const std::string& scope,
-    const std::string& key,
-    absl::optional<base::Value>* value) {
-  ValueStore::Status status = EnsureDbIsOpen();
-  if (!status.ok())
-    return status;
-  std::string scoped_key;
-  if (!CreateKey(scope, key, &scoped_key))
-    return ValueStore::Status(ValueStore::OTHER_ERROR, kInvalidScope);
-
-  return LazyLevelDb::Read(scoped_key, value);
-}
-
-ValueStore::Status LeveldbScopedDatabase::Read(const std::string& scope,
-                                               base::DictionaryValue* values) {
-  ValueStore::Status status = EnsureDbIsOpen();
-  if (!status.ok())
-    return status;
-
-  std::string prefix;
-  if (!CreateKey(scope, "", &prefix))
-    return ValueStore::Status(ValueStore::OTHER_ERROR, kInvalidScope);
-
-  std::unique_ptr<leveldb::Iterator> it(db()->NewIterator(read_options()));
-
-  std::unique_ptr<base::DictionaryValue> settings(new base::DictionaryValue());
-
-  for (it->Seek(prefix); it->Valid() && it->key().starts_with(prefix);
-       it->Next()) {
-    leveldb::Slice descoped_key(it->key());
-    descoped_key.remove_prefix(prefix.size());
-    absl::optional<base::Value> value = base::JSONReader::Read(
-        base::StringPiece(it->value().data(), it->value().size()));
-    if (!value) {
-      return ValueStore::Status(ValueStore::CORRUPTION,
-                                LazyLevelDb::Delete(it->key().ToString()).ok()
-                                    ? ValueStore::VALUE_RESTORE_DELETE_SUCCESS
-                                    : ValueStore::VALUE_RESTORE_DELETE_FAILURE,
-                                kInvalidJson);
-    }
-    values->SetKey(descoped_key.ToString(), std::move(*value));
-  }
-
-  return status;
-}
-
-ValueStore::Status LeveldbScopedDatabase::Write(const std::string& scope,
-                                                const std::string& key,
-                                                const base::Value& value) {
-  ValueStore::Status status = EnsureDbIsOpen();
-  if (!status.ok())
-    return status;
-
-  leveldb::WriteBatch batch;
-  status = AddToWriteBatch(&batch, scope, key, value);
-  if (!status.ok())
-    return status;
-  return ToValueStoreError(db()->Write(write_options(), &batch));
-}
-
-ValueStore::Status LeveldbScopedDatabase::Write(
-    const std::string& scope,
-    const base::DictionaryValue& values) {
-  ValueStore::Status status = EnsureDbIsOpen();
-  if (!status.ok())
-    return status;
-
-  leveldb::WriteBatch batch;
-  for (base::DictionaryValue::Iterator it(values); !it.IsAtEnd();
-       it.Advance()) {
-    status = AddToWriteBatch(&batch, scope, it.key(), it.value());
-    if (!status.ok())
-      return status;
-  }
-
-  return ToValueStoreError(db()->Write(write_options(), &batch));
-}
-
-ValueStore::Status LeveldbScopedDatabase::DeleteValues(
-    const std::string& scope,
-    const std::vector<std::string>& keys) {
-  ValueStore::Status status = EnsureDbIsOpen();
-  if (!status.ok())
-    return status;
-
-  leveldb::WriteBatch batch;
-  std::string scoped_key;
-  for (const auto& key : keys) {
-    if (!CreateKey(scope, key, &scoped_key))
-      return ValueStore::Status(ValueStore::OTHER_ERROR, kInvalidScope);
-    batch.Delete(scoped_key);
-  }
-
-  return ToValueStoreError(db()->Write(write_options(), &batch));
-}
-
-ValueStore::Status LeveldbScopedDatabase::AddToWriteBatch(
-    leveldb::WriteBatch* batch,
-    const std::string& scope,
-    const std::string& key,
-    const base::Value& value) {
-  std::string scoped_key;
-  if (!CreateKey(scope, key, &scoped_key))
-    return ValueStore::Status(ValueStore::OTHER_ERROR, kInvalidScope);
-
-  std::string value_as_json;
-  if (!base::JSONWriter::Write(value, &value_as_json))
-    return ValueStore::Status(ValueStore::OTHER_ERROR, kCannotSerialize);
-
-  batch->Put(scoped_key, value_as_json);
-  return ValueStore::Status();
-}
diff --git a/extensions/browser/value_store/leveldb_scoped_database.h b/extensions/browser/value_store/leveldb_scoped_database.h
deleted file mode 100644
index 8ee8da1..0000000
--- a/extensions/browser/value_store/leveldb_scoped_database.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_BROWSER_VALUE_STORE_LEVELDB_SCOPED_DATABASE_H_
-#define EXTENSIONS_BROWSER_VALUE_STORE_LEVELDB_SCOPED_DATABASE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "extensions/browser/value_store/lazy_leveldb.h"
-#include "extensions/browser/value_store/value_store.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-// This database is used to persist values with their keys scoped within a
-// specified namespace - AKA |scope|. Values will be written as follows:
-//
-// <scope><delimiter><scoped-key> -> <value>
-//
-// Note: |scope| must not contain the delimiter, but the |key| may.
-//
-class LeveldbScopedDatabase
-    : public LazyLevelDb,
-      public base::RefCountedThreadSafe<LeveldbScopedDatabase> {
- public:
-  // Splits the full key into the scope and inner (scoped) key.
-  // Returns true if successfully split, and false if not and leaves |scope| and
-  // |key| unchanged.
-  static bool SplitKey(const std::string& full_key,
-                       std::string* scope,
-                       std::string* key);
-
-  // Creates a fully scoped key. |scope| cannot be an empty key and cannot
-  // contain the delimiter. |scoped_key| will be set to:
-  //
-  //   <scope><delimiter><key>
-  //
-  // Will return true when successful, false if not.
-  static bool CreateKey(const std::string& scope,
-                        const std::string& key,
-                        std::string* scoped_key);
-
-  LeveldbScopedDatabase(const std::string& uma_client_name,
-                        const base::FilePath& path);
-
-  // Reads a single |value| from the database for the specified |key|.
-  ValueStore::Status Read(const std::string& scope,
-                          const std::string& key,
-                          absl::optional<base::Value>* value);
-
-  // Reads all |values| from the database stored within the specified |scope|.
-  ValueStore::Status Read(const std::string& scope,
-                          base::DictionaryValue* values);
-
-  // Writes a single |key| => |value| to the database.
-  ValueStore::Status Write(const std::string& scope,
-                           const std::string& key,
-                           const base::Value& value);
-
-  // Writes all |values| to the database with the keys scoped with |scope|.
-  ValueStore::Status Write(const std::string& scope,
-                           const base::DictionaryValue& values);
-
-  // Deletes all |keys| from the databases withing the specified |scope|.
-  ValueStore::Status DeleteValues(const std::string& scope,
-                                  const std::vector<std::string>& keys);
-
- protected:
-  friend class base::RefCountedThreadSafe<LeveldbScopedDatabase>;
-  virtual ~LeveldbScopedDatabase();
-
-  static ValueStore::Status AddToWriteBatch(leveldb::WriteBatch* batch,
-                                            const std::string& scope,
-                                            const std::string& key,
-                                            const base::Value& value);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LeveldbScopedDatabase);
-};
-
-#endif  // EXTENSIONS_BROWSER_VALUE_STORE_LEVELDB_SCOPED_DATABASE_H_
diff --git a/extensions/browser/value_store/leveldb_scoped_database_unittest.cc b/extensions/browser/value_store/leveldb_scoped_database_unittest.cc
deleted file mode 100644
index b788aa7b..0000000
--- a/extensions/browser/value_store/leveldb_scoped_database_unittest.cc
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/browser/value_store/leveldb_scoped_database.h"
-
-#include <stddef.h>
-
-#include <map>
-#include <string>
-
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/memory/ref_counted.h"
-#include "base/values.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-const char kTestUMAClientName[] = "Test";
-}  // namespace
-
-class LeveldbScopedDatabaseUnitTest : public testing::Test {
- public:
-  LeveldbScopedDatabaseUnitTest() {}
-  ~LeveldbScopedDatabaseUnitTest() override {}
-
- protected:
-  void SetUp() override {
-    ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
-    db_ =
-        new LeveldbScopedDatabase(kTestUMAClientName, database_dir_.GetPath());
-  }
-
-  void TearDown() override {
-    db_ = nullptr;
-    base::DeletePathRecursively(database_dir_.GetPath());
-  }
-
-  ValueStore::Status ReadAllValues(
-      std::map<std::string, std::string>* values) const {
-    values->clear();
-    leveldb::ReadOptions read_options;
-    read_options.verify_checksums = true;
-    std::unique_ptr<leveldb::Iterator> iterator;
-    ValueStore::Status status = db_->CreateIterator(read_options, &iterator);
-    if (!status.ok())
-      return status;
-    iterator->SeekToFirst();
-    while (iterator->Valid()) {
-      // The LeveldbProfileDatabase writes all values as JSON strings.
-      // This method returns the encoded strings.
-      (*values)[iterator->key().ToString()] = iterator->value().ToString();
-      iterator->Next();
-    }
-    return db_->ToValueStoreError(iterator->status());
-  }
-
-  content::BrowserTaskEnvironment task_environment_;
-  base::ScopedTempDir database_dir_;
-  scoped_refptr<LeveldbScopedDatabase> db_;
-};
-
-TEST_F(LeveldbScopedDatabaseUnitTest, TestSplitKey) {
-  std::string scope;
-  std::string key;
-  EXPECT_TRUE(LeveldbScopedDatabase::SplitKey("s:k", &scope, &key));
-  EXPECT_EQ(scope, "s");
-  EXPECT_EQ(key, "k");
-  EXPECT_TRUE(LeveldbScopedDatabase::SplitKey("s:", &scope, &key));
-  EXPECT_EQ(scope, "s");
-  EXPECT_EQ(key, "");
-  EXPECT_TRUE(LeveldbScopedDatabase::SplitKey("s:k:o", &scope, &key));
-  EXPECT_EQ(scope, "s");
-  EXPECT_EQ(key, "k:o");
-  EXPECT_FALSE(LeveldbScopedDatabase::SplitKey("s-k", &scope, &key));
-  EXPECT_FALSE(LeveldbScopedDatabase::SplitKey("", &scope, &key));
-  EXPECT_FALSE(LeveldbScopedDatabase::SplitKey(":k", &scope, &key));
-}
-
-TEST_F(LeveldbScopedDatabaseUnitTest, TestCreateKey) {
-  std::string scoped_key;
-
-  EXPECT_TRUE(LeveldbScopedDatabase::CreateKey("scope", "key", &scoped_key));
-  EXPECT_EQ("scope:key", scoped_key);
-  EXPECT_TRUE(LeveldbScopedDatabase::CreateKey("scope", "", &scoped_key));
-  EXPECT_EQ("scope:", scoped_key);
-  EXPECT_TRUE(LeveldbScopedDatabase::CreateKey("scope", "key:o", &scoped_key));
-  EXPECT_EQ("scope:key:o", scoped_key);
-
-  EXPECT_FALSE(LeveldbScopedDatabase::CreateKey("", "key", &scoped_key));
-  EXPECT_FALSE(
-      LeveldbScopedDatabase::CreateKey("scope:withdelim", "key", &scoped_key));
-}
-
-TEST_F(LeveldbScopedDatabaseUnitTest, TestWrite) {
-  std::map<std::string, std::string> db_values;
-  EXPECT_TRUE(ReadAllValues(&db_values).ok());
-  EXPECT_EQ(0u, db_values.size());
-
-  base::DictionaryValue scope1_values;
-  scope1_values.SetString("s1_key1", "s1_value1");
-  scope1_values.SetString("s1_key2", "s1_value2");
-  EXPECT_FALSE(db_->Write("", scope1_values).ok());
-  EXPECT_TRUE(db_->Write("scope1", scope1_values).ok());
-
-  base::DictionaryValue scope2_values;
-  scope2_values.SetString("s2_key1", "s2_value1");
-  scope2_values.SetString("s2_key2", "s2_value2");
-  EXPECT_TRUE(db_->Write("scope2", scope2_values).ok());
-
-  // Read all values using raw leveldb. Values are JSON strings.
-  EXPECT_TRUE(ReadAllValues(&db_values).ok());
-  EXPECT_EQ(4u, db_values.size());
-  EXPECT_EQ("\"s1_value1\"", db_values["scope1:s1_key1"]);
-  EXPECT_EQ("\"s1_value2\"", db_values["scope1:s1_key2"]);
-  EXPECT_EQ("\"s2_value1\"", db_values["scope2:s2_key1"]);
-  EXPECT_EQ("\"s2_value2\"", db_values["scope2:s2_key2"]);
-
-  // Intentionally overwrite value (with a new value).
-  base::DictionaryValue changed_scope2_values;
-  changed_scope2_values.SetString("s2_key1", "s2_value1");
-  changed_scope2_values.SetString("s2_key2", "s2_value3");
-  EXPECT_TRUE(db_->Write("scope2", changed_scope2_values).ok());
-
-  EXPECT_TRUE(ReadAllValues(&db_values).ok());
-  EXPECT_EQ(4u, db_values.size());
-  EXPECT_EQ("\"s1_value1\"", db_values["scope1:s1_key1"]);
-  EXPECT_EQ("\"s1_value2\"", db_values["scope1:s1_key2"]);
-  EXPECT_EQ("\"s2_value1\"", db_values["scope2:s2_key1"]);
-  EXPECT_EQ("\"s2_value3\"", db_values["scope2:s2_key2"]);
-}
-
-TEST_F(LeveldbScopedDatabaseUnitTest, TestRead) {
-  base::DictionaryValue scope1_values;
-  scope1_values.SetString("s1_key1", "s1_value1");
-  scope1_values.SetString("s1_key2", "s1_value2");
-  EXPECT_TRUE(db_->Write("scope1", scope1_values).ok());
-
-  base::DictionaryValue scope2_values;
-  scope2_values.SetString("s2_key1", "s2_value1");
-  scope2_values.SetString("s2_key2", "s2_value2");
-  EXPECT_TRUE(db_->Write("scope2", scope2_values).ok());
-
-  // And test an empty scope.
-  EXPECT_FALSE(db_->Write("", scope2_values).ok());
-
-  base::DictionaryValue read_s1_vals;
-  EXPECT_FALSE(db_->Read("", &read_s1_vals).ok());
-  EXPECT_TRUE(db_->Read("scope1", &read_s1_vals).ok());
-  EXPECT_TRUE(scope1_values.Equals(&read_s1_vals));
-
-  base::DictionaryValue read_s2_vals;
-  EXPECT_TRUE(db_->Read("scope2", &read_s2_vals).ok());
-  EXPECT_TRUE(scope2_values.Equals(&read_s2_vals));
-}
-
-TEST_F(LeveldbScopedDatabaseUnitTest, TestEmptyValue) {
-  base::DictionaryValue values;
-  values.SetString("s1_key1", "");
-  EXPECT_TRUE(db_->Write("scope1", values).ok());
-
-  absl::optional<base::Value> value;
-  ASSERT_TRUE(db_->Read("scope1", "s1_key1", &value).ok());
-  ASSERT_TRUE(value.has_value());
-  ASSERT_TRUE(value->is_string());
-  EXPECT_EQ(value->GetString(), "");
-}
-
-TEST_F(LeveldbScopedDatabaseUnitTest, TestValueContainingDelimiter) {
-  base::DictionaryValue values;
-  values.SetString("s1_key1", "with:delimiter");
-  EXPECT_TRUE(db_->Write("scope1", values).ok());
-
-  absl::optional<base::Value> value;
-  ASSERT_TRUE(db_->Read("scope1", "s1_key1", &value).ok());
-  ASSERT_TRUE(value.has_value());
-  ASSERT_TRUE(value->is_string());
-  EXPECT_EQ(value->GetString(), "with:delimiter");
-}
-
-TEST_F(LeveldbScopedDatabaseUnitTest, TestDeleteValues) {
-  base::DictionaryValue scope1_values;
-  scope1_values.SetString("s1_key1", "s1_value1");
-  scope1_values.SetString("s1_key2", "s1_value2");
-  EXPECT_TRUE(db_->Write("scope1", scope1_values).ok());
-
-  base::DictionaryValue scope2_values;
-  scope2_values.SetString("s2_key1", "s2_value1");
-  scope2_values.SetString("s2_key2", "s2_value2");
-  EXPECT_TRUE(db_->Write("scope2", scope2_values).ok());
-
-  std::vector<std::string> keys;
-  keys.push_back("s2_key1");
-  keys.push_back("s2_key2");
-  keys.push_back("s1_key1");
-  EXPECT_TRUE(db_->DeleteValues("scope2", keys).ok());
-
-  base::DictionaryValue read_s1_vals;
-  EXPECT_TRUE(db_->Read("scope1", &read_s1_vals).ok());
-  EXPECT_TRUE(scope1_values.Equals(&read_s1_vals));
-
-  base::DictionaryValue read_s2_vals;
-  EXPECT_TRUE(db_->Read("scope2", &read_s2_vals).ok());
-  EXPECT_TRUE(read_s2_vals.DictEmpty());
-}
diff --git a/extensions/browser/value_store/leveldb_value_store.h b/extensions/browser/value_store/leveldb_value_store.h
index 4a55b89..7f4a8a4 100644
--- a/extensions/browser/value_store/leveldb_value_store.h
+++ b/extensions/browser/value_store/leveldb_value_store.h
@@ -37,6 +37,9 @@
   // Must be deleted on the FILE thread.
   ~LeveldbValueStore() override;
 
+  LeveldbValueStore(const LeveldbValueStore&) = delete;
+  LeveldbValueStore& operator=(const LeveldbValueStore&) = delete;
+
   // ValueStore implementation.
   size_t GetBytesInUse(const std::string& key) override;
   size_t GetBytesInUse(const std::vector<std::string>& keys) override;
@@ -72,8 +75,6 @@
 
   // Commits the changes in |batch| to the database.
   ValueStore::Status WriteToDb(leveldb::WriteBatch* batch);
-
-  DISALLOW_COPY_AND_ASSIGN(LeveldbValueStore);
 };
 
 #endif  // EXTENSIONS_BROWSER_VALUE_STORE_LEVELDB_VALUE_STORE_H_
diff --git a/extensions/browser/value_store/leveldb_value_store_unittest.cc b/extensions/browser/value_store/leveldb_value_store_unittest.cc
index e36fc12..c3538833 100644
--- a/extensions/browser/value_store/leveldb_value_store_unittest.cc
+++ b/extensions/browser/value_store/leveldb_value_store_unittest.cc
@@ -35,8 +35,8 @@
 
 class LeveldbValueStoreUnitTest : public testing::Test {
  public:
-  LeveldbValueStoreUnitTest() {}
-  ~LeveldbValueStoreUnitTest() override {}
+  LeveldbValueStoreUnitTest() = default;
+  ~LeveldbValueStoreUnitTest() override = default;
 
  protected:
   void SetUp() override {
@@ -109,7 +109,6 @@
 // (unless absolutely necessary), and instead only removes corrupted keys.
 TEST_F(LeveldbValueStoreUnitTest, RestoreDoesMinimumNecessary) {
   const char* kNotCorruptKeys[] = {"a", "n", "z"};
-  const size_t kNotCorruptKeysSize = 3u;
   const char kCorruptKey1[] = "f";
   const char kCorruptKey2[] = "s";
   const char kValue[] = "value";
@@ -117,9 +116,9 @@
 
   // Insert a collection of non-corrupted pairs.
   std::unique_ptr<base::Value> value(new base::Value(kValue));
-  for (size_t i = 0; i < kNotCorruptKeysSize; ++i) {
+  for (auto* kNotCorruptKey : kNotCorruptKeys) {
     ASSERT_TRUE(store()
-                    ->Set(ValueStore::DEFAULTS, kNotCorruptKeys[i], *value)
+                    ->Set(ValueStore::DEFAULTS, kNotCorruptKey, *value)
                     .status()
                     .ok());
   }
@@ -139,12 +138,12 @@
 
   // We should still have all valid pairs present in the database.
   std::string value_string;
-  for (size_t i = 0; i < kNotCorruptKeysSize; ++i) {
-    result = store()->Get(kNotCorruptKeys[i]);
+  for (auto* kNotCorruptKey : kNotCorruptKeys) {
+    result = store()->Get(kNotCorruptKey);
     EXPECT_TRUE(result.status().ok());
     ASSERT_EQ(ValueStore::RESTORE_NONE, result.status().restore_status);
-    EXPECT_TRUE(result.settings().HasKey(kNotCorruptKeys[i]));
-    EXPECT_TRUE(result.settings().GetString(kNotCorruptKeys[i], &value_string));
+    EXPECT_TRUE(result.settings().HasKey(kNotCorruptKey));
+    EXPECT_TRUE(result.settings().GetString(kNotCorruptKey, &value_string));
     EXPECT_EQ(kValue, value_string);
   }
 }
@@ -158,14 +157,13 @@
 TEST_F(LeveldbValueStoreUnitTest, RestoreFullDatabase) {
   const std::string kLolCats("I can haz leveldb filez?");
   const char* kNotCorruptKeys[] = {"a", "n", "z"};
-  const size_t kNotCorruptKeysSize = 3u;
   const char kValue[] = "value";
 
   // Generate a database.
   std::unique_ptr<base::Value> value(new base::Value(kValue));
-  for (size_t i = 0; i < kNotCorruptKeysSize; ++i) {
+  for (auto* kNotCorruptKey : kNotCorruptKeys) {
     ASSERT_TRUE(store()
-                    ->Set(ValueStore::DEFAULTS, kNotCorruptKeys[i], *value)
+                    ->Set(ValueStore::DEFAULTS, kNotCorruptKey, *value)
                     .status()
                     .ok());
   }
diff --git a/extensions/browser/value_store/settings_namespace.h b/extensions/browser/value_store/settings_namespace.h
index ad537b4..171b4ae 100644
--- a/extensions/browser/value_store/settings_namespace.h
+++ b/extensions/browser/value_store/settings_namespace.h
@@ -11,6 +11,8 @@
 
 namespace settings_namespace {
 
+// TODO(crbug.com/1226956): Move extensions specific namespaces out of
+// ValueStore.
 // The namespaces of the storage areas that have ValueStore.
 enum Namespace {
   LOCAL,    // "local"    i.e. chrome.storage.local
diff --git a/extensions/browser/value_store/test_value_store_factory.cc b/extensions/browser/value_store/test_value_store_factory.cc
index de75f95..557d470 100644
--- a/extensions/browser/value_store/test_value_store_factory.cc
+++ b/extensions/browser/value_store/test_value_store_factory.cc
@@ -7,6 +7,7 @@
 #include "base/memory/ptr_util.h"
 #include "extensions/browser/value_store/leveldb_value_store.h"
 #include "extensions/browser/value_store/testing_value_store.h"
+#include "extensions/browser/value_store/value_store_client_id.h"
 
 namespace {
 
@@ -22,10 +23,10 @@
 
 TestValueStoreFactory::StorageHelper::~StorageHelper() = default;
 
-std::set<ExtensionId>
+std::set<ValueStoreClientId>
 TestValueStoreFactory::StorageHelper::GetKnownExtensionIDs(
     ModelType model_type) const {
-  std::set<ExtensionId> ids;
+  std::set<ValueStoreClientId> ids;
   switch (model_type) {
     case ValueStoreFactory::ModelType::APP:
       for (const auto& key : app_stores_)
@@ -45,51 +46,51 @@
 }
 
 ValueStore* TestValueStoreFactory::StorageHelper::AddValueStore(
-    const ExtensionId& extension_id,
+    const ValueStoreClientId& id,
     ValueStore* value_store,
     ModelType model_type) {
   if (model_type == ValueStoreFactory::ModelType::APP) {
-    DCHECK(app_stores_.find(extension_id) == app_stores_.end());
-    app_stores_[extension_id] = value_store;
+    DCHECK(app_stores_.find(id) == app_stores_.end());
+    app_stores_[id] = value_store;
   } else {
-    DCHECK(extension_stores_.find(extension_id) == extension_stores_.end());
-    extension_stores_[extension_id] = value_store;
+    DCHECK(extension_stores_.find(id) == extension_stores_.end());
+    extension_stores_[id] = value_store;
   }
   return value_store;
 }
 
 void TestValueStoreFactory::StorageHelper::DeleteSettings(
-    const ExtensionId& extension_id,
+    const ValueStoreClientId& id,
     ModelType model_type) {
   switch (model_type) {
     case ValueStoreFactory::ModelType::APP:
-      app_stores_.erase(extension_id);
+      app_stores_.erase(id);
       break;
     case ValueStoreFactory::ModelType::EXTENSION:
-      extension_stores_.erase(extension_id);
+      extension_stores_.erase(id);
       break;
   }
 }
 
 bool TestValueStoreFactory::StorageHelper::HasSettings(
-    const ExtensionId& extension_id,
+    const ValueStoreClientId& id,
     ModelType model_type) const {
   switch (model_type) {
     case ValueStoreFactory::ModelType::APP:
-      return app_stores_.find(extension_id) != app_stores_.end();
+      return app_stores_.find(id) != app_stores_.end();
     case ValueStoreFactory::ModelType::EXTENSION:
-      return extension_stores_.find(extension_id) != extension_stores_.end();
+      return extension_stores_.find(id) != extension_stores_.end();
   }
   NOTREACHED();
   return false;
 }
 
 ValueStore* TestValueStoreFactory::StorageHelper::GetExisting(
-    const ExtensionId& extension_id) const {
-  auto it = app_stores_.find(extension_id);
+    const ValueStoreClientId& id) const {
+  auto it = app_stores_.find(id);
   if (it != app_stores_.end())
     return it->second;
-  it = extension_stores_.find(extension_id);
+  it = extension_stores_.find(id);
   if (it != extension_stores_.end())
     return it->second;
   return nullptr;
@@ -100,7 +101,7 @@
 TestValueStoreFactory::TestValueStoreFactory(const base::FilePath& db_path)
     : db_path_(db_path) {}
 
-TestValueStoreFactory::~TestValueStoreFactory() {}
+TestValueStoreFactory::~TestValueStoreFactory() = default;
 
 std::unique_ptr<ValueStore> TestValueStoreFactory::CreateRulesStore() {
   if (db_path_.empty())
@@ -133,13 +134,13 @@
 std::unique_ptr<ValueStore> TestValueStoreFactory::CreateSettingsStore(
     SettingsNamespace settings_namespace,
     ModelType model_type,
-    const ExtensionId& extension_id) {
+    const ValueStoreClientId& id) {
   std::unique_ptr<ValueStore> settings_store(CreateRulesStore());
   // Note: This factory is purposely keeping the raw pointers to each ValueStore
   //       created. Tests using TestValueStoreFactory must be careful to keep
   //       those ValueStore's alive for the duration of their test.
   GetStorageHelper(settings_namespace)
-      .AddValueStore(extension_id, settings_store.get(), model_type);
+      .AddValueStore(id, settings_store.get(), model_type);
   return settings_store;
 }
 
@@ -149,18 +150,17 @@
 
 void TestValueStoreFactory::DeleteSettings(SettingsNamespace settings_namespace,
                                            ModelType model_type,
-                                           const ExtensionId& extension_id) {
-  GetStorageHelper(settings_namespace).DeleteSettings(extension_id, model_type);
+                                           const ValueStoreClientId& id) {
+  GetStorageHelper(settings_namespace).DeleteSettings(id, model_type);
 }
 
 bool TestValueStoreFactory::HasSettings(SettingsNamespace settings_namespace,
                                         ModelType model_type,
-                                        const ExtensionId& extension_id) {
-  return GetStorageHelper(settings_namespace)
-      .HasSettings(extension_id, model_type);
+                                        const ValueStoreClientId& id) {
+  return GetStorageHelper(settings_namespace).HasSettings(id, model_type);
 }
 
-std::set<ExtensionId> TestValueStoreFactory::GetKnownExtensionIDs(
+std::set<ValueStoreClientId> TestValueStoreFactory::GetKnownExtensionIDs(
     SettingsNamespace settings_namespace,
     ModelType model_type) const {
   return const_cast<TestValueStoreFactory*>(this)
@@ -169,14 +169,14 @@
 }
 
 ValueStore* TestValueStoreFactory::GetExisting(
-    const ExtensionId& extension_id) const {
-  ValueStore* existing_store = local_helper_.GetExisting(extension_id);
+    const ValueStoreClientId& id) const {
+  ValueStore* existing_store = local_helper_.GetExisting(id);
   if (existing_store)
     return existing_store;
-  existing_store = sync_helper_.GetExisting(extension_id);
+  existing_store = sync_helper_.GetExisting(id);
   if (existing_store)
     return existing_store;
-  existing_store = managed_helper_.GetExisting(extension_id);
+  existing_store = managed_helper_.GetExisting(id);
   DCHECK(existing_store != nullptr);
   return existing_store;
 }
diff --git a/extensions/browser/value_store/test_value_store_factory.h b/extensions/browser/value_store/test_value_store_factory.h
index 534bae8..08f80a1 100644
--- a/extensions/browser/value_store/test_value_store_factory.h
+++ b/extensions/browser/value_store/test_value_store_factory.h
@@ -10,8 +10,8 @@
 #include <set>
 
 #include "base/files/file_path.h"
+#include "extensions/browser/value_store/value_store_client_id.h"
 #include "extensions/browser/value_store/value_store_factory.h"
-#include "extensions/common/extension_id.h"
 
 class ValueStore;
 
@@ -24,6 +24,8 @@
  public:
   TestValueStoreFactory();
   explicit TestValueStoreFactory(const base::FilePath& db_path);
+  TestValueStoreFactory(const TestValueStoreFactory&) = delete;
+  TestValueStoreFactory& operator=(const TestValueStoreFactory&) = delete;
 
   // ValueStoreFactory
   std::unique_ptr<ValueStore> CreateRulesStore() override;
@@ -31,14 +33,14 @@
   std::unique_ptr<ValueStore> CreateSettingsStore(
       settings_namespace::Namespace settings_namespace,
       ModelType model_type,
-      const ExtensionId& extension_id) override;
+      const ValueStoreClientId& id) override;
   void DeleteSettings(settings_namespace::Namespace settings_namespace,
                       ModelType model_type,
-                      const ExtensionId& extension_id) override;
+                      const ValueStoreClientId& id) override;
   bool HasSettings(settings_namespace::Namespace settings_namespace,
                    ModelType model_type,
-                   const ExtensionId& extension_id) override;
-  std::set<ExtensionId> GetKnownExtensionIDs(
+                   const ValueStoreClientId& id) override;
+  std::set<ValueStoreClientId> GetKnownExtensionIDs(
       settings_namespace::Namespace settings_namespace,
       ModelType model_type) const override;
 
@@ -47,7 +49,7 @@
   // deleted at any time.
   ValueStore* LastCreatedStore() const;
   // Return a previously created |ValueStore| for an extension.
-  ValueStore* GetExisting(const ExtensionId& extension_id) const;
+  ValueStore* GetExisting(const ValueStoreClientId& id) const;
   // Reset this class (as if just created).
   void Reset();
 
@@ -58,21 +60,22 @@
    public:
     StorageHelper();
     ~StorageHelper();
-    std::set<ExtensionId> GetKnownExtensionIDs(ModelType model_type) const;
-    ValueStore* AddValueStore(const ExtensionId& extension_id,
+    StorageHelper(const StorageHelper&) = delete;
+    StorageHelper& operator=(const StorageHelper&) = delete;
+
+    std::set<ValueStoreClientId> GetKnownExtensionIDs(
+        ModelType model_type) const;
+    ValueStore* AddValueStore(const ValueStoreClientId& id,
                               ValueStore* value_store,
                               ModelType model_type);
-    void DeleteSettings(const ExtensionId& extension_id, ModelType model_type);
-    bool HasSettings(const ExtensionId& extension_id,
-                     ModelType model_type) const;
+    void DeleteSettings(const ValueStoreClientId& id, ModelType model_type);
+    bool HasSettings(const ValueStoreClientId& id, ModelType model_type) const;
     void Reset();
-    ValueStore* GetExisting(const ExtensionId& extension_id) const;
+    ValueStore* GetExisting(const ValueStoreClientId& id) const;
 
    private:
-    std::map<ExtensionId, ValueStore*> app_stores_;
-    std::map<ExtensionId, ValueStore*> extension_stores_;
-
-    DISALLOW_COPY_AND_ASSIGN(StorageHelper);
+    std::map<ValueStoreClientId, ValueStore*> app_stores_;
+    std::map<ValueStoreClientId, ValueStore*> extension_stores_;
   };
 
   StorageHelper& GetStorageHelper(
@@ -87,8 +90,6 @@
   StorageHelper local_helper_;
   StorageHelper sync_helper_;
   StorageHelper managed_helper_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestValueStoreFactory);
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/value_store/testing_value_store.cc b/extensions/browser/value_store/testing_value_store.cc
index 3bf99b4..afbf982 100644
--- a/extensions/browser/value_store/testing_value_store.cc
+++ b/extensions/browser/value_store/testing_value_store.cc
@@ -22,9 +22,8 @@
 
 }  // namespace
 
-TestingValueStore::TestingValueStore() : read_count_(0), write_count_(0) {}
-
-TestingValueStore::~TestingValueStore() {}
+TestingValueStore::TestingValueStore() = default;
+TestingValueStore::~TestingValueStore() = default;
 
 void TestingValueStore::set_status_code(StatusCode status_code) {
   status_ = ValueStore::Status(status_code, kGenericErrorMessage);
@@ -60,10 +59,10 @@
     return ReadResult(CreateStatusCopy(status_));
 
   auto settings = std::make_unique<base::DictionaryValue>();
-  for (auto it = keys.cbegin(); it != keys.cend(); ++it) {
-    base::Value* value = storage_.FindKey(*it);
+  for (const auto& key : keys) {
+    base::Value* value = storage_.FindKey(key);
     if (value) {
-      settings->SetKey(*it, value->Clone());
+      settings->SetKey(key, value->Clone());
     }
   }
   return ReadResult(std::move(settings), CreateStatusCopy(status_));
diff --git a/extensions/browser/value_store/testing_value_store.h b/extensions/browser/value_store/testing_value_store.h
index 55ed6b6..a0266bc 100644
--- a/extensions/browser/value_store/testing_value_store.h
+++ b/extensions/browser/value_store/testing_value_store.h
@@ -20,6 +20,8 @@
  public:
   TestingValueStore();
   ~TestingValueStore() override;
+  TestingValueStore(const TestingValueStore&) = delete;
+  TestingValueStore& operator=(const TestingValueStore&) = delete;
 
   // Sets the error code for requests. If OK, errors won't be thrown.
   // Defaults to OK.
@@ -51,11 +53,9 @@
 
  private:
   base::DictionaryValue storage_;
-  int read_count_;
-  int write_count_;
+  int read_count_ = 0;
+  int write_count_ = 0;
   ValueStore::Status status_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestingValueStore);
 };
 
 #endif  // EXTENSIONS_BROWSER_VALUE_STORE_TESTING_VALUE_STORE_H_
diff --git a/extensions/browser/value_store/value_store.cc b/extensions/browser/value_store/value_store.cc
index 2989b12..e04a1e7 100644
--- a/extensions/browser/value_store/value_store.cc
+++ b/extensions/browser/value_store/value_store.cc
@@ -10,7 +10,7 @@
 
 // Implementation of Status.
 
-ValueStore::Status::Status() : code(OK), restore_status(RESTORE_NONE) {}
+ValueStore::Status::Status() = default;
 
 ValueStore::Status::Status(StatusCode code, const std::string& message)
     : Status(code, RESTORE_NONE, message) {}
diff --git a/extensions/browser/value_store/value_store.h b/extensions/browser/value_store/value_store.h
index ac15266..3364806 100644
--- a/extensions/browser/value_store/value_store.h
+++ b/extensions/browser/value_store/value_store.h
@@ -79,9 +79,9 @@
     void Merge(const Status& status);
 
     // The status code.
-    StatusCode code;
+    StatusCode code = OK;
 
-    BackingStoreRestoreStatus restore_status;
+    BackingStoreRestoreStatus restore_status = RESTORE_NONE;
 
     // Message associated with the status (error) if there is one.
     std::string message;
@@ -95,6 +95,8 @@
     ReadResult(ReadResult&& other);
     ~ReadResult();
     ReadResult& operator=(ReadResult&& rhs);
+    ReadResult(const ReadResult&) = delete;
+    ReadResult& operator=(const ReadResult&) = delete;
 
     // Gets the settings read from the storage. Note that this represents
     // the root object. If you request the value for key "foo", that value will
@@ -112,8 +114,6 @@
    private:
     std::unique_ptr<base::DictionaryValue> settings_;
     Status status_;
-
-    DISALLOW_COPY_AND_ASSIGN(ReadResult);
   };
 
   // The result of a write operation (Set/Remove/Clear).
@@ -124,6 +124,8 @@
     WriteResult(WriteResult&& other);
     ~WriteResult();
     WriteResult& operator=(WriteResult&& rhs);
+    WriteResult(const WriteResult&) = delete;
+    WriteResult& operator=(const WriteResult&) = delete;
 
     // Gets the list of changes to the settings which resulted from the write.
     // Won't be present if the NO_GENERATE_CHANGES WriteOptions was given.
@@ -136,8 +138,6 @@
    private:
     ValueStoreChangeList changes_;
     Status status_;
-
-    DISALLOW_COPY_AND_ASSIGN(WriteResult);
   };
 
   // Options for write operations.
@@ -153,7 +153,7 @@
   };
   typedef int WriteOptions;
 
-  virtual ~ValueStore() {}
+  virtual ~ValueStore() = default;
 
   // Gets the amount of space being used by a single value, in bytes.
   // Note: The GetBytesInUse methods are only used by extension settings at the
diff --git a/extensions/browser/value_store/value_store_change_unittest.cc b/extensions/browser/value_store/value_store_change_unittest.cc
index 8cebea3..8925101 100644
--- a/extensions/browser/value_store/value_store_change_unittest.cc
+++ b/extensions/browser/value_store/value_store_change_unittest.cc
@@ -6,13 +6,10 @@
 #include "base/json/json_writer.h"
 #include "base/values.h"
 #include "extensions/browser/value_store/value_store_change.h"
-#include "extensions/common/value_builder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::DictionaryValue;
 using base::Value;
-using extensions::DictionaryBuilder;
-using extensions::ListBuilder;
 
 namespace {
 
@@ -55,39 +52,39 @@
 
 TEST(ValueStoreChangeTest, ToValue) {
   // Create a mildly complicated structure that has dots in it.
-  std::unique_ptr<base::DictionaryValue> value =
-      DictionaryBuilder()
-          .Set("key", "value")
-          .Set("key.with.dots", "value.with.dots")
-          .Set("tricked", DictionaryBuilder().Set("you", "nodots").Build())
-          .Set("tricked.you", "with.dots")
-          .Build();
+  base::Value inner_dict(base::Value::Type::DICTIONARY);
+  inner_dict.SetKey("you", base::Value("nodots"));
+
+  base::Value value(base::Value::Type::DICTIONARY);
+  value.SetKey("key", base::Value("value"));
+  value.SetKey("key.with.dots", base::Value("value.with.dots"));
+  value.SetKey("tricked", std::move(inner_dict));
+  value.SetKey("tricked.you", base::Value("with.dots"));
 
   ValueStoreChangeList change_list;
+  change_list.push_back(ValueStoreChange("key", value.Clone(), value.Clone()));
   change_list.push_back(
-      ValueStoreChange("key", value->Clone(), value->Clone()));
-  change_list.push_back(
-      ValueStoreChange("key.with.dots", value->Clone(), value->Clone()));
+      ValueStoreChange("key.with.dots", value.Clone(), value.Clone()));
 
   base::Value changes_value = ValueStoreChange::ToValue(std::move(change_list));
 
-  DictionaryBuilder v1(*value);
-  DictionaryBuilder v2(*value);
-  DictionaryBuilder v3(*value);
-  DictionaryBuilder v4(*value);
-  std::unique_ptr<base::DictionaryValue> expected_from_json =
-      DictionaryBuilder()
-          .Set("key", DictionaryBuilder()
-                          .Set("oldValue", v1.Build())
-                          .Set("newValue", v2.Build())
-                          .Build())
-          .Set("key.with.dots", DictionaryBuilder()
-                                    .Set("oldValue", v3.Build())
-                                    .Set("newValue", v4.Build())
-                                    .Build())
-          .Build();
+  base::Value v1(value.Clone());
+  base::Value v2(value.Clone());
+  base::Value v3(value.Clone());
+  base::Value v4(value.Clone());
 
-  EXPECT_TRUE(changes_value.Equals(expected_from_json.get()));
+  base::Value inner_dict2(base::Value::Type::DICTIONARY);
+  base::Value inner_dict3(base::Value::Type::DICTIONARY);
+
+  inner_dict2.SetKey("oldValue", std::move(v1));
+  inner_dict2.SetKey("newValue", std::move(v2));
+  inner_dict3.SetKey("oldValue", std::move(v3));
+  inner_dict3.SetKey("newValue", std::move(v4));
+
+  base::Value expected_from_json(base::Value::Type::DICTIONARY);
+  expected_from_json.SetKey("key", std::move(inner_dict2));
+  expected_from_json.SetKey("key.with.dots", std::move(inner_dict3));
+  EXPECT_EQ(changes_value, expected_from_json);
 }
 
 }  // namespace
diff --git a/extensions/browser/value_store/value_store_client_id.h b/extensions/browser/value_store/value_store_client_id.h
new file mode 100644
index 0000000..f320b208
--- /dev/null
+++ b/extensions/browser/value_store/value_store_client_id.h
@@ -0,0 +1,17 @@
+// Copyright 2021 The Chromium 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 EXTENSIONS_BROWSER_VALUE_STORE_VALUE_STORE_CLIENT_ID_H_
+#define EXTENSIONS_BROWSER_VALUE_STORE_VALUE_STORE_CLIENT_ID_H_
+
+#include <string>
+
+// TODO(crbug.com/1226956): Move out of extensions namespace.
+namespace extensions {
+
+using ValueStoreClientId = std::string;
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_VALUE_STORE_VALUE_STORE_CLIENT_ID_H_
\ No newline at end of file
diff --git a/extensions/browser/value_store/value_store_factory.h b/extensions/browser/value_store/value_store_factory.h
index 25580d17..81c0776 100644
--- a/extensions/browser/value_store/value_store_factory.h
+++ b/extensions/browser/value_store/value_store_factory.h
@@ -10,7 +10,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "extensions/browser/value_store/settings_namespace.h"
-#include "extensions/common/extension_id.h"
+#include "extensions/browser/value_store/value_store_client_id.h"
 
 class ValueStore;
 
@@ -37,29 +37,30 @@
   virtual std::unique_ptr<ValueStore> CreateSettingsStore(
       settings_namespace::Namespace settings_namespace,
       ModelType model_type,
-      const ExtensionId& extension_id) = 0;
+      const ValueStoreClientId& id) = 0;
 
   // Delete all settings for specified given extension in the specified
   // namespace/model_type.
   virtual void DeleteSettings(settings_namespace::Namespace settings_namespace,
                               ModelType model_type,
-                              const ExtensionId& extension_id) = 0;
+                              const ValueStoreClientId& id) = 0;
 
   // Are there any settings stored in the specified namespace/model_type for
   // the given extension?
   virtual bool HasSettings(settings_namespace::Namespace settings_namespace,
                            ModelType model_type,
-                           const ExtensionId& extension_id) = 0;
+                           const ValueStoreClientId& id) = 0;
 
+  // TODO(crbug.com/1226956): Remove reference to extensions.
   // Return all extension ID's with settings stored in the given
   // namespace/model_type.
-  virtual std::set<ExtensionId> GetKnownExtensionIDs(
+  virtual std::set<ValueStoreClientId> GetKnownExtensionIDs(
       settings_namespace::Namespace settings_namespace,
       ModelType model_type) const = 0;
 
  protected:
   friend class base::RefCountedThreadSafe<ValueStoreFactory>;
-  virtual ~ValueStoreFactory() {}
+  virtual ~ValueStoreFactory() = default;
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/value_store/value_store_factory_impl.cc b/extensions/browser/value_store/value_store_factory_impl.cc
index 09f3a94..7cc31d9 100644
--- a/extensions/browser/value_store/value_store_factory_impl.cc
+++ b/extensions/browser/value_store/value_store_factory_impl.cc
@@ -6,6 +6,7 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "extensions/browser/value_store/legacy_value_store_factory.h"
+#include "extensions/browser/value_store/value_store_client_id.h"
 
 namespace extensions {
 
@@ -28,25 +29,24 @@
 std::unique_ptr<ValueStore> ValueStoreFactoryImpl::CreateSettingsStore(
     SettingsNamespace settings_namespace,
     ModelType model_type,
-    const ExtensionId& extension_id) {
+    const ValueStoreClientId& id) {
   return legacy_factory_->CreateSettingsStore(settings_namespace, model_type,
-                                              extension_id);
+                                              id);
 }
 
 void ValueStoreFactoryImpl::DeleteSettings(SettingsNamespace settings_namespace,
                                            ModelType model_type,
-                                           const ExtensionId& extension_id) {
-  legacy_factory_->DeleteSettings(settings_namespace, model_type, extension_id);
+                                           const ValueStoreClientId& id) {
+  legacy_factory_->DeleteSettings(settings_namespace, model_type, id);
 }
 
 bool ValueStoreFactoryImpl::HasSettings(SettingsNamespace settings_namespace,
                                         ModelType model_type,
-                                        const ExtensionId& extension_id) {
-  return legacy_factory_->HasSettings(settings_namespace, model_type,
-                                      extension_id);
+                                        const ValueStoreClientId& id) {
+  return legacy_factory_->HasSettings(settings_namespace, model_type, id);
 }
 
-std::set<ExtensionId> ValueStoreFactoryImpl::GetKnownExtensionIDs(
+std::set<ValueStoreClientId> ValueStoreFactoryImpl::GetKnownExtensionIDs(
     SettingsNamespace settings_namespace,
     ModelType model_type) const {
   return legacy_factory_->GetKnownExtensionIDs(settings_namespace, model_type);
diff --git a/extensions/browser/value_store/value_store_factory_impl.h b/extensions/browser/value_store/value_store_factory_impl.h
index 178e2d2..a625850 100644
--- a/extensions/browser/value_store/value_store_factory_impl.h
+++ b/extensions/browser/value_store/value_store_factory_impl.h
@@ -12,8 +12,8 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "extensions/browser/value_store/value_store.h"
+#include "extensions/browser/value_store/value_store_client_id.h"
 #include "extensions/browser/value_store/value_store_factory.h"
-#include "extensions/common/extension_id.h"
 
 namespace extensions {
 
@@ -24,6 +24,8 @@
 class ValueStoreFactoryImpl : public ValueStoreFactory {
  public:
   explicit ValueStoreFactoryImpl(const base::FilePath& profile_path);
+  ValueStoreFactoryImpl(const ValueStoreFactoryImpl&) = delete;
+  ValueStoreFactoryImpl& operator=(const ValueStoreFactoryImpl&) = delete;
 
   // ValueStoreFactory
   std::unique_ptr<ValueStore> CreateRulesStore() override;
@@ -31,14 +33,14 @@
   std::unique_ptr<ValueStore> CreateSettingsStore(
       settings_namespace::Namespace settings_namespace,
       ModelType model_type,
-      const ExtensionId& extension_id) override;
+      const ValueStoreClientId& id) override;
   void DeleteSettings(settings_namespace::Namespace settings_namespace,
                       ModelType model_type,
-                      const ExtensionId& extension_id) override;
+                      const ValueStoreClientId& id) override;
   bool HasSettings(settings_namespace::Namespace settings_namespace,
                    ModelType model_type,
-                   const ExtensionId& extension_id) override;
-  std::set<ExtensionId> GetKnownExtensionIDs(
+                   const ValueStoreClientId& id) override;
+  std::set<ValueStoreClientId> GetKnownExtensionIDs(
       settings_namespace::Namespace settings_namespace,
       ModelType model_type) const override;
 
@@ -47,8 +49,6 @@
   ~ValueStoreFactoryImpl() override;
 
   scoped_refptr<LegacyValueStoreFactory> legacy_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ValueStoreFactoryImpl);
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/value_store/value_store_frontend.cc b/extensions/browser/value_store/value_store_frontend.cc
index ce63844..22771bf 100644
--- a/extensions/browser/value_store/value_store_frontend.cc
+++ b/extensions/browser/value_store/value_store_frontend.cc
@@ -30,6 +30,8 @@
       : store_factory_(store_factory),
         backend_type_(backend_type),
         task_runner_(task_runner) {}
+  Backend(const Backend&) = delete;
+  Backend& operator=(const Backend&) = delete;
 
   void Get(const std::string& key, ValueStoreFrontend::ReadCallback callback) {
     DCHECK(task_runner_->RunsTasksInCurrentSequence());
@@ -113,8 +115,6 @@
   std::unique_ptr<ValueStore> storage_;
 
   base::FilePath db_path_;
-
-  DISALLOW_COPY_AND_ASSIGN(Backend);
 };
 
 ValueStoreFrontend::ValueStoreFrontend(
diff --git a/extensions/browser/value_store/value_store_frontend.h b/extensions/browser/value_store/value_store_frontend.h
index 118f3c4..ca9323c 100644
--- a/extensions/browser/value_store/value_store_frontend.h
+++ b/extensions/browser/value_store/value_store_frontend.h
@@ -24,16 +24,19 @@
 // A frontend for a LeveldbValueStore, for use on the UI thread.
 class ValueStoreFrontend {
  public:
+  // TODO(crbug.com/1226956): Move extensions specific enum out of ValueStore.
   // The kind of extensions data stored in a backend.
   enum class BackendType { RULES, STATE };
 
   using ReadCallback = base::OnceCallback<void(std::unique_ptr<base::Value>)>;
 
   ValueStoreFrontend(
-      const scoped_refptr<extensions::ValueStoreFactory>& store_factory,
+      const scoped_refptr<ValueStoreFactory>& store_factory,
       BackendType backend_type,
       const scoped_refptr<base::SequencedTaskRunner>& task_runner);
   ~ValueStoreFrontend();
+  ValueStoreFrontend(const ValueStoreFrontend&) = delete;
+  ValueStoreFrontend& operator=(const ValueStoreFrontend&) = delete;
 
   // Retrieves a value from the database asynchronously, passing a copy to
   // |callback| when ready. NULL is passed if no matching entry is found.
@@ -53,8 +56,6 @@
   scoped_refptr<Backend> backend_;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(ValueStoreFrontend);
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/value_store/value_store_frontend_unittest.cc b/extensions/browser/value_store/value_store_frontend_unittest.cc
index 3ea816b..89f51ba 100644
--- a/extensions/browser/value_store/value_store_frontend_unittest.cc
+++ b/extensions/browser/value_store/value_store_frontend_unittest.cc
@@ -13,9 +13,8 @@
 #include "base/path_service.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_utils.h"
-#include "extensions/browser/extension_file_task_runner.h"
 #include "extensions/browser/value_store/test_value_store_factory.h"
-#include "extensions/common/extension_paths.h"
+#include "extensions/browser/value_store/value_store_task_runner.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -28,13 +27,13 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 
     base::FilePath test_data_dir;
-    ASSERT_TRUE(
-        base::PathService::Get(extensions::DIR_TEST_DATA, &test_data_dir));
-    base::FilePath src_db(test_data_dir.AppendASCII("value_store_db"));
+    ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+    base::FilePath src_db(
+        test_data_dir.AppendASCII("extensions/test/data/value_store_db"));
     db_path_ = temp_dir_.GetPath().AppendASCII("temp_db");
     base::CopyDirectory(src_db, db_path_, true);
 
-    factory_ = new extensions::TestValueStoreFactory(db_path_);
+    factory_ = new TestValueStoreFactory(db_path_);
 
     ResetStorage();
   }
@@ -48,7 +47,7 @@
   void ResetStorage() {
     storage_ = std::make_unique<ValueStoreFrontend>(
         factory_, ValueStoreFrontend::BackendType::RULES,
-        GetExtensionFileTaskRunner());
+        value_store::GetValueStoreTaskRunner());
   }
 
   bool Get(const std::string& key, std::unique_ptr<base::Value>* output) {
@@ -64,7 +63,7 @@
     *output = std::move(result);
   }
 
-  scoped_refptr<extensions::TestValueStoreFactory> factory_;
+  scoped_refptr<TestValueStoreFactory> factory_;
   std::unique_ptr<ValueStoreFrontend> storage_;
   base::ScopedTempDir temp_dir_;
   base::FilePath db_path_;
diff --git a/extensions/browser/value_store/value_store_task_runner.cc b/extensions/browser/value_store/value_store_task_runner.cc
new file mode 100644
index 0000000..af591cf
--- /dev/null
+++ b/extensions/browser/value_store/value_store_task_runner.cc
@@ -0,0 +1,32 @@
+// Copyright 2021 The Chromium 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 "extensions/browser/value_store/value_store_task_runner.h"
+
+#include "base/sequenced_task_runner.h"
+#include "base/task/lazy_thread_pool_task_runner.h"
+#include "base/task/task_traits.h"
+
+namespace value_store {
+
+namespace {
+
+// Note: All tasks posted to a single task runner have the same priority. This
+// is unfortunate, since some file-related tasks are high priority, and others
+// are low priority (like garbage collection). Split the difference and use
+// USER_VISIBLE, which is the default priority and what a task posted to a
+// named thread (like the FILE thread) would receive.
+base::LazyThreadPoolSequencedTaskRunner g_task_runner =
+    LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
+        base::TaskTraits(base::MayBlock(),
+                         base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
+                         base::TaskPriority::USER_VISIBLE));
+
+}  // namespace
+
+scoped_refptr<base::SequencedTaskRunner> GetValueStoreTaskRunner() {
+  return g_task_runner.Get();
+}
+
+}  // namespace value_store
diff --git a/extensions/browser/value_store/value_store_task_runner.h b/extensions/browser/value_store/value_store_task_runner.h
new file mode 100644
index 0000000..5aa4674
--- /dev/null
+++ b/extensions/browser/value_store/value_store_task_runner.h
@@ -0,0 +1,22 @@
+// Copyright 2021 The Chromium 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 EXTENSIONS_BROWSER_VALUE_STORE_VALUE_STORE_TASK_RUNNER_H_
+#define EXTENSIONS_BROWSER_VALUE_STORE_VALUE_STORE_TASK_RUNNER_H_
+
+#include "base/memory/ref_counted.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace value_store {
+
+// Returns the singleton instance of the task runner to be used for value store
+// tasks that read, modify, or delete files.
+scoped_refptr<base::SequencedTaskRunner> GetValueStoreTaskRunner();
+
+}  // namespace value_store
+
+#endif  // EXTENSIONS_BROWSER_VALUE_STORE_VALUE_STORE_TASK_RUNNER_H_
diff --git a/extensions/browser/value_store/value_store_unittest.cc b/extensions/browser/value_store/value_store_unittest.cc
index 97b65d5..ee45ef6 100644
--- a/extensions/browser/value_store/value_store_unittest.cc
+++ b/extensions/browser/value_store/value_store_unittest.cc
@@ -92,27 +92,27 @@
 
   std::set<std::string> keys_seen;
 
-  for (auto it = actual.cbegin(); it != actual.cend(); ++it) {
-    if (keys_seen.count(it->key())) {
-      return testing::AssertionFailure() <<
-          "Multiple changes seen for key: " << it->key();
+  for (const auto& it : actual) {
+    if (keys_seen.count(it.key())) {
+      return testing::AssertionFailure()
+             << "Multiple changes seen for key: " << it.key();
     }
-    keys_seen.insert(it->key());
+    keys_seen.insert(it.key());
 
-    if (!expected_as_map.count(it->key())) {
-      return testing::AssertionFailure() <<
-          "Actual has unexpected change for key: " << it->key();
+    if (!expected_as_map.count(it.key())) {
+      return testing::AssertionFailure()
+             << "Actual has unexpected change for key: " << it.key();
     }
 
-    const ValueStoreChange* expected_change = expected_as_map[it->key()];
+    const ValueStoreChange* expected_change = expected_as_map[it.key()];
     std::string error;
-    if (!ValuesEqual(expected_change->new_value(), it->new_value(), &error)) {
-      return testing::AssertionFailure() <<
-          "New value for " << it->key() << " was unexpected: " << error;
+    if (!ValuesEqual(expected_change->new_value(), it.new_value(), &error)) {
+      return testing::AssertionFailure()
+             << "New value for " << it.key() << " was unexpected: " << error;
     }
-    if (!ValuesEqual(expected_change->old_value(), it->old_value(), &error)) {
-      return testing::AssertionFailure() <<
-          "Old value for " << it->key() << " was unexpected: " << error;
+    if (!ValuesEqual(expected_change->old_value(), it.old_value(), &error)) {
+      return testing::AssertionFailure()
+             << "Old value for " << it.key() << " was unexpected: " << error;
     }
   }
 
@@ -159,7 +159,7 @@
   dict123_->Set(key3_, val3_->CreateDeepCopy());
 }
 
-ValueStoreTest::~ValueStoreTest() {}
+ValueStoreTest::~ValueStoreTest() = default;
 
 void ValueStoreTest::SetUp() {
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
diff --git a/extensions/browser/value_store/value_store_unittest.h b/extensions/browser/value_store/value_store_unittest.h
index 1f0dbd0..a07e8aa 100644
--- a/extensions/browser/value_store/value_store_unittest.h
+++ b/extensions/browser/value_store/value_store_unittest.h
@@ -22,7 +22,7 @@
 class ValueStoreTest : public testing::TestWithParam<ValueStoreTestParam> {
  public:
   ValueStoreTest();
-  virtual ~ValueStoreTest();
+  ~ValueStoreTest() override;
 
   void SetUp() override;
   void TearDown() override;
diff --git a/headless/test/data/protocol/emulation/intersection-observer-with-viewport-expected.txt b/headless/test/data/protocol/emulation/intersection-observer-with-viewport-expected.txt
new file mode 100644
index 0000000..2c4b3b7
--- /dev/null
+++ b/headless/test/data/protocol/emulation/intersection-observer-with-viewport-expected.txt
@@ -0,0 +1,5 @@
+Tests that intersection observer works with device emulation.
+requested url: http://example.com/
+target intersecting true
+target intersecting false
+target intersecting true
\ No newline at end of file
diff --git a/headless/test/data/protocol/emulation/intersection-observer-with-viewport.js b/headless/test/data/protocol/emulation/intersection-observer-with-viewport.js
new file mode 100644
index 0000000..7aa43c5d
--- /dev/null
+++ b/headless/test/data/protocol/emulation/intersection-observer-with-viewport.js
@@ -0,0 +1,60 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function(testRunner) {
+  const {page, session, dp} = await testRunner.startWithFrameControl(
+      `Tests that intersection observer works with device emulation.`);
+  const RendererTestHelper =
+      await testRunner.loadScript('../helpers/renderer-test-helper.js');
+  const {httpInterceptor, frameNavigationHelper, virtualTimeController} =
+      await (new RendererTestHelper(testRunner, dp, page)).init();
+
+  const params = {
+      deviceScaleFactor: 1,
+      width: 384,
+      height: 800,
+      mobile: true,
+      screenWidth: 384,
+      screenHeight: 800,
+      viewport: {x: 0, y: 0, width: 1, height: 1, scale: 1}
+  };
+  await dp.Emulation.setDeviceMetricsOverride(params);
+  dp.Runtime.enable();
+  httpInterceptor.addResponse(`http://example.com/`, `
+      <html><head>
+      <style>
+        .tall { background-color: green; height: 3000px; }
+        .short { background-color: red; height: 100px; }
+      </style></head>
+      <body>
+        <div id='target' class='short'></div>
+        <div class='tall'></div>
+      </body>
+      <script>
+        window.addEventListener('DOMContentLoaded', () => {
+          const observer = new IntersectionObserver((entries, observer) => {
+            for (const entry of entries) {
+              console.log(entry.target.id + ' intersecting ' +
+                  entry.isIntersecting);
+            }
+          });
+          observer.observe(document.querySelector('#target'));
+        });
+      </script>
+  `);
+  const initialTimeExpired = new Promise(async resolve => {
+    await virtualTimeController.grantInitialTime(1000, 1000, null, resolve);
+    frameNavigationHelper.navigate('http://example.com/');
+  });
+  await initialTimeExpired;
+  session.evaluateAsync(`
+      window.scrollBy(0, 200);
+  `);
+  await new Promise(resolve => virtualTimeController.grantTime(500, resolve));
+  session.evaluateAsync(`
+      window.scrollTo(0, 0);
+  `);
+  await new Promise(resolve => virtualTimeController.grantTime(500, resolve));
+  testRunner.completeTest();
+})
diff --git a/headless/test/headless_compositor_browsertest.cc b/headless/test/headless_compositor_browsertest.cc
index 84f9179..fa6bc90 100644
--- a/headless/test/headless_compositor_browsertest.cc
+++ b/headless/test/headless_compositor_browsertest.cc
@@ -160,5 +160,7 @@
                          "sanity/screenshot-after-metrics-override.js")
 HEADLESS_COMPOSITOR_TEST(ScreenshotDeviceScaleFactor,
                          "emulation/screenshot-device-scale-factor.js")
+HEADLESS_COMPOSITOR_TEST(VirtualTimeIntersectionObserverWithViewport,
+                         "emulation/intersection-observer-with-viewport.js")
 
 }  // namespace headless
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index 9d5c7dd..78b6622 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -1361,10 +1361,6 @@
         location_regexp_exclude: ".+/[+]/infra/config/.+"
       }
       builders {
-        name: "chromium/try/linux_chromium_tsan_rel_ng_bionic"
-        includable_only: true
-      }
-      builders {
         name: "chromium/try/linux_chromium_ubsan_rel_ng"
         includable_only: true
       }
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 83bfe98..1879abf4 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -13810,99 +13810,6 @@
       }
     }
     builders {
-      name: "Linux TSan (bionic)"
-      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-18.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: "luciexe"
-      }
-      properties:
-        '{'
-        '  "$build/goma": {'
-        '    "enable_ats": true,'
-        '    "jobs": 500,'
-        '    "rpc_extra_params": "?prod",'
-        '    "server_host": "goma.chromium.org",'
-        '    "use_luci_auth": true'
-        '  },'
-        '  "$kitchen": {'
-        '    "devshell": true,'
-        '    "git_auth": true'
-        '  },'
-        '  "$recipe_engine/isolated": {'
-        '    "server": "https://isolateserver.appspot.com"'
-        '  },'
-        '  "$recipe_engine/resultdb/test_presentation": {'
-        '    "column_keys": [],'
-        '    "grouping_keys": ['
-        '      "status",'
-        '      "v.test_suite"'
-        '    ]'
-        '  },'
-        '  "builder_group": "chromium.memory",'
-        '  "recipe": "chromium"'
-        '}'
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.gtests_local"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://[^/]*blink_web_tests/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "Linux TSan Builder"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
@@ -78023,109 +77930,6 @@
       }
     }
     builders {
-      name: "linux_chromium_tsan_rel_ng_bionic"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builder:linux_chromium_tsan_rel_ng_bionic"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-18.04"
-      dimensions: "pool:luci.chromium.try"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "luciexe"
-      }
-      properties:
-        '{'
-        '  "$build/goma": {'
-        '    "enable_ats": true,'
-        '    "jobs": 150,'
-        '    "rpc_extra_params": "?prod",'
-        '    "server_host": "goma.chromium.org",'
-        '    "use_luci_auth": true'
-        '  },'
-        '  "$kitchen": {'
-        '    "devshell": true,'
-        '    "git_auth": true'
-        '  },'
-        '  "$recipe_engine/isolated": {'
-        '    "server": "https://isolateserver.appspot.com"'
-        '  },'
-        '  "$recipe_engine/resultdb/test_presentation": {'
-        '    "column_keys": [],'
-        '    "grouping_keys": ['
-        '      "status",'
-        '      "v.test_suite"'
-        '    ]'
-        '  },'
-        '  "builder_group": "tryserver.chromium.linux",'
-        '  "recipe": "chromium_trybot"'
-        '}'
-      execution_timeout_secs: 14400
-      expiration_secs: 7200
-      grace_period {
-        seconds: 120
-      }
-      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
-      }
-      experiments {
-        key: "chromium.chromium_tests.use_rbe_cas"
-        value: 5
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-        bq_exports {
-          project: "chrome-luci-data"
-          dataset: "chromium"
-          table: "blink_web_tests_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://[^/]*blink_web_tests/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "linux_chromium_ubsan_rel_ng"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index 2f60198..6dc574f 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -504,11 +504,6 @@
     short_name: "bld"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Linux TSan (bionic)"
-    category: "chromium.memory|linux|TSan v2"
-    short_name: "tst"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Linux TSan Tests"
     category: "chromium.memory|linux|TSan v2"
     short_name: "tst"
@@ -1193,11 +1188,6 @@
     short_name: "bld"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Linux TSan (bionic)"
-    category: "chromium.memory|linux|TSan v2"
-    short_name: "tst"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Linux TSan Tests"
     category: "chromium.memory|linux|TSan v2"
     short_name: "tst"
@@ -2491,9 +2481,6 @@
     name: "buildbucket/luci.chromium.try/linux_chromium_tsan_rel_ng"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux_chromium_tsan_rel_ng_bionic"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux_layout_tests_composite_after_paint"
   }
   builders {
@@ -9416,11 +9403,6 @@
     short_name: "bld"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Linux TSan (bionic)"
-    category: "linux|TSan v2"
-    short_name: "tst"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Linux TSan Tests"
     category: "linux|TSan v2"
     short_name: "tst"
@@ -14344,9 +14326,6 @@
     name: "buildbucket/luci.chromium.try/linux_chromium_tsan_rel_ng"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux_chromium_tsan_rel_ng_bionic"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux_chromium_ubsan_rel_ng"
   }
   builders {
@@ -15306,9 +15285,6 @@
     name: "buildbucket/luci.chromium.try/linux_chromium_tsan_rel_ng"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux_chromium_tsan_rel_ng_bionic"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux_chromium_ubsan_rel_ng"
   }
   builders {
diff --git a/infra/config/generated/luci-notify.cfg b/infra/config/generated/luci-notify.cfg
index 843c889..f20521e 100644
--- a/infra/config/generated/luci-notify.cfg
+++ b/infra/config/generated/luci-notify.cfg
@@ -1220,20 +1220,6 @@
     on_occurrence: FAILURE
     failed_step_regexp: "\\b(bot_update|compile|gclient runhooks|runhooks|update|\\w*nocompile_test)\\b"
     email {
-      recipients: "thomasanderson@chromium.org"
-    }
-  }
-  builders {
-    bucket: "ci"
-    name: "Linux TSan (bionic)"
-    repository: "https://chromium.googlesource.com/chromium/src"
-  }
-}
-notifiers {
-  notifications {
-    on_occurrence: FAILURE
-    failed_step_regexp: "\\b(bot_update|compile|gclient runhooks|runhooks|update|\\w*nocompile_test)\\b"
-    email {
       rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
     }
     template: "tree_closure_email_template"
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg
index 0ead81a..b20a31a 100644
--- a/infra/config/generated/luci-scheduler.cfg
+++ b/infra/config/generated/luci-scheduler.cfg
@@ -2018,16 +2018,6 @@
   }
 }
 job {
-  id: "Linux TSan (bionic)"
-  realm: "ci"
-  acl_sets: "ci"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "Linux TSan (bionic)"
-  }
-}
-job {
   id: "Linux TSan Builder"
   realm: "ci"
   acl_sets: "ci"
@@ -7243,7 +7233,6 @@
   triggers: "Linux FYI GPU TSAN Release"
   triggers: "Linux FYI SkiaRenderer Dawn Release (Intel HD 630)"
   triggers: "Linux MSan Builder"
-  triggers: "Linux TSan (bionic)"
   triggers: "Linux TSan Builder"
   triggers: "Linux TSan Builder (goma cache silo)"
   triggers: "Linux TSan Builder (reclient)"
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index 24e1a05..e5309947 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -6168,20 +6168,6 @@
     ),
 )
 
-# TODO(https://crbug.com/1200904): Remove this after migration
-ci.memory_builder(
-    name = "Linux TSan (bionic)",
-    branch_selector = branches.STANDARD_MILESTONE,
-    console_view_entry = consoles.console_view_entry(
-        category = "linux|TSan v2",
-        short_name = "tst",
-    ),
-    cq_mirrors_console_view = "mirrors",
-    main_console_view = "main",
-    tree_closing = False,
-    os = os.LINUX_BIONIC,
-)
-
 ci.memory_builder(
     name = "Linux TSan Tests",
     branch_selector = branches.STANDARD_MILESTONE,
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index a05e142..d044398 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -1442,16 +1442,6 @@
     goma_jobs = goma.jobs.J150,
 )
 
-# TODO(crbug.com/1200904): Remove after migration
-try_.chromium_linux_builder(
-    name = "linux_chromium_tsan_rel_ng_bionic",
-    branch_selector = branches.STANDARD_MILESTONE,
-    builderless = not settings.is_main,
-    goma_jobs = goma.jobs.J150,
-    os = os.LINUX_BIONIC,
-    main_list_view = "try",
-)
-
 try_.chromium_linux_builder(
     name = "linux_chromium_tsan_rel_ng",
     branch_selector = branches.STANDARD_MILESTONE,
diff --git a/infra/inclusive_language_presubmit_exempt_dirs.txt b/infra/inclusive_language_presubmit_exempt_dirs.txt
index 449988e..feab0120 100644
--- a/infra/inclusive_language_presubmit_exempt_dirs.txt
+++ b/infra/inclusive_language_presubmit_exempt_dirs.txt
@@ -16,7 +16,6 @@
 chrome/browser/autofill 2 1
 chrome/browser/chromeos/extensions 8 2
 chrome/browser/chromeos/fileapi 1 1
-chrome/browser/chromeos/policy 15 2
 chrome/browser/devtools 3 1
 chrome/browser/download 1 1
 chrome/browser/extensions 2 2
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 8b14b0c..5340d31 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -442,7 +442,7 @@
 const base::Feature kGlobalMediaControlsPictureInPicture {
   "GlobalMediaControlsPictureInPicture",
 #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
-    BUILDFLAG(IS_CHROMEOS_LACROS)
+    defined(OS_CHROMEOS) || BUILDFLAG(IS_CHROMEOS_LACROS)
       base::FEATURE_ENABLED_BY_DEFAULT
 #else
       base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/printing/printing_context_win_unittest.cc b/printing/printing_context_win_unittest.cc
index a6c30af..59058cf 100644
--- a/printing/printing_context_win_unittest.cc
+++ b/printing/printing_context_win_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/test/task_environment.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/scoped_hdc.h"
+#include "base/win/windows_version.h"
 #include "printing/backend/printing_info_win.h"
 #include "printing/backend/win_helper.h"
 #include "printing/mojom/print.mojom.h"
@@ -146,6 +147,10 @@
 };
 
 TEST_F(PrintingContextTest, PrintAll) {
+  // TODO(crbug.com/1231528): Investigate why this test fails on Win 7 bots.
+  if (base::win::GetVersion() <= base::win::Version::WIN7)
+    return;
+
   if (IsTestCaseDisabled())
     return;
 
@@ -161,6 +166,10 @@
 }
 
 TEST_F(PrintingContextTest, Color) {
+  // TODO(crbug.com/1231528): Investigate why this test fails on Win 7 bots.
+  if (base::win::GetVersion() <= base::win::Version::WIN7)
+    return;
+
   if (IsTestCaseDisabled())
     return;
 
@@ -176,6 +185,10 @@
 }
 
 TEST_F(PrintingContextTest, Base) {
+  // TODO(crbug.com/1231528): Investigate why this test fails on Win 7 bots.
+  if (base::win::GetVersion() <= base::win::Version::WIN7)
+    return;
+
   if (IsTestCaseDisabled())
     return;
 
diff --git a/sql/database.cc b/sql/database.cc
index 4de5a5e..e6d5798e 100644
--- a/sql/database.cc
+++ b/sql/database.cc
@@ -1215,6 +1215,45 @@
   return Execute(sql);
 }
 
+bool Database::ExecuteScriptForTesting(const char* sql_script) {
+  DCHECK(sql_script);
+  if (!db_) {
+    DCHECK(poisoned_) << "Illegal use of Database without a db";
+    return false;
+  }
+
+  absl::optional<base::ScopedBlockingCall> scoped_blocking_call;
+  InitScopedBlockingCall(FROM_HERE, &scoped_blocking_call);
+
+  while (*sql_script) {
+    sqlite3_stmt* sqlite_statement;
+    int sqlite_error = sqlite3_prepare_v3(db_, sql_script, /* nByte= */ -1,
+                                          SqlitePrepareFlags(),
+                                          &sqlite_statement, &sql_script);
+    if (sqlite_error != SQLITE_OK)
+      return false;
+
+    if (!sqlite_statement) {
+      // Trailing comment or whitespace after the last semicolon.
+      return true;
+    }
+
+    // TODO(pwnall): Investigate restricting ExecuteScriptForTesting() to
+    //               statements that don't produce any result rows.
+    do {
+      sqlite_error = sqlite3_step(sqlite_statement);
+    } while (sqlite_error == SQLITE_ROW);
+
+    // sqlite3_finalize() returns SQLITE_OK if the most recent sqlite3_step()
+    // returned SQLITE_DONE or SQLITE_ROW, otherwise the error code.
+    sqlite_error = sqlite3_finalize(sqlite_statement);
+    if (sqlite_error != SQLITE_OK)
+      return false;
+  }
+
+  return true;
+}
+
 scoped_refptr<Database::StatementRef> Database::GetCachedStatement(
     StatementID id,
     const char* sql) {
@@ -1294,6 +1333,9 @@
       << "Unused text: " << std::string(unused_sql) << "\n"
       << "in prepared SQL statement: " << std::string(sql);
 #endif  // DCHECK_IS_ON()
+
+  DCHECK(sqlite_statement) << "No SQL statement in string: " << sql;
+
   return base::MakeRefCounted<StatementRef>(this, sqlite_statement, true);
 }
 
@@ -1347,6 +1389,8 @@
       << "in SQL statement: " << std::string(sql);
 #endif  // DCHECK_IS_ON()
 
+  DCHECK(sqlite_statement) << "No SQL statement in string: " << sql;
+
   sqlite3_finalize(sqlite_statement);
   return true;
 }
diff --git a/sql/database.h b/sql/database.h
index 92ec6cf..f17a7ba 100644
--- a/sql/database.h
+++ b/sql/database.h
@@ -398,15 +398,23 @@
   // Executes a SQL statement. Returns true for success, and false for failure.
   //
   // `sql` should be a single SQL statement. Production code should not execute
-  // multiple SQL statements at once, to facilitate crash debugging.
-  //
-  // TODO(crbug.com/1230443): Migrate testing code that executes multiple SQL
-  // statements to a separate method.
+  // multiple SQL statements at once, to facilitate crash debugging. Test code
+  // should use ExecuteScriptForTesting().
   //
   // `sql` cannot have parameters. Statements with parameters can be handled by
   // sql::Statement. See GetCachedStatement() and GetUniqueStatement().
   bool Execute(const char* sql) WARN_UNUSED_RESULT;
 
+  // Executes a sequence of SQL statements.
+  //
+  // Returns true if all statements execute successfully. If a statement fails,
+  // stops and returns false. Calls should be wrapped in ASSERT_TRUE().
+  //
+  // The database's error handler is not invoked when errors occur. This method
+  // is a convenience for setting up a complex on-disk database state, such as
+  // an old schema version with test contents.
+  bool ExecuteScriptForTesting(const char* sql_script) WARN_UNUSED_RESULT;
+
   // Returns a statement for the given SQL using the statement cache. It can
   // take a nontrivial amount of work to parse and compile a statement, so
   // keeping commonly-used ones around for future use is important for
diff --git a/sql/database_unittest.cc b/sql/database_unittest.cc
index de888e7..c5805eb 100644
--- a/sql/database_unittest.cc
+++ b/sql/database_unittest.cc
@@ -175,21 +175,94 @@
   std::unique_ptr<Database> db_;
 };
 
-TEST_P(SQLDatabaseTest, Execute) {
-  // Valid statement should return true.
-  ASSERT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
+TEST_P(SQLDatabaseTest, Execute_ValidStatement) {
+  ASSERT_TRUE(db_->Execute("CREATE TABLE data(contents TEXT)"));
   EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
+}
 
-  // Invalid statement should fail.
+TEST_P(SQLDatabaseTest, Execute_InvalidStatement) {
   {
     sql::test::ScopedErrorExpecter error_expecter;
     error_expecter.ExpectError(SQLITE_ERROR);
-    EXPECT_FALSE(db_->Execute("CREATE TAB foo (a, b"));
+    EXPECT_FALSE(db_->Execute("CREATE TABLE data("));
     EXPECT_TRUE(error_expecter.SawExpectedErrors());
   }
   EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode());
 }
 
+TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_OneLineValid) {
+  ASSERT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data(contents TEXT)"));
+  EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
+}
+
+TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_OneLineInvalid) {
+  ASSERT_FALSE(db_->ExecuteScriptForTesting("CREATE TABLE data("));
+  EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode());
+}
+
+TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_ExtraContents) {
+  EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data1(id)"))
+      << "Minimal statement";
+  EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data2(id);"))
+      << "Extra semicolon";
+  EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data3(id) -- Comment"))
+      << "Trailing comment";
+
+  EXPECT_TRUE(db_->ExecuteScriptForTesting(
+      "CREATE TABLE data4(id);CREATE TABLE data5(id)"))
+      << "Extra statement without whitespace";
+  EXPECT_TRUE(db_->ExecuteScriptForTesting(
+      "CREATE TABLE data6(id); CREATE TABLE data7(id)"))
+      << "Extra statement separated by whitespace";
+
+  EXPECT_TRUE(db_->ExecuteScriptForTesting("CREATE TABLE data8(id);-- Comment"))
+      << "Comment without whitespace";
+  EXPECT_TRUE(
+      db_->ExecuteScriptForTesting("CREATE TABLE data9(id); -- Comment"))
+      << "Comment sepatated by whitespace";
+}
+
+TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_MultipleValidLines) {
+  EXPECT_TRUE(db_->ExecuteScriptForTesting(R"(
+      CREATE TABLE data1(contents TEXT);
+      CREATE TABLE data2(contents TEXT);
+      CREATE TABLE data3(contents TEXT);
+  )"));
+  EXPECT_EQ(SQLITE_OK, db_->GetErrorCode());
+
+  // DoesColumnExist() is implemented directly on top of a SQLite call. The
+  // other schema functions use sql::Statement infrastructure to query the
+  // schema table.
+  EXPECT_TRUE(db_->DoesColumnExist("data1", "contents"));
+  EXPECT_TRUE(db_->DoesColumnExist("data2", "contents"));
+  EXPECT_TRUE(db_->DoesColumnExist("data3", "contents"));
+}
+
+TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_StopsOnCompileError) {
+  EXPECT_FALSE(db_->ExecuteScriptForTesting(R"(
+      CREATE TABLE data1(contents TEXT);
+      CREATE TABLE data1();
+      CREATE TABLE data3(contents TEXT);
+  )"));
+  EXPECT_EQ(SQLITE_ERROR, db_->GetErrorCode());
+
+  EXPECT_TRUE(db_->DoesColumnExist("data1", "contents"));
+  EXPECT_FALSE(db_->DoesColumnExist("data3", "contents"));
+}
+
+TEST_P(SQLDatabaseTest, ExecuteScriptForTesting_StopsOnStepError) {
+  EXPECT_FALSE(db_->ExecuteScriptForTesting(R"(
+      CREATE TABLE data1(contents TEXT UNIQUE);
+      INSERT INTO data1(contents) VALUES('value1');
+      INSERT INTO data1(contents) VALUES('value1');
+      CREATE TABLE data3(contents TEXT);
+  )"));
+  EXPECT_EQ(SQLITE_CONSTRAINT_UNIQUE, db_->GetErrorCode());
+
+  EXPECT_TRUE(db_->DoesColumnExist("data1", "contents"));
+  EXPECT_FALSE(db_->DoesColumnExist("data3", "contents"));
+}
+
 TEST_P(SQLDatabaseTest, CachedStatement) {
   StatementID id1 = SQL_FROM_HERE;
   StatementID id2 = SQL_FROM_HERE;
@@ -565,6 +638,30 @@
       << "Comment separated by whitespace";
 }
 
+TEST_P(SQLDatabaseTest, GetUniqueStatement_NoContents) {
+  EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("")) << "Empty string";
+  EXPECT_DCHECK_DEATH(db_->GetUniqueStatement(" ")) << "Space";
+  EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("\n")) << "Newline";
+  EXPECT_DCHECK_DEATH(db_->GetUniqueStatement("-- Comment")) << "Comment";
+}
+
+TEST_P(SQLDatabaseTest, GetCachedStatement_NoContents) {
+  EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE, ""))
+      << "Empty string";
+  EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE, " ")) << "Space";
+  EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE, "\n"))
+      << "Newline";
+  EXPECT_DCHECK_DEATH(db_->GetCachedStatement(SQL_FROM_HERE, "-- Comment"))
+      << "Comment";
+}
+
+TEST_P(SQLDatabaseTest, IsSQLValid_NoContents) {
+  EXPECT_DCHECK_DEATH(db_->IsSQLValid("")) << "Empty string";
+  EXPECT_DCHECK_DEATH(db_->IsSQLValid(" ")) << "Space";
+  EXPECT_DCHECK_DEATH(db_->IsSQLValid("\n")) << "Newline";
+  EXPECT_DCHECK_DEATH(db_->IsSQLValid("-- Comment")) << "Comment";
+}
+
 // Test that Database::Raze() results in a database without the
 // tables from the original database.
 TEST_P(SQLDatabaseTest, Raze) {
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 92a3159..9f2a934 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -10666,7 +10666,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.109"
+              "revision": "version:92.0.4515.112"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -10752,7 +10752,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M93",
-              "revision": "version:93.0.4577.8"
+              "revision": "version:93.0.4577.9"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -10924,7 +10924,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.109"
+              "revision": "version:92.0.4515.112"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -11010,7 +11010,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M93",
-              "revision": "version:93.0.4577.8"
+              "revision": "version:93.0.4577.9"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 7017c80..5b26422 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -49445,7 +49445,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.109"
+              "revision": "version:92.0.4515.112"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49532,7 +49532,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M93",
-              "revision": "version:93.0.4577.8"
+              "revision": "version:93.0.4577.9"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49706,7 +49706,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.109"
+              "revision": "version:92.0.4515.112"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49793,7 +49793,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M93",
-              "revision": "version:93.0.4577.8"
+              "revision": "version:93.0.4577.9"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50039,7 +50039,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.109"
+              "revision": "version:92.0.4515.112"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50125,7 +50125,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M93",
-              "revision": "version:93.0.4577.8"
+              "revision": "version:93.0.4577.9"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50297,7 +50297,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.109"
+              "revision": "version:92.0.4515.112"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50383,7 +50383,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M93",
-              "revision": "version:93.0.4577.8"
+              "revision": "version:93.0.4577.9"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50629,7 +50629,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.109"
+              "revision": "version:92.0.4515.112"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50715,7 +50715,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M93",
-              "revision": "version:93.0.4577.8"
+              "revision": "version:93.0.4577.9"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50887,7 +50887,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M92",
-              "revision": "version:92.0.4515.109"
+              "revision": "version:92.0.4515.112"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50973,7 +50973,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M93",
-              "revision": "version:93.0.4577.8"
+              "revision": "version:93.0.4577.9"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 5903eba..e19bb14 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -1605,25 +1605,6 @@
         "test_id_prefix": "ninja://tools/grit:grit_python_unittests/"
       },
       {
-        "isolate_name": "mac_signing_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mac_signing_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Mac-10.11"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/installer/mac:mac_signing_tests/"
-      },
-      {
         "isolate_name": "mojo_python_unittests",
         "merge": {
           "args": [],
@@ -3407,26 +3388,6 @@
         "test_id_prefix": "ninja://tools/grit:grit_python_unittests/"
       },
       {
-        "isolate_name": "mac_signing_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mac_signing_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.12.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/installer/mac:mac_signing_tests/"
-      },
-      {
         "isolate_name": "mojo_python_unittests",
         "merge": {
           "args": [],
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 62f124a5..1351d24 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -9393,1862 +9393,6 @@
       }
     ]
   },
-  "Linux TSan (bionic)": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "absl_hardening_tests",
-        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "accessibility_unittests",
-        "test_id_prefix": "ninja://ui/accessibility:accessibility_unittests/"
-      },
-      {
-        "args": [
-          "angle_unittests",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "app_shell_unittests",
-        "test_id_prefix": "ninja://extensions/shell:app_shell_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "aura_unittests",
-        "test_id_prefix": "ninja://ui/aura:aura_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_unittests",
-        "test_id_prefix": "ninja://base:base_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_util_unittests",
-        "test_id_prefix": "ninja://base/util:base_util_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_common_unittests",
-        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_fuzzer_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_fuzzer_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_heap_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_platform_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "blink_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_crypto_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_ssl_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
-      },
-      {
-        "args": [
-          "--gtest_filter=-*UsingRealWebcam*",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "capture_unittests",
-        "test_id_prefix": "ninja://media/capture:capture_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cast_unittests",
-        "test_id_prefix": "ninja://media/cast:cast_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "cc_unittests",
-        "test_id_prefix": "ninja://cc:cc_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_app_unittests",
-        "test_id_prefix": "ninja://chrome/test:chrome_app_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_unittests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "color_unittests",
-        "test_id_prefix": "ninja://ui/color:color_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_browsertests",
-        "test_id_prefix": "ninja://components:components_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "compositor_unittests",
-        "test_id_prefix": "ninja://ui/compositor:compositor_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 15
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
-          "--enable-gpu",
-          "--test-launcher-bot-mode",
-          "--test-launcher-jobs=1",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/vulkan.content_browsertests.filter",
-          "--enable-features=UseSkiaRenderer,UiGpuRasterization,Vulkan",
-          "--use-vulkan=swiftshader",
-          "--enable-oop-rasterization",
-          "--enable-gpu-rasterization",
-          "--disable-software-compositing-fallback",
-          "--disable-vulkan-fallback-to-gl-for-testing",
-          "--disable-headless-mode",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "vulkan_swiftshader_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_unittests",
-        "test_id_prefix": "ninja://content/test:content_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_tests",
-        "test_id_prefix": "ninja://components/cronet:cronet_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_unittests",
-        "test_id_prefix": "ninja://components/cronet:cronet_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crypto_unittests",
-        "test_id_prefix": "ninja://crypto:crypto_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "dbus_unittests",
-        "test_id_prefix": "ninja://dbus:dbus_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "device_unittests",
-        "test_id_prefix": "ninja://device:device_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "display_unittests",
-        "test_id_prefix": "ninja://ui/display:display_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "events_unittests",
-        "test_id_prefix": "ninja://ui/events:events_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_unittests",
-        "test_id_prefix": "ninja://extensions:extensions_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "filesystem_service_unittests",
-        "test_id_prefix": "ninja://components/services/filesystem:filesystem_service_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gcm_unit_tests",
-        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gfx_unittests",
-        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gin_unittests",
-        "test_id_prefix": "ninja://gin:gin_unittests/"
-      },
-      {
-        "args": [
-          "--use-cmd-decoder=passthrough",
-          "--test-launcher-print-test-stdio=always",
-          "--use-gpu-in-tests",
-          "--no-xvfb"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_passthrough",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3",
-              "os": "Ubuntu",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "gl_tests",
-        "test_id_prefix": "ninja://gpu:gl_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_unittests",
-        "test_id_prefix": "ninja://ui/gl:gl_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "google_apis_unittests",
-        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gpu_unittests",
-        "test_id_prefix": "ninja://gpu:gpu_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gtk_unittests",
-        "test_id_prefix": "ninja://ui/gtk:gtk_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gwp_asan_unittests",
-        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_browsertests",
-        "test_id_prefix": "ninja://headless:headless_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_unittests",
-        "test_id_prefix": "ninja://headless:headless_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 32
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ipc_tests",
-        "test_id_prefix": "ninja://ipc:ipc_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "jingle_unittests",
-        "test_id_prefix": "ninja://jingle:jingle_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "latency_unittests",
-        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "libjingle_xmpp_unittests",
-        "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "liburlpattern_unittests",
-        "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_unittests",
-        "test_id_prefix": "ninja://media:media_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "message_center_unittests",
-        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "midi_unittests",
-        "test_id_prefix": "ninja://media/midi:midi_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_core_unittests",
-        "test_id_prefix": "ninja://mojo/core:mojo_core_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_unittests",
-        "test_id_prefix": "ninja://mojo:mojo_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "native_theme_unittests",
-        "test_id_prefix": "ninja://ui/native_theme:native_theme_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test": "net_unittests",
-        "test_id_prefix": "ninja://net:net_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "openscreen_unittests",
-        "test_id_prefix": "ninja://chrome/browser/media/router:openscreen_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "pdf_unittests",
-        "test_id_prefix": "ninja://pdf:pdf_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "perfetto_unittests",
-        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ppapi_unittests",
-        "test_id_prefix": "ninja://ppapi:ppapi_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "printing_unittests",
-        "test_id_prefix": "ninja://printing:printing_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "remoting_unittests",
-        "test_id_prefix": "ninja://remoting:remoting_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sandbox_linux_unittests",
-        "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "service_manager_unittests",
-        "test_id_prefix": "ninja://services/service_manager/tests:service_manager_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "services_unittests",
-        "test_id_prefix": "ninja://services:services_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "shell_dialogs_unittests",
-        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "skia_unittests",
-        "test_id_prefix": "ninja://skia:skia_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "snapshot_unittests",
-        "test_id_prefix": "ninja://ui/snapshot:snapshot_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sql_unittests",
-        "test_id_prefix": "ninja://sql:sql_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "storage_unittests",
-        "test_id_prefix": "ninja://storage:storage_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "sync_integration_tests",
-        "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "traffic_annotation_auditor_unittests",
-        "test_id_prefix": "ninja://tools/traffic_annotation/auditor:traffic_annotation_auditor_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_base_unittests",
-        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_touch_selection_unittests",
-        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "unit_tests",
-        "test_id_prefix": "ninja://chrome/test:unit_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "url_unittests",
-        "test_id_prefix": "ninja://url:url_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_unittests",
-        "test_id_prefix": "ninja://ui/views:views_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "viz_unittests",
-        "test_id_prefix": "ninja://components/viz:viz_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_common_unittests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_common_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "vr_pixeltests",
-        "test_id_prefix": "ninja://chrome/browser/vr:vr_pixeltests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_browsertests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_unittests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wm_unittests",
-        "test_id_prefix": "ninja://ui/wm:wm_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wtf_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "x11_unittests",
-        "test_id_prefix": "ninja://ui/platform_window/x11:x11_unittests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "xr_browser_tests",
-        "test_id_prefix": "ninja://chrome/test:xr_browser_tests/"
-      },
-      {
-        "args": [
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-18.04"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "zlib_unittests",
-        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
-      }
-    ]
-  },
   "Linux TSan Tests": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index d9585df..fe7f317 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -557,9 +557,7 @@
       'Mac10.15 Tests', # https://crbug.com/1042757
       'Mac10.15 Tests (dbg)', # https://crbug.com/1201386
       'mac-code-coverage', # https://crbug.com/1201386
-      'Linux TSan (bionic)',  # https://crbug.com/368525
       'Linux TSan Tests',  # https://crbug.com/368525
-      # TODO(crbug.com/1200904): Remove after migration
       'Win10 Tests x64 (dbg)',
     ],
     'modifications': {
@@ -777,12 +775,6 @@
   },
   'cc_unittests': {
     'modifications': {
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        'swarming': {
-          'shards': 3,
-        },
-      },
       'Linux TSan Tests': {
         'swarming': {
           'shards': 3,
@@ -1141,12 +1133,6 @@
           'shards': 5,
         },
       },
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        'swarming': {
-          'shards': 2,
-        },
-      },
       'Linux TSan Tests': {
         'swarming': {
           'shards': 2,
@@ -1211,12 +1197,6 @@
           'shards': 10, # https://crbug.com/1103330
         },
       },
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        'swarming': {
-          'shards': 15,
-        },
-      },
       'Linux TSan Tests': {
         'swarming': {
           'shards': 15,
@@ -1465,8 +1445,6 @@
   'crashpad_tests': {
     'remove_from': [
       'linux-win_cross-rel', # https://crbug.com/762167
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)',
       # https://crbug.com/crashpad/304
       'Linux TSan Tests',
       'ToTLinuxTSan',
@@ -1611,22 +1589,6 @@
           ],
         },
       },
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        'args': [
-          '--use-gpu-in-tests',
-          '--no-xvfb',
-        ],
-        'swarming': {
-          'dimension_sets': [
-            {
-              'gpu': '10de:1cb3',
-              'os': 'Ubuntu',
-              'pool': 'chromium.tests.gpu',
-            },
-          ],
-        },
-      },
       'Linux TSan Tests': {
         'args': [
           '--use-gpu-in-tests',
@@ -1797,13 +1759,6 @@
           'shards': 5,
         },
       },
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        # These are slow on the TSan bots for some reason, crbug.com/794372
-        'swarming': {
-          'shards': 32, # Adjusted for testing, see https://crbug.com/1179567
-        },
-      },
       'Linux TSan Tests': {
         # These are slow on the TSan bots for some reason, crbug.com/794372
         'swarming': {
@@ -1908,6 +1863,13 @@
       },
     },
   },
+  'mac_signing_tests': {
+    'remove_from': [
+      # TODO(crbug.com/1220743): Re-enable.
+      'Mac10.11 Tests',
+      'Mac10.12 Tests',
+    ]
+  },
   'maps_pixel_passthrough_test': {
     'modifications': {
       'Android FYI Release (Pixel 4)': {
@@ -2158,8 +2120,6 @@
   },
   'nacl_helper_nonsfi_unittests': {
     'remove_from': [
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)',  # Sets enable_nacl=false.
       'Linux TSan Tests',  # Sets enable_nacl=false.
     ],
   },
@@ -2167,8 +2127,6 @@
     'remove_from': [
       'ToTMacASan',  # The mac asan tot bot sets enable_nacl=false
       'linux-win_cross-rel',  # Sets enable_nacl=false, https://crbug.com/774186
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)',  # The TSan bot sets enable_nacl=false
       'Linux TSan Tests',  # The TSan bot sets enable_nacl=false
       'Mac ASan 64 Tests (1)',  # The mac asan bot sets enable_nacl=false
     ],
@@ -2208,12 +2166,6 @@
           'shards': 2,
         },
       },
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        'swarming': {
-          'shards': 4,
-        }
-      },
       'Linux TSan Tests': {
         'swarming': {
           'shards': 4,
@@ -2659,12 +2611,6 @@
           'shards': 4,
         },
       },
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        'swarming': {
-          'shards': 6,
-        },
-      },
       'Linux TSan Tests': {
         'swarming': {
           'shards': 6,
@@ -2918,12 +2864,6 @@
           'shards': 2,
         },
       },
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        'swarming': {
-          'shards': 2,
-        },
-      },
       'Linux TSan Tests': {
         'swarming': {
           'shards': 2,
@@ -3185,12 +3125,6 @@
           'shards': 5,
         },
       },
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        'swarming': {
-          'shards': 2,
-        },
-      },
       'Linux TSan Tests': {
         'swarming': {
           'shards': 2,
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index a4c701d..baba694 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -431,7 +431,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M93',
-          'revision': 'version:93.0.4577.8',
+          'revision': 'version:93.0.4577.9',
         }
       ],
     },
@@ -455,7 +455,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M92',
-          'revision': 'version:92.0.4515.109',
+          'revision': 'version:92.0.4515.112',
         }
       ],
     },
@@ -503,7 +503,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M93',
-          'revision': 'version:93.0.4577.8',
+          'revision': 'version:93.0.4577.9',
         }
       ],
     },
@@ -527,7 +527,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M92',
-          'revision': 'version:92.0.4515.109',
+          'revision': 'version:92.0.4515.112',
         }
       ],
     },
@@ -575,7 +575,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M93',
-          'revision': 'version:93.0.4577.8',
+          'revision': 'version:93.0.4577.9',
         }
       ],
     },
@@ -599,7 +599,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M92',
-          'revision': 'version:92.0.4515.109',
+          'revision': 'version:92.0.4515.112',
         }
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index c30aa8d..747b3c7 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -5304,18 +5304,6 @@
           '--test-launcher-print-test-stdio=always',
         ],
       },
-      # TODO(crbug.com/1200904): Remove after migration
-      'Linux TSan (bionic)': {
-        'mixins': [
-          'linux-bionic',
-        ],
-        'test_suites': {
-          'gtest_tests': 'chromium_linux_and_gl_and_vulkan_gtests',
-        },
-        'args': [
-          '--test-launcher-print-test-stdio=always',
-        ],
-      },
       'Linux TSan Tests': {
         'mixins': [
           'linux-bionic',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 5b4fba3..68b5a77 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2251,6 +2251,21 @@
             ]
         }
     ],
+    "CommerceMerchantViewer": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_20210721",
+                    "params": {
+                        "delete_all_merchants_on_clear_history": "true"
+                    }
+                }
+            ]
+        }
+    ],
     "CompositeAfterPaint": [
         {
             "platforms": [
diff --git a/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc b/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
index 06b0c84..d573470 100644
--- a/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
+++ b/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
@@ -5,7 +5,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/js_event_handler.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
-#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_string_resource.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/core/events/before_unload_event.h"
@@ -91,6 +91,7 @@
   HeapVector<ScriptValue> arguments;
   ScriptState* script_state_of_listener =
       event_handler_->CallbackRelevantScriptState();
+  v8::Isolate* isolate = script_state_of_listener->GetIsolate();
 
   if (special_error_event_handling) {
     auto* error_event = To<ErrorEvent>(&event);
@@ -100,17 +101,27 @@
     ScriptValue error_attribute = error_event->error(script_state_of_listener);
     if (error_attribute.IsEmpty() ||
         error_event->target()->InterfaceName() == event_target_names::kWorker) {
-      error_attribute =
-          ScriptValue::CreateNull(script_state_of_listener->GetIsolate());
+      error_attribute = ScriptValue::CreateNull(isolate);
     }
     arguments = {
-        ScriptValue::From(script_state_of_listener, error_event->message()),
-        ScriptValue::From(script_state_of_listener, error_event->filename()),
-        ScriptValue::From(script_state_of_listener, error_event->lineno()),
-        ScriptValue::From(script_state_of_listener, error_event->colno()),
+        ScriptValue(isolate,
+                    ToV8Traits<IDLStringV2>::ToV8(script_state_of_listener,
+                                                  error_event->message())
+                        .ToLocalChecked()),
+        ScriptValue(isolate,
+                    ToV8Traits<IDLStringV2>::ToV8(script_state_of_listener,
+                                                  error_event->filename())
+                        .ToLocalChecked()),
+        ScriptValue(isolate,
+                    ToV8Traits<IDLUnsignedLong>::ToV8(script_state_of_listener,
+                                                      error_event->lineno())
+                        .ToLocalChecked()),
+        ScriptValue(isolate, ToV8Traits<IDLUnsignedLong>::ToV8(
+                                 script_state_of_listener, error_event->colno())
+                                 .ToLocalChecked()),
         error_attribute};
   } else {
-    arguments = {ScriptValue::From(script_state_of_listener, js_event)};
+    arguments.push_back(ScriptValue(isolate, js_event));
   }
 
   if (!event_handler_->IsRunnableOrThrowException(
@@ -123,7 +134,7 @@
   if (!event_handler_
            ->InvokeWithoutRunnabilityCheck(event.currentTarget(), arguments)
            .To(&result) ||
-      GetIsolate()->IsExecutionTerminating())
+      isolate->IsExecutionTerminating())
     return;
   v8::Local<v8::Value> v8_return_value = result.V8Value();
 
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 0bce899..5e0cbdf 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -2077,12 +2077,20 @@
   if (lh.IsNegative() && font.PrimaryFont())
     return font.PrimaryFont()->GetFontMetrics().FixedLineSpacing();
 
-  if (lh.IsPercentOrCalc()) {
-    return LayoutUnit(
-        MinimumValueForLength(lh, ComputedFontSizeAsFixed(font)).ToInt());
-  }
+  if (RuntimeEnabledFeatures::FractionalLineHeightEnabled()) {
+    if (lh.IsPercentOrCalc()) {
+      return MinimumValueForLength(lh, ComputedFontSizeAsFixed(font));
+    }
 
-  return LayoutUnit(floorf(lh.Value()));
+    return LayoutUnit::FromFloatFloor(lh.Value());
+  } else {
+    if (lh.IsPercentOrCalc()) {
+      return LayoutUnit(
+          MinimumValueForLength(lh, ComputedFontSizeAsFixed(font)).ToInt());
+    }
+
+    return LayoutUnit(floorf(lh.Value()));
+  }
 }
 
 LayoutUnit ComputedStyle::ComputedLineHeightAsFixed() const {
diff --git a/third_party/blink/renderer/modules/breakout_box/BUILD.gn b/third_party/blink/renderer/modules/breakout_box/BUILD.gn
index 497fde0..f622158 100644
--- a/third_party/blink/renderer/modules/breakout_box/BUILD.gn
+++ b/third_party/blink/renderer/modules/breakout_box/BUILD.gn
@@ -31,10 +31,6 @@
     "pushable_media_stream_video_source.h",
     "transferred_frame_queue_underlying_source.cc",
     "transferred_frame_queue_underlying_source.h",
-    "video_track_signal_underlying_sink.cc",
-    "video_track_signal_underlying_sink.h",
-    "video_track_signal_underlying_source.cc",
-    "video_track_signal_underlying_source.h",
   ]
   deps = [
     "//third_party/blink/renderer/modules/mediastream:mediastream",
@@ -56,8 +52,6 @@
     "pushable_media_stream_video_source_test.cc",
     "stream_test_utils.cc",
     "stream_test_utils.h",
-    "video_track_signal_underlying_sink_test.cc",
-    "video_track_signal_underlying_source_test.cc",
   ]
 
   deps = [
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator.cc
index e0b321c..4403046 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_track_generator.cc
@@ -8,14 +8,12 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_media_stream_track_generator_init.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/streams/readable_stream.h"
 #include "third_party/blink/renderer/core/streams/writable_stream.h"
 #include "third_party/blink/renderer/core/streams/writable_stream_transferring_optimizer.h"
 #include "third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_sink.h"
 #include "third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_sink.h"
 #include "third_party/blink/renderer/modules/breakout_box/pushable_media_stream_audio_source.h"
 #include "third_party/blink/renderer/modules/breakout_box/pushable_media_stream_video_source.h"
-#include "third_party/blink/renderer/modules/breakout_box/video_track_signal_underlying_source.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_utils.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -28,18 +26,6 @@
 
 namespace blink {
 
-namespace {
-
-const wtf_size_t kDefaultMaxSignalBufferSize = 20u;
-
-class NullUnderlyingSource : public UnderlyingSourceBase {
- public:
-  explicit NullUnderlyingSource(ScriptState* script_state)
-      : UnderlyingSourceBase(script_state) {}
-};
-
-}  // namespace
-
 MediaStreamTrackGenerator* MediaStreamTrackGenerator::Create(
     ScriptState* script_state,
     const String& kind,
@@ -62,8 +48,7 @@
 
   return MakeGarbageCollected<MediaStreamTrackGenerator>(
       script_state, type,
-      /*track_id=*/WTF::CreateCanonicalUUIDString(), nullptr,
-      kDefaultMaxSignalBufferSize);
+      /*track_id=*/WTF::CreateCanonicalUUIDString());
 }
 
 MediaStreamTrackGenerator* MediaStreamTrackGenerator::Create(
@@ -81,11 +66,6 @@
     return nullptr;
   }
 
-  if (init->hasSignalTarget() && init->signalTarget()->kind() != init->kind()) {
-    exception_state.ThrowTypeError("kind and signalTarget.kind() do not match");
-    return nullptr;
-  }
-
   MediaStreamSource::StreamType type;
   if (init->kind() == "video") {
     type = MediaStreamSource::kTypeVideo;
@@ -96,33 +76,24 @@
     return nullptr;
   }
 
-  wtf_size_t max_signal_buffer_size = kDefaultMaxSignalBufferSize;
-  if (init->hasMaxSignalBufferSize())
-    max_signal_buffer_size = init->maxSignalBufferSize();
-
   return MakeGarbageCollected<MediaStreamTrackGenerator>(
       script_state, type,
-      /*track_id=*/WTF::CreateCanonicalUUIDString(),
-      init->getSignalTargetOr(nullptr),
-      max_signal_buffer_size);
+      /*track_id=*/WTF::CreateCanonicalUUIDString());
 }
 
 MediaStreamTrackGenerator::MediaStreamTrackGenerator(
     ScriptState* script_state,
     MediaStreamSource::StreamType type,
-    const String& track_id,
-    MediaStreamTrack* signal_target,
-    wtf_size_t max_signal_buffer_size)
+    const String& track_id)
     : MediaStreamTrack(
           ExecutionContext::From(script_state),
           MakeGarbageCollected<MediaStreamComponent>(
               MakeGarbageCollected<MediaStreamSource>(track_id,
                                                       type,
                                                       track_id,
-                                                      /*remote=*/false))),
-      max_signal_buffer_size_(max_signal_buffer_size) {
+                                                      /*remote=*/false))) {
   if (type == MediaStreamSource::kTypeVideo) {
-    CreateVideoOutputPlatformTrack(signal_target);
+    CreateVideoOutputPlatformTrack();
   } else {
     DCHECK_EQ(type, MediaStreamSource::kTypeAudio);
     CreateAudioOutputPlatformTrack();
@@ -143,19 +114,6 @@
   return writable_;
 }
 
-ReadableStream* MediaStreamTrackGenerator::readableControl(
-    ScriptState* script_state) {
-  if (readable_control_)