diff --git a/DEPS b/DEPS
index 079d488..221c5cb 100644
--- a/DEPS
+++ b/DEPS
@@ -199,7 +199,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:e9585787c808e21d6eaa2c7d7a928dbc19999172',
+  'luci_go': 'git_revision:a373a19da0fbbbe81b2b684e3797260294393e40',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -231,7 +231,7 @@
   # 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': '0bfac0127c5e4e67c2f37622f00d370b9fbd00a7',
+  'skia_revision': 'f2fb26d162b950d1a52cdf81c2fcf82cb4b5de59',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -306,7 +306,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': '1fc91d67bf1a8363fdf800aa665402537c729ef2',
+  'devtools_frontend_revision': 'f514645ba5af1aec49d69f07f0811ccfc068b950',
   # 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.
@@ -346,7 +346,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': 'dc890d6915a004c398e5e83e0467433109ac129e',
+  'dawn_revision': '51791e04094f7f399dab8c507b3ab5336936f2fb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1037,7 +1037,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ce514ad38e0f8077d92704d2300f6ab0a1d263ad',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '45ca14d5ec897a98e458abbdc1123633222c5fbb',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1644,7 +1644,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'b0291fd966b55a5efc496772555b94842bde1085',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '11806896bba2c7d040ab81b4999f340ec557b7ef',
+    Var('webrtc_git') + '/src.git' + '@' + '4a1c2c4754aa145625bd03aa1176a75d68ffa896',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1671,7 +1671,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'qxkaCck3N7NNLCHvQM2gksDboY80QAXbM9dfnJD0-y8C',
+          'version': 'nd7yQQ-V4Vhc9bpvP_u3p7X0LVCxdlS946BHctVPg5MC',
         },
       ],
       'dep_type': 'cipd',
@@ -1681,7 +1681,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': 'mXlfDemOBUbOngfIwncHzw56bAtEBcVh15WyA9ikp2cC',
+          'version': 'rcX7oPaX2IWDB3XLoKp3dksyI7hhD7sMhOJrwNq46hAC',
         },
       ],
       'dep_type': 'cipd',
@@ -1691,7 +1691,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-amd64',
-          'version': 'U5z-9pZVF7_n6d_eDRqkGGExXzWAwaI9weKVJ0UNCWIC',
+          'version': '5DO-jjFFNcDssKFQDFLkkgvfeRqjlYUfRb9j2-QN2EYC',
         },
       ],
       'dep_type': 'cipd',
@@ -1702,7 +1702,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d31c628a9226d68e16507278d1a9e02cfd123e14',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@904937f61dd57e4269eb5d61874a64215cd85d32',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index bb3d0c38..faed6640 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2775,8 +2775,9 @@
     'spellcheck': ['rlp+watch@chromium.org',
                    'rouslan+spell@chromium.org',
                    'timvolodine@chromium.org'],
-    'startup': ['grt+watch@chromium.org',
-                'pastarmovj+watch@chromium.org'],
+    'startup': ['nicolaso+watch@chromium.org',
+                'pastarmovj+watch@chromium.org',
+                'ydago+watch@chromium.org'],
     'status_area': ['cros-status-area-eng+watchlist@google.com'],
     'storage_service': ['dmurph+watching-storageservice@chromium.org'],
     'structured_headers': ['iclelland+watch@chromium.org'],
diff --git a/apps/COMMON_METADATA b/apps/COMMON_METADATA
new file mode 100644
index 0000000..603ee30
--- /dev/null
+++ b/apps/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Platform>Apps"
+}
+team_email: "apps-dev@chromium.org"
\ No newline at end of file
diff --git a/apps/DIR_METADATA b/apps/DIR_METADATA
index e2c4d38a..46fce34 100644
--- a/apps/DIR_METADATA
+++ b/apps/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Platform>Apps"
-}
-team_email: "apps-dev@chromium.org"
\ No newline at end of file
+mixins: "//apps/COMMON_METADATA"
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 14c812f..6360187 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -564,8 +564,14 @@
     "login/ui/animation_frame.h",
     "login/ui/arrow_button_view.cc",
     "login/ui/arrow_button_view.h",
+    "login/ui/auth_factor_model.cc",
+    "login/ui/auth_factor_model.h",
+    "login/ui/auth_icon_view.cc",
+    "login/ui/auth_icon_view.h",
     "login/ui/bottom_status_indicator.cc",
     "login/ui/bottom_status_indicator.h",
+    "login/ui/fingerprint_auth_model.cc",
+    "login/ui/fingerprint_auth_model.h",
     "login/ui/horizontal_image_sequence_animation_decoder.cc",
     "login/ui/horizontal_image_sequence_animation_decoder.h",
     "login/ui/hover_notifier.cc",
@@ -580,6 +586,8 @@
     "login/ui/lock_screen.h",
     "login/ui/lock_screen_media_controls_view.cc",
     "login/ui/lock_screen_media_controls_view.h",
+    "login/ui/login_auth_factors_view.cc",
+    "login/ui/login_auth_factors_view.h",
     "login/ui/login_auth_user_view.cc",
     "login/ui/login_auth_user_view.h",
     "login/ui/login_base_bubble_view.cc",
diff --git a/ash/accessibility/DIR_METADATA b/ash/accessibility/DIR_METADATA
index 14320f50..79fdee1 100644
--- a/ash/accessibility/DIR_METADATA
+++ b/ash/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail {
   component: "OS>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/ash/app_list/views/assistant/DIR_METADATA b/ash/app_list/views/assistant/DIR_METADATA
index 5cf9e51..cfb0c371 100644
--- a/ash/app_list/views/assistant/DIR_METADATA
+++ b/ash/app_list/views/assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Shell>Assistant"
-}
+mixins: "//chromeos/assistant/COMMON_METADATA"
diff --git a/ash/assistant/DIR_METADATA b/ash/assistant/DIR_METADATA
index 5cf9e51..cfb0c371 100644
--- a/ash/assistant/DIR_METADATA
+++ b/ash/assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Shell>Assistant"
-}
+mixins: "//chromeos/assistant/COMMON_METADATA"
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index d06066bf..ca9efff71 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1048,7 +1048,7 @@
 // Enables or disables using the system input engine for physical typing in
 // Korean.
 const base::Feature kSystemKoreanPhysicalTyping{
-    "SystemKoreanPhysicalTyping", base::FEATURE_DISABLED_BY_DEFAULT};
+    "SystemKoreanPhysicalTyping", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables or disables using the system input engine for physical typing in
 // languages based on latin script.
diff --git a/ash/dbus/DIR_METADATA b/ash/dbus/DIR_METADATA
new file mode 100644
index 0000000..40779e6
--- /dev/null
+++ b/ash/dbus/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chromeos/dbus/COMMON_METADATA"
diff --git a/ash/keyboard/COMMON_METADATA b/ash/keyboard/COMMON_METADATA
new file mode 100644
index 0000000..1ae4c22
--- /dev/null
+++ b/ash/keyboard/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Inputs"
+}
diff --git a/ash/keyboard/DIR_METADATA b/ash/keyboard/DIR_METADATA
index 1ae4c22..671c987 100644
--- a/ash/keyboard/DIR_METADATA
+++ b/ash/keyboard/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Inputs"
-}
+mixins: "//ash/keyboard/COMMON_METADATA"
diff --git a/ash/login/ui/auth_factor_model.cc b/ash/login/ui/auth_factor_model.cc
new file mode 100644
index 0000000..78d80d96
--- /dev/null
+++ b/ash/login/ui/auth_factor_model.cc
@@ -0,0 +1,21 @@
+// 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 "ash/login/ui/auth_factor_model.h"
+
+namespace ash {
+
+int operator|(int types, AuthFactorType type) {
+  return types | static_cast<int>(type);
+}
+
+int operator|(AuthFactorType type1, AuthFactorType type2) {
+  return static_cast<int>(type1) | static_cast<int>(type2);
+}
+
+AuthFactorModel::AuthFactorModel() = default;
+
+AuthFactorModel::~AuthFactorModel() = default;
+
+}  // namespace ash
diff --git a/ash/login/ui/auth_factor_model.h b/ash/login/ui/auth_factor_model.h
new file mode 100644
index 0000000..0263eb09
--- /dev/null
+++ b/ash/login/ui/auth_factor_model.h
@@ -0,0 +1,76 @@
+// 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 ASH_LOGIN_UI_AUTH_FACTOR_MODEL_H_
+#define ASH_LOGIN_UI_AUTH_FACTOR_MODEL_H_
+
+#include <string>
+
+namespace ash {
+
+class AuthIconView;
+
+enum class AuthFactorType {
+  kFingerprint = 1 << 0,
+  kSmartLock = 1 << 1,
+};
+
+// Allow combining AuthFactorTypes with bitwise OR. Used to look up the
+// appropriate label to show when several auth factors are visible.
+int operator|(int types, AuthFactorType type);
+int operator|(AuthFactorType type1, AuthFactorType type2);
+
+// Base class representing an auth factor. Used by LoginAuthFactorsView to
+// display a list of auth factors.
+class AuthFactorModel {
+ public:
+  enum class AuthFactorState {
+    // The feature is disabled, disallowed by policy, or requires
+    // hardware that isn’t present.
+    kUnavailable,
+    // The auth factor can be used but requires additional steps
+    // before use, e.g. turn on Bluetooth.
+    kAvailable,
+    // The auth factor is ready to authenticate. This state should
+    // only be returned if authentication can be completed in one
+    // step (two if a click is required).
+    kReady,
+    // The auth factor has a non-blocking error to show the
+    // user, e.g. Fingerprint’s “Not recognized”, which clears
+    // after a few seconds. GetLabel() and UpdateIcon() show the
+    // relevant messages.
+    kErrorTemporary,
+    // The auth factor cannot be used because of an unrecoverable
+    // error, e.g. Fingerprint’s “Too many attempts”. GetLabel()
+    // and UpdateIcon() show the relevant messages.
+    kErrorPermanent,
+    // The auth factor requires the user to tap/click to enter.
+    kClickRequired,
+    // Authentication is complete.
+    kAuthenticated,
+  };
+
+  AuthFactorModel();
+  AuthFactorModel(AuthFactorModel&) = delete;
+  AuthFactorModel& operator=(AuthFactorModel&) = delete;
+  virtual ~AuthFactorModel();
+
+  virtual AuthFactorState GetAuthFactorState() = 0;
+
+  virtual AuthFactorType GetType() = 0;
+
+  // The label that should be shown in the current state.
+  virtual std::u16string GetLabel() = 0;
+
+  // Controls whether the label is announced by Chromevox.
+  virtual bool ShouldAnnounceLabel() = 0;
+
+  // Update an AuthIconView to represent the current state of the auth factor.
+  // Should call SetIcon() or set up an animation.
+  virtual void UpdateIcon(AuthIconView* icon_view) = 0;
+};
+
+}  // namespace ash
+
+#endif  // ASH_LOGIN_UI_AUTH_FACTOR_MODEL_H_
diff --git a/ash/login/ui/auth_icon_view.cc b/ash/login/ui/auth_icon_view.cc
new file mode 100644
index 0000000..c7c039b30
--- /dev/null
+++ b/ash/login/ui/auth_icon_view.cc
@@ -0,0 +1,31 @@
+// 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 "ash/login/ui/auth_icon_view.h"
+
+#include "ash/style/ash_color_provider.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/vector_icon_types.h"
+
+namespace ash {
+
+namespace {
+constexpr int kAuthIconSizeDp = 28;
+}
+
+AuthIconView::AuthIconView()
+    : AnimatedRoundedImageView(gfx::Size(kAuthIconSizeDp, kAuthIconSizeDp),
+                               /*corner_radius=*/0) {}
+
+AuthIconView::~AuthIconView() = default;
+
+void AuthIconView::SetIcon(const gfx::VectorIcon& icon) {
+  const SkColor icon_color = AshColorProvider::Get()->GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kIconColorPrimary);
+
+  SetImage(gfx::CreateVectorIcon(icon, kAuthIconSizeDp, icon_color));
+}
+
+}  // namespace ash
diff --git a/ash/login/ui/auth_icon_view.h b/ash/login/ui/auth_icon_view.h
new file mode 100644
index 0000000..afcc9cfe
--- /dev/null
+++ b/ash/login/ui/auth_icon_view.h
@@ -0,0 +1,33 @@
+// 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 ASH_LOGIN_UI_AUTH_ICON_VIEW_H_
+#define ASH_LOGIN_UI_AUTH_ICON_VIEW_H_
+
+#include "ash/login/ui/animated_rounded_image_view.h"
+
+namespace gfx {
+struct VectorIcon;
+}  // namespace gfx
+
+namespace ash {
+
+// An icon with a built-in progress bar functionality and animation support used
+// to show auth factors (e.g. Fingerprint, Smart Lock) in the
+// LoginAuthFactorsView.
+// TODO(crbug.com/1252880): Add progress animation.
+class AuthIconView : public AnimatedRoundedImageView {
+ public:
+  AuthIconView();
+  AuthIconView(AuthIconView&) = delete;
+  AuthIconView& operator=(AuthIconView&) = delete;
+  ~AuthIconView() override;
+
+  // Show a static icon.
+  void SetIcon(const gfx::VectorIcon& icon);
+};
+
+}  // namespace ash
+
+#endif  // ASH_LOGIN_UI_AUTH_ICON_VIEW_H_
diff --git a/ash/login/ui/fingerprint_auth_model.cc b/ash/login/ui/fingerprint_auth_model.cc
new file mode 100644
index 0000000..1b239487
--- /dev/null
+++ b/ash/login/ui/fingerprint_auth_model.cc
@@ -0,0 +1,49 @@
+// 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 "ash/login/ui/fingerprint_auth_model.h"
+
+#include "ash/login/ui/auth_icon_view.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// TODO(crbug.com/1233614): This stub will be replaced with a full
+// implementation as part of the Smart Lock UI revamp.
+
+namespace ash {
+
+FingerprintAuthModel::FingerprintAuthModel() = default;
+
+FingerprintAuthModel::~FingerprintAuthModel() = default;
+
+AuthFactorModel::AuthFactorState FingerprintAuthModel::GetAuthFactorState() {
+  // TODO(crbug.com/1233614): Calculate the correct AuthFactorState based on the
+  // current FingerprintState.
+  return AuthFactorState::kUnavailable;
+}
+
+AuthFactorType FingerprintAuthModel::GetType() {
+  return AuthFactorType::kFingerprint;
+}
+
+std::u16string FingerprintAuthModel::GetLabel() {
+  // TODO(crbug.com/1233614): Calculate the correct label based on the current
+  // FingerprintState.
+  return l10n_util::GetStringUTF16(IDS_ASH_LOGIN_FINGERPRINT_UNLOCK_AVAILABLE);
+}
+
+bool FingerprintAuthModel::ShouldAnnounceLabel() {
+  // TODO(crbug.com/1233614): Correctly choose which labels to announce in order
+  // to match the behavior of the existing Fingerprint implementation.
+  return false;
+}
+
+void FingerprintAuthModel::UpdateIcon(AuthIconView* icon_view) {
+  // TODO(crbug.com/1233614): Show the correct icon/animation depending on the
+  // current FingerprintState.
+  icon_view->SetIcon(kLockScreenFingerprintIcon);
+}
+
+}  // namespace ash
diff --git a/ash/login/ui/fingerprint_auth_model.h b/ash/login/ui/fingerprint_auth_model.h
new file mode 100644
index 0000000..3310fbc
--- /dev/null
+++ b/ash/login/ui/fingerprint_auth_model.h
@@ -0,0 +1,36 @@
+// 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 ASH_LOGIN_UI_FINGERPRINT_AUTH_MODEL_H_
+#define ASH_LOGIN_UI_FINGERPRINT_AUTH_MODEL_H_
+
+#include <string>
+
+#include "ash/login/ui/auth_factor_model.h"
+
+namespace ash {
+
+class AuthIconView;
+
+// Implements the logic necessary to show Fingerprint as an auth factor on the
+// lock screen.
+// TODO(crbug.com/1233614): Finish migrating FingerprintView to this class.
+class FingerprintAuthModel : public AuthFactorModel {
+ public:
+  FingerprintAuthModel();
+  FingerprintAuthModel(FingerprintAuthModel&) = delete;
+  FingerprintAuthModel& operator=(FingerprintAuthModel&) = delete;
+  ~FingerprintAuthModel() override;
+
+  // AuthFactorModel:
+  AuthFactorState GetAuthFactorState() override;
+  AuthFactorType GetType() override;
+  std::u16string GetLabel() override;
+  bool ShouldAnnounceLabel() override;
+  void UpdateIcon(AuthIconView* icon_view) override;
+};
+
+}  // namespace ash
+
+#endif  // ASH_LOGIN_UI_FINGERPRINT_AUTH_MODEL_H_
diff --git a/ash/login/ui/login_auth_factors_view.cc b/ash/login/ui/login_auth_factors_view.cc
new file mode 100644
index 0000000..aa105d71
--- /dev/null
+++ b/ash/login/ui/login_auth_factors_view.cc
@@ -0,0 +1,70 @@
+// 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 "ash/login/ui/login_auth_factors_view.h"
+
+#include "ash/login/ui/auth_factor_model.h"
+#include "ash/login/ui/auth_icon_view.h"
+#include "ash/style/ash_color_provider.h"
+#include "ui/compositor/layer.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+
+namespace ash {
+
+namespace {
+
+constexpr int kAuthFactorsViewWidthDp = 204;
+constexpr int kSpacingBetweenIconsAndLabelDp = 15;
+constexpr int kIconTopSpacingDp = 20;
+
+}  // namespace
+
+LoginAuthFactorsView::LoginAuthFactorsView() {
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
+  SetBorder(views::CreateEmptyBorder(kIconTopSpacingDp, 0, 0, 0));
+
+  auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::Orientation::kVertical, gfx::Insets(),
+      kSpacingBetweenIconsAndLabelDp));
+  layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kCenter);
+
+  icon_ = AddChildView(std::make_unique<AuthIconView>());
+
+  label_ = AddChildView(std::make_unique<views::Label>());
+  label_->SetSubpixelRenderingEnabled(false);
+  label_->SetAutoColorReadabilityEnabled(false);
+  label_->SetEnabledColor(AshColorProvider::Get()->GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kTextColorSecondary));
+  label_->SetMultiLine(true);
+}
+
+LoginAuthFactorsView::~LoginAuthFactorsView() = default;
+
+void LoginAuthFactorsView::AddAuthFactor(
+    std::unique_ptr<AuthFactorModel> auth_factor) {
+  auth_factors_.push_back(std::move(auth_factor));
+  UpdateState();
+}
+
+void LoginAuthFactorsView::UpdateState() {
+  if (auth_factors_.empty())
+    return;
+  // TODO(crbug.com/1233614) Add support for multiple auth factors.
+  auto& auth_factor = auth_factors_[0];
+
+  auth_factor->UpdateIcon(icon_);
+  label_->SetText(auth_factor->GetLabel());
+}
+
+// views::View:
+gfx::Size LoginAuthFactorsView::CalculatePreferredSize() const {
+  gfx::Size size = views::View::CalculatePreferredSize();
+  size.set_width(kAuthFactorsViewWidthDp);
+  return size;
+}
+
+}  // namespace ash
diff --git a/ash/login/ui/login_auth_factors_view.h b/ash/login/ui/login_auth_factors_view.h
new file mode 100644
index 0000000..92568885
--- /dev/null
+++ b/ash/login/ui/login_auth_factors_view.h
@@ -0,0 +1,54 @@
+// 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 ASH_LOGIN_UI_LOGIN_AUTH_FACTORS_VIEW_H_
+#define ASH_LOGIN_UI_LOGIN_AUTH_FACTORS_VIEW_H_
+
+#include "ui/views/view.h"
+
+namespace views {
+class Label;
+}  // namespace views
+
+namespace ash {
+
+class AuthIconView;
+class AuthFactorModel;
+
+// A view that displays a collection of auth factors to be shown on the lock and
+// login screens.
+class LoginAuthFactorsView : public views::View {
+ public:
+  LoginAuthFactorsView();
+  LoginAuthFactorsView(LoginAuthFactorsView&) = delete;
+  LoginAuthFactorsView& operator=(LoginAuthFactorsView&) = delete;
+  ~LoginAuthFactorsView() override;
+
+  // Add an auth factor to be displayed. Auth factors should be added in the
+  // order they should be displayed.
+  void AddAuthFactor(std::unique_ptr<AuthFactorModel> auth_factor);
+
+  // Recomputes the state and updates the label and icons. Should be called
+  // whenever any auth factor's state changes so that those changes can be
+  // reflected in the UI.
+  void UpdateState();
+
+  // views::View:
+  gfx::Size CalculatePreferredSize() const override;
+
+  // TODO(crbug.com/1233614): Many more methods will be added here to facilitate
+  // state management, especially after multiple auth factors have been
+  // implemented. See go/cros-smartlock-ui-revamp.
+
+ private:
+  // TODO(crbug.com/1233614): Replace |icon_| with a collection of icons and
+  // animate them with, e.g. an AnimatingLayoutManager.
+  AuthIconView* icon_;
+  views::Label* label_;
+  std::vector<std::unique_ptr<AuthFactorModel>> auth_factors_;
+};
+
+}  // namespace ash
+
+#endif  // ASH_LOGIN_UI_LOGIN_AUTH_FACTORS_VIEW_H_
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 3d82291..1311f89 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -8,11 +8,14 @@
 #include <memory>
 #include <utility>
 
+#include "ash/constants/ash_features.h"
 #include "ash/login/login_screen_controller.h"
 #include "ash/login/resources/grit/login_resources.h"
 #include "ash/login/ui/arrow_button_view.h"
+#include "ash/login/ui/fingerprint_auth_model.h"
 #include "ash/login/ui/horizontal_image_sequence_animation_decoder.h"
 #include "ash/login/ui/lock_screen.h"
+#include "ash/login/ui/login_auth_factors_view.h"
 #include "ash/login/ui/login_constants.h"
 #include "ash/login/ui/login_display_style.h"
 #include "ash/login/ui/login_password_view.h"
@@ -34,6 +37,7 @@
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/night_light/time_of_day.h"
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/i18n/time_formatting.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -217,6 +221,8 @@
 };
 
 // The label shown below the fingerprint icon.
+// TODO(crbug.com/1233614): Remove this class after the Smart Lock UI revamp is
+// complete.
 class FingerprintLabel : public views::Label {
  public:
   FingerprintLabel() {
@@ -393,6 +399,8 @@
 }  // namespace
 
 // Consists of fingerprint icon view and a label.
+// TODO(crbug.com/1233614): Remove this class after the Smart Lock UI revamp is
+// complete.
 class LoginAuthUserView::FingerprintView : public views::View {
  public:
   FingerprintView() {
@@ -997,6 +1005,10 @@
   return view_->challenge_response_view_->GetLabelForTesting();
 }
 
+LoginAuthFactorsView* LoginAuthUserView::TestApi::auth_factors_view() const {
+  return view_->auth_factors_view_;
+}
+
 bool LoginAuthUserView::TestApi::HasAuthMethod(AuthMethods auth_method) const {
   return view_->HasAuthMethod(auth_method);
 }
@@ -1107,8 +1119,18 @@
   auto locked_tpm_message_view = std::make_unique<LockedTpmMessageView>();
   locked_tpm_message_view_ = locked_tpm_message_view.get();
 
-  auto fingerprint_view = std::make_unique<FingerprintView>();
-  fingerprint_view_ = fingerprint_view.get();
+  bool smartLockUIRevampEnabled =
+      base::FeatureList::IsEnabled(ash::features::kSmartLockUIRevamp);
+  std::unique_ptr<FingerprintView> fingerprint_view;
+  std::unique_ptr<LoginAuthFactorsView> auth_factors_view;
+  if (smartLockUIRevampEnabled) {
+    auth_factors_view = std::make_unique<LoginAuthFactorsView>();
+    auth_factors_view_ = auth_factors_view.get();
+    auth_factors_view_->AddAuthFactor(std::make_unique<FingerprintAuthModel>());
+  } else {
+    fingerprint_view = std::make_unique<FingerprintView>();
+    fingerprint_view_ = fingerprint_view.get();
+  }
 
   auto challenge_response_view =
       std::make_unique<ChallengeResponseView>(base::BindRepeating(
@@ -1138,8 +1160,15 @@
       login_views_utils::WrapViewForPreferredSize(std::move(pin_input_view));
   auto wrapped_pin_password_toggle_view =
       login_views_utils::WrapViewForPreferredSize(std::move(toggle_container));
-  auto wrapped_fingerprint_view =
-      login_views_utils::WrapViewForPreferredSize(std::move(fingerprint_view));
+  std::unique_ptr<views::View> wrapped_fingerprint_view;
+  std::unique_ptr<views::View> wrapped_auth_factors_view;
+  if (smartLockUIRevampEnabled) {
+    wrapped_auth_factors_view = login_views_utils::WrapViewForPreferredSize(
+        std::move(auth_factors_view));
+  } else {
+    wrapped_fingerprint_view = login_views_utils::WrapViewForPreferredSize(
+        std::move(fingerprint_view));
+  }
   auto wrapped_challenge_response_view =
       login_views_utils::WrapViewForPreferredSize(
           std::move(challenge_response_view));
@@ -1164,8 +1193,15 @@
   views::View* wrapped_pin_view_ptr = AddChildView(std::move(wrapped_pin_view));
   views::View* wrapped_pin_password_toggle_view_ptr =
       AddChildView(std::move(wrapped_pin_password_toggle_view));
-  views::View* wrapped_fingerprint_view_ptr =
-      AddChildView(std::move(wrapped_fingerprint_view));
+  views::View* wrapped_fingerprint_view_ptr;
+  views::View* wrapped_auth_factors_view_ptr;
+  if (smartLockUIRevampEnabled) {
+    wrapped_auth_factors_view_ptr =
+        AddChildView(std::move(wrapped_auth_factors_view));
+  } else {
+    wrapped_fingerprint_view_ptr =
+        AddChildView(std::move(wrapped_fingerprint_view));
+  }
   views::View* wrapped_challenge_response_view_ptr =
       AddChildView(std::move(wrapped_challenge_response_view));
   views::View* wrapped_user_view_ptr =
@@ -1204,7 +1240,11 @@
   add_view(wrapped_padding_below_password_view_ptr);
   add_view(wrapped_pin_view_ptr);
   add_view(wrapped_pin_password_toggle_view_ptr);
-  add_view(wrapped_fingerprint_view_ptr);
+  if (smartLockUIRevampEnabled) {
+    add_view(wrapped_auth_factors_view_ptr);
+  } else {
+    add_view(wrapped_fingerprint_view_ptr);
+  }
   add_view(wrapped_challenge_response_view_ptr);
   add_padding(kDistanceFromPinKeyboardToBigUserViewBottomDp);
 
@@ -1287,8 +1327,10 @@
   pin_password_toggle_->SetVisible(current_state.has_toggle);
   pin_password_toggle_->SetText(GetPinPasswordToggleText());
 
-  fingerprint_view_->SetVisible(current_state.has_fingerprint);
-  fingerprint_view_->SetCanUsePin(HasAuthMethod(AUTH_PIN));
+  if (fingerprint_view_) {
+    fingerprint_view_->SetVisible(current_state.has_fingerprint);
+    fingerprint_view_->SetCanUsePin(HasAuthMethod(AUTH_PIN));
+  }
   challenge_response_view_->SetVisible(current_state.has_challenge_response);
 
   padding_below_user_view_->SetPreferredSize(GetPaddingBelowUserView());
@@ -1336,7 +1378,9 @@
   stop_animation(this);
   stop_animation(password_view_);
   stop_animation(pin_view_);
-  stop_animation(fingerprint_view_);
+  if (fingerprint_view_) {
+    stop_animation(fingerprint_view_);
+  }
   stop_animation(challenge_response_view_);
   stop_animation(pin_password_toggle_);
 
@@ -1466,7 +1510,8 @@
   ////////
   // Fade the fingerprint view if it is being hidden or shown.
 
-  if (previous_state_->has_fingerprint != current_state.has_fingerprint) {
+  if (fingerprint_view_ &&
+      previous_state_->has_fingerprint != current_state.has_fingerprint) {
     float opacity_start = 0, opacity_end = 1;
     if (!current_state.has_fingerprint)
       std::swap(opacity_start, opacity_end);
@@ -1520,10 +1565,16 @@
 }
 
 void LoginAuthUserView::SetFingerprintState(FingerprintState state) {
+  if (!fingerprint_view_)
+    return;
+
   fingerprint_view_->SetState(state);
 }
 
 void LoginAuthUserView::NotifyFingerprintAuthResult(bool success) {
+  if (!fingerprint_view_)
+    return;
+
   fingerprint_view_->NotifyFingerprintAuthResult(success);
 }
 
@@ -1765,8 +1816,7 @@
   // - Disabled message shown
   // - No password auth available
   if (HasAuthMethod(AUTH_CHALLENGE_RESPONSE) ||
-      HasAuthMethod(AUTH_ONLINE_SIGN_IN) ||
-      HasAuthMethod(AUTH_DISABLED) ||
+      HasAuthMethod(AUTH_ONLINE_SIGN_IN) || HasAuthMethod(AUTH_DISABLED) ||
       !HasAuthMethod(AUTH_PASSWORD)) {
     input_field_mode_ = InputFieldMode::NONE;
     return;
@@ -1842,7 +1892,7 @@
 
   if (state.has_pinpad)
     return SizeFromHeight(kDistanceBetweenPasswordFieldAndPinKeyboardDp);
-  if (state.has_fingerprint)
+  if (state.has_fingerprint || auth_factors_view_)
     return SizeFromHeight(kDistanceBetweenPasswordFieldAndFingerprintViewDp);
   if (state.has_challenge_response)
     return SizeFromHeight(kDistanceBetweenPwdFieldAndChallengeResponseViewDp);
diff --git a/ash/login/ui/login_auth_user_view.h b/ash/login/ui/login_auth_user_view.h
index 7aff83f..3ad8a01 100644
--- a/ash/login/ui/login_auth_user_view.h
+++ b/ash/login/ui/login_auth_user_view.h
@@ -28,6 +28,7 @@
 
 namespace ash {
 
+class LoginAuthFactorsView;
 class LoginPasswordView;
 class LoginPinView;
 class LoginPinInputView;
@@ -98,6 +99,7 @@
     views::View* disabled_auth_message() const;
     views::Button* challenge_response_button();
     views::Label* challenge_response_label();
+    LoginAuthFactorsView* auth_factors_view() const;
     bool HasAuthMethod(AuthMethods auth_method) const;
     const std::u16string& GetDisabledAuthMessageContent() const;
 
@@ -281,6 +283,7 @@
   views::LabelButton* online_sign_in_button_ = nullptr;
   DisabledAuthMessageView* disabled_auth_message_ = nullptr;
   FingerprintView* fingerprint_view_ = nullptr;
+  LoginAuthFactorsView* auth_factors_view_ = nullptr;
   ChallengeResponseView* challenge_response_view_ = nullptr;
   LockedTpmMessageView* locked_tpm_message_view_ = nullptr;
 
diff --git a/ash/login/ui/login_auth_user_view_unittest.cc b/ash/login/ui/login_auth_user_view_unittest.cc
index a591d96..b7135e3 100644
--- a/ash/login/ui/login_auth_user_view_unittest.cc
+++ b/ash/login/ui/login_auth_user_view_unittest.cc
@@ -507,6 +507,15 @@
   base::RunLoop().RunUntilIdle();
 }
 
+// The LoginAuthFactorsView is part of the Smart Lock UI Revamp, and should not
+// be shown unless the feature flag is enabled.
+TEST_P(LoginAuthUserViewUnittest,
+       AuthFactorsViewNotSetWithSmartLockFeatureDisabled) {
+  LoginAuthUserView::TestApi auth_test(view_);
+  auto* auth_factors_view = auth_test.auth_factors_view();
+  EXPECT_FALSE(auth_factors_view);
+}
+
 INSTANTIATE_TEST_SUITE_P(LoginAuthUserViewTests,
                          LoginAuthUserViewUnittest,
                          testing::Bool(),  // PIN autosubmit feature
diff --git a/ash/public/cpp/app_list/vector_icons/DIR_METADATA b/ash/public/cpp/app_list/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/ash/public/cpp/app_list/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/ash/public/cpp/assistant/DIR_METADATA b/ash/public/cpp/assistant/DIR_METADATA
index 5cf9e51..cfb0c371 100644
--- a/ash/public/cpp/assistant/DIR_METADATA
+++ b/ash/public/cpp/assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Shell>Assistant"
-}
+mixins: "//chromeos/assistant/COMMON_METADATA"
diff --git a/ash/public/cpp/holding_space/COMMON_METADATA b/ash/public/cpp/holding_space/COMMON_METADATA
new file mode 100644
index 0000000..982c76d
--- /dev/null
+++ b/ash/public/cpp/holding_space/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Shell>HoldingSpace"
+}
diff --git a/ash/public/cpp/holding_space/DIR_METADATA b/ash/public/cpp/holding_space/DIR_METADATA
index 982c76d..4820d9d 100644
--- a/ash/public/cpp/holding_space/DIR_METADATA
+++ b/ash/public/cpp/holding_space/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Shell>HoldingSpace"
-}
+mixins: "//ash/public/cpp/holding_space/COMMON_METADATA"
diff --git a/ash/public/cpp/toast_data.h b/ash/public/cpp/toast_data.h
index 3b9e234..7b0c1eb 100644
--- a/ash/public/cpp/toast_data.h
+++ b/ash/public/cpp/toast_data.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "ash/public/cpp/ash_public_export.h"
+#include "base/callback.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace ash {
@@ -31,6 +32,7 @@
   absl::optional<std::u16string> dismiss_text;
   bool visible_on_lock_screen;
   bool is_managed = false;
+  base::RepeatingClosure dismiss_callback;
 };
 
 }  // namespace ash
diff --git a/ash/public/cpp/wallpaper/DIR_METADATA b/ash/public/cpp/wallpaper/DIR_METADATA
index e242c729..f13868a 100644
--- a/ash/public/cpp/wallpaper/DIR_METADATA
+++ b/ash/public/cpp/wallpaper/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Systems>Wallpaper"
-}
+mixins: "//ash/wallpaper/COMMON_METADATA"
diff --git a/ash/quick_pair/COMMON_METADATA b/ash/quick_pair/COMMON_METADATA
new file mode 100644
index 0000000..4891ec87
--- /dev/null
+++ b/ash/quick_pair/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "OS>Systems>Multidevice>FastPair"
+}
diff --git a/ash/quick_pair/DIR_METADATA b/ash/quick_pair/DIR_METADATA
index 4891ec87..8ce78732 100644
--- a/ash/quick_pair/DIR_METADATA
+++ b/ash/quick_pair/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "OS>Systems>Multidevice>FastPair"
-}
+mixins: "//ash/quick_pair/COMMON_METADATA"
diff --git a/ash/resources/vector_icons/DIR_METADATA b/ash/resources/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/ash/resources/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/ash/services/quick_pair/DIR_METADATA b/ash/services/quick_pair/DIR_METADATA
index 4891ec87..8ce78732 100644
--- a/ash/services/quick_pair/DIR_METADATA
+++ b/ash/services/quick_pair/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "OS>Systems>Multidevice>FastPair"
-}
+mixins: "//ash/quick_pair/COMMON_METADATA"
diff --git a/ash/shortcut_viewer/vector_icons/DIR_METADATA b/ash/shortcut_viewer/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/ash/shortcut_viewer/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/ash/system/accessibility/DIR_METADATA b/ash/system/accessibility/DIR_METADATA
index 14320f50..79fdee1 100644
--- a/ash/system/accessibility/DIR_METADATA
+++ b/ash/system/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail {
   component: "OS>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/ash/system/holding_space/DIR_METADATA b/ash/system/holding_space/DIR_METADATA
new file mode 100644
index 0000000..4820d9d
--- /dev/null
+++ b/ash/system/holding_space/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//ash/public/cpp/holding_space/COMMON_METADATA"
diff --git a/ash/system/message_center/DIR_METADATA b/ash/system/message_center/DIR_METADATA
index 5a353a5..5cee1e93 100644
--- a/ash/system/message_center/DIR_METADATA
+++ b/ash/system/message_center/DIR_METADATA
@@ -1,3 +1,4 @@
+mixins: "//ui/message_center/COMMON_METADATA"
 monorail {
   component: "UI>Shell>Notifications"
 }
diff --git a/ash/system/phonehub/DIR_METADATA b/ash/system/phonehub/DIR_METADATA
new file mode 100644
index 0000000..fb34eb9
--- /dev/null
+++ b/ash/system/phonehub/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chromeos/components/phonehub/COMMON_METADATA"
diff --git a/ash/system/toast/toast_manager_impl.cc b/ash/system/toast/toast_manager_impl.cc
index cd9cd17..b918bad7 100644
--- a/ash/system/toast/toast_manager_impl.cc
+++ b/ash/system/toast/toast_manager_impl.cc
@@ -93,7 +93,7 @@
   overlay_ = std::make_unique<ToastOverlay>(
       this, current_toast_data_->text, current_toast_data_->dismiss_text,
       current_toast_data_->visible_on_lock_screen && locked_,
-      current_toast_data_->is_managed);
+      current_toast_data_->is_managed, current_toast_data_->dismiss_callback);
   overlay_->Show(true);
 
   if (current_toast_data_->duration_ms != ToastData::kInfiniteDuration) {
diff --git a/ash/system/toast/toast_overlay.cc b/ash/system/toast/toast_overlay.cc
index cc61bae..e333d584 100644
--- a/ash/system/toast/toast_overlay.cc
+++ b/ash/system/toast/toast_overlay.cc
@@ -176,7 +176,7 @@
 class ToastOverlayView : public views::View {
  public:
   // This object is not owned by the views hierarchy or by the widget.
-  ToastOverlayView(ToastOverlay* overlay,
+  ToastOverlayView(base::RepeatingClosure dismiss_callback,
                    const std::u16string& text,
                    const absl::optional<std::u16string>& dismiss_text,
                    const bool is_managed) {
@@ -206,8 +206,7 @@
       return;
 
     button_ = AddChildView(std::make_unique<ToastOverlayButton>(
-        base::BindRepeating(&ToastOverlay::Show, base::Unretained(overlay),
-                            false),
+        std::move(dismiss_callback),
         dismiss_text.value().empty()
             ? l10n_util::GetStringUTF16(IDS_ASH_TOAST_DISMISS_BUTTON)
             : dismiss_text.value()));
@@ -263,13 +262,20 @@
                            const std::u16string& text,
                            absl::optional<std::u16string> dismiss_text,
                            bool show_on_lock_screen,
-                           bool is_managed)
+                           bool is_managed,
+                           base::RepeatingClosure dismiss_callback)
     : delegate_(delegate),
       text_(text),
       dismiss_text_(dismiss_text),
       overlay_widget_(new views::Widget),
-      overlay_view_(new ToastOverlayView(this, text, dismiss_text, is_managed)),
+      overlay_view_(new ToastOverlayView(
+          base::BindRepeating(&ToastOverlay::OnButtonClicked,
+                              base::Unretained(this)),
+          text,
+          dismiss_text,
+          is_managed)),
       display_observer_(std::make_unique<ToastDisplayObserver>(this)),
+      dismiss_callback_(std::move(dismiss_callback)),
       widget_size_(overlay_view_->GetPreferredSize()) {
   views::Widget::InitParams params;
   params.type = views::Widget::InitParams::TYPE_POPUP;
@@ -354,6 +360,13 @@
   return bounds;
 }
 
+void ToastOverlay::OnButtonClicked() {
+  if (dismiss_callback_) {
+    dismiss_callback_.Run();
+  }
+  Show(/*visible=*/false);
+}
+
 void ToastOverlay::OnImplicitAnimationsScheduled() {}
 
 void ToastOverlay::OnImplicitAnimationsCompleted() {
diff --git a/ash/system/toast/toast_overlay.h b/ash/system/toast/toast_overlay.h
index 2fa7d30..656ec82e 100644
--- a/ash/system/toast/toast_overlay.h
+++ b/ash/system/toast/toast_overlay.h
@@ -10,6 +10,7 @@
 
 #include "ash/ash_export.h"
 #include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
+#include "base/callback.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/events/event.h"
@@ -46,12 +47,14 @@
   // |dismiss_text| is the message for the button to dismiss the toast message.
   // If |dismiss_text| is null, no dismiss button will be shown. If
   // |dismiss_text| has a value but the string is empty, the default text is
-  // used. If |is_managed| is true, a managed icon will be added to the toast.
+  // used. |dismiss_callback| will be called when the button is pressed.
+  // If |is_managed| is true, a managed icon will be added to the toast.
   ToastOverlay(Delegate* delegate,
                const std::u16string& text,
                absl::optional<std::u16string> dismiss_text,
                bool show_on_lock_screen,
-               bool is_managed);
+               bool is_managed,
+               base::RepeatingClosure dismiss_callback);
 
   ToastOverlay(const ToastOverlay&) = delete;
   ToastOverlay& operator=(const ToastOverlay&) = delete;
@@ -72,6 +75,9 @@
   // Returns the current bounds of the overlay, which is based on visibility.
   gfx::Rect CalculateOverlayBounds();
 
+  // Executed the callback and closes the toast.
+  void OnButtonClicked();
+
   // ui::ImplicitAnimationObserver:
   void OnImplicitAnimationsScheduled() override;
   void OnImplicitAnimationsCompleted() override;
@@ -89,6 +95,7 @@
   std::unique_ptr<views::Widget> overlay_widget_;
   std::unique_ptr<ToastOverlayView> overlay_view_;
   std::unique_ptr<ToastDisplayObserver> display_observer_;
+  base::RepeatingClosure dismiss_callback_;
 
   gfx::Size widget_size_;
 };
diff --git a/ash/wallpaper/COMMON_METADATA b/ash/wallpaper/COMMON_METADATA
new file mode 100644
index 0000000..e242c729
--- /dev/null
+++ b/ash/wallpaper/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Systems>Wallpaper"
+}
diff --git a/ash/wallpaper/DIR_METADATA b/ash/wallpaper/DIR_METADATA
index e242c729..f13868a 100644
--- a/ash/wallpaper/DIR_METADATA
+++ b/ash/wallpaper/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Systems>Wallpaper"
-}
+mixins: "//ash/wallpaper/COMMON_METADATA"
diff --git a/ash/webui/BUILD.gn b/ash/webui/BUILD.gn
index e2ad9f3..995ff71 100644
--- a/ash/webui/BUILD.gn
+++ b/ash/webui/BUILD.gn
@@ -20,6 +20,7 @@
     "//ash/webui/common/backend:unit_tests",
     "//ash/webui/diagnostics_ui/backend:unit_tests",
     "//ash/webui/diagnostics_ui/mojom:unit_tests",
+    "//ash/webui/file_manager:unit_tests",
     "//ash/webui/help_app_ui:unit_tests",
     "//ash/webui/scanning:unit_tests",
     "//ash/webui/shimless_rma/backend:unit_tests",
diff --git a/ash/webui/diagnostics_ui/resources/BUILD.gn b/ash/webui/diagnostics_ui/resources/BUILD.gn
index f926e08d..bfe5de89 100644
--- a/ash/webui/diagnostics_ui/resources/BUILD.gn
+++ b/ash/webui/diagnostics_ui/resources/BUILD.gn
@@ -32,6 +32,7 @@
     ":input_card",
     ":input_list",
     ":ip_config_info_drawer",
+    ":keyboard_tester",
     ":memory_card",
     ":mojo_interface_provider",
     ":mojo_utils",
@@ -208,6 +209,7 @@
 js_library("input_list") {
   deps = [
     ":input_card",
+    ":keyboard_tester",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
 }
@@ -225,6 +227,13 @@
   ]
 }
 
+js_library("keyboard_tester") {
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
+  ]
+}
+
 js_library("memory_card") {
   deps = [
     ":data_point",
@@ -407,6 +416,7 @@
     "input_card.js",
     "input_list.js",
     "ip_config_info_drawer.js",
+    "keyboard_tester.js",
     "memory_card.js",
     "network_card.js",
     "network_info.js",
diff --git a/ash/webui/diagnostics_ui/resources/diagnostics_app_resources.grd b/ash/webui/diagnostics_ui/resources/diagnostics_app_resources.grd
index 79bcf94..efc1a2e 100644
--- a/ash/webui/diagnostics_ui/resources/diagnostics_app_resources.grd
+++ b/ash/webui/diagnostics_ui/resources/diagnostics_app_resources.grd
@@ -37,6 +37,7 @@
       <include name="IDR_DIAGNOSTICS_INPUT_DATA_PROVIDER_MOJO_LITE_JS" file="${root_gen_dir}/ash/webui/diagnostics_ui/mojom/input_data_provider.mojom-lite.js" resource_path="input_data_provider.mojom-lite.js" use_base_dir="false" type="BINDATA" />
       <include name="IDR_DIAGNOSTICS_INPUT_LIST_JS" file="${root_gen_dir}/ash/webui/diagnostics_ui/resources/input_list.js" resource_path="input_list.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_DIAGNOSTICS_IP_CONFIG_INFO_DRAWER_JS" file="${root_gen_dir}/ash/webui/diagnostics_ui/resources/ip_config_info_drawer.js" resource_path="ip_config_info_drawer.js" use_base_dir="false" type="BINDATA"/>
+      <include name="IDR_DIAGNOSTICS_KEYBOARD_TESTER_JS" file="${root_gen_dir}/ash/webui/diagnostics_ui/resources/keyboard_tester.js" resource_path="keyboard_tester.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_DIAGNOSTICS_MEMORY_CARD_JS" file="${root_gen_dir}/ash/webui/diagnostics_ui/resources/memory_card.js" resource_path="memory_card.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_DIAGNOSTICS_MOJO_INTERFACE_PROVIDER_JS" file="mojo_interface_provider.js" type="BINDATA"/>
       <include name="IDR_DIAGNOSTICS_MOJO_UTILS_JS" file="mojo_utils.js" type="BINDATA"/>
diff --git a/ash/webui/diagnostics_ui/resources/input_list.html b/ash/webui/diagnostics_ui/resources/input_list.html
index b412913..826b0c5 100644
--- a/ash/webui/diagnostics_ui/resources/input_list.html
+++ b/ash/webui/diagnostics_ui/resources/input_list.html
@@ -9,7 +9,8 @@
 <div id="inputListContainer">
   <div class="diagnostics-cards-container">
     <div class="card-width">
-      <input-card device-type="keyboard" devices="[[keyboards_]]">
+      <input-card device-type="keyboard" devices="[[keyboards_]]"
+          on-test-button-click="handleKeyboardTestButtonClick_">
         <div slot="title">[[i18n('inputCategoryKeyboard')]]</div>
       </input-card>
       <input-card device-type="touchpad" devices="[[touchpads_]]">
diff --git a/ash/webui/diagnostics_ui/resources/input_list.js b/ash/webui/diagnostics_ui/resources/input_list.js
index 9c1ce75..a87e4324 100644
--- a/ash/webui/diagnostics_ui/resources/input_list.js
+++ b/ash/webui/diagnostics_ui/resources/input_list.js
@@ -4,7 +4,9 @@
 
 import './diagnostics_shared_css.js';
 import './input_card.js';
+import './keyboard_tester.js';
 
+import {assert} from 'chrome://resources/js/assert.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';
 
@@ -29,6 +31,9 @@
   /** @private {?ConnectedDevicesObserverReceiver} */
   connectedDevicesObserverReceiver_: null,
 
+  /** @private {?KeyboardTesterElement} */
+  keyboardTester_: null,
+
   properties: {
     /** @private {!Array<!KeyboardInfo>} */
     keyboards_: {
@@ -126,4 +131,19 @@
     this.removeDeviceById_('touchpads_', id);
     this.removeDeviceById_('touchscreens_', id);
   },
+
+  /**
+   * @param {!CustomEvent} e
+   * @private
+   */
+  handleKeyboardTestButtonClick_(e) {
+    if (!this.keyboardTester_) {
+      this.keyboardTester_ = /** @type {!KeyboardTesterElement} */ (
+          document.createElement('keyboard-tester'));
+      this.root.appendChild(this.keyboardTester_);
+    }
+    this.keyboardTester_.keyboard = assert(
+        this.keyboards_.find((keyboard) => keyboard.id === e.detail.evdevId));
+    this.keyboardTester_.show();
+  },
 });
diff --git a/ash/webui/diagnostics_ui/resources/keyboard_tester.html b/ash/webui/diagnostics_ui/resources/keyboard_tester.html
new file mode 100644
index 0000000..e323ede1
--- /dev/null
+++ b/ash/webui/diagnostics_ui/resources/keyboard_tester.html
@@ -0,0 +1,11 @@
+<cr-dialog id="dialog" show-close-button>
+  <div slot="title">Keyboard tester</div>
+  <div slot="body">
+    <p>Physical layout: [[keyboard.physicalLayout]]</p>
+    <p>Mechanical layout: [[keyboard.mechanicalLayout]]</p>
+    <p>Number pad presence: [[keyboard.numberPadPresent]]</p>
+    <template is="dom-if" if="[[keyboard.hasAssistantKey]]">
+      <p>Has Assistant key</p>
+    </template>
+  </div>
+</cr-dialog>
diff --git a/ash/webui/diagnostics_ui/resources/keyboard_tester.js b/ash/webui/diagnostics_ui/resources/keyboard_tester.js
new file mode 100644
index 0000000..1dab25c
--- /dev/null
+++ b/ash/webui/diagnostics_ui/resources/keyboard_tester.js
@@ -0,0 +1,41 @@
+// 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/cr_elements/cr_dialog/cr_dialog.m.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {KeyboardInfo} from './diagnostics_types.js'
+
+/**
+ * @fileoverview
+ * 'keyboard-tester' displays a tester UI for a keyboard.
+ */
+
+Polymer({
+  is: 'keyboard-tester',
+
+  _template: html`{__html_template__}`,
+
+  properties: {
+    /**
+     * The keyboard being tested, or null if none is being tested at the moment.
+     * @type {?KeyboardInfo}
+     */
+    keyboard: KeyboardInfo,
+  },
+
+  /** Shows the tester's dialog. */
+  show() {
+    this.$.dialog.showModal();
+  },
+
+  /**
+   * Returns whether the tester is currently open.
+   * @return {boolean}
+   */
+  isOpen() {
+    return this.$.dialog.open;
+  },
+});
diff --git a/ash/webui/file_manager/BUILD.gn b/ash/webui/file_manager/BUILD.gn
index 89e0027..89b25f8d 100644
--- a/ash/webui/file_manager/BUILD.gn
+++ b/ash/webui/file_manager/BUILD.gn
@@ -18,6 +18,8 @@
     "file_manager_ui.cc",
     "file_manager_ui.h",
     "file_manager_ui_delegate.h",
+    "resource_loader.cc",
+    "resource_loader.h",
     "url_constants.cc",
     "url_constants.h",
   ]
@@ -33,3 +35,14 @@
     "//ui/web_dialogs",
   ]
 }
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [ "resource_loader_unittest.cc" ]
+
+  deps = [
+    ":file_manager_ui",
+    "//content/test:test_support",
+  ]
+}
diff --git a/ash/webui/file_manager/DIR_METADATA b/ash/webui/file_manager/DIR_METADATA
index 5b8d7cd..e9400b87 100644
--- a/ash/webui/file_manager/DIR_METADATA
+++ b/ash/webui/file_manager/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>FileManager"
-}
+mixins: "//ui/file_manager/COMMON_METADATA"
diff --git a/ash/webui/file_manager/file_manager_ui.cc b/ash/webui/file_manager/file_manager_ui.cc
index 7e14b61..bb7e48aa 100644
--- a/ash/webui/file_manager/file_manager_ui.cc
+++ b/ash/webui/file_manager/file_manager_ui.cc
@@ -5,6 +5,7 @@
 #include "ash/webui/file_manager/file_manager_ui.h"
 
 #include "ash/webui/file_manager/file_manager_page_handler.h"
+#include "ash/webui/file_manager/resource_loader.h"
 #include "ash/webui/file_manager/resources/grit/file_manager_swa_resources.h"
 #include "ash/webui/file_manager/resources/grit/file_manager_swa_resources_map.h"
 #include "ash/webui/file_manager/url_constants.h"
@@ -21,21 +22,6 @@
 namespace ash {
 namespace file_manager {
 
-void AddFilesAppResources(content::WebUIDataSource* source,
-                          const webui::ResourcePath* entries,
-                          size_t size) {
-  for (size_t i = 0; i < size; ++i) {
-    std::string path(entries[i].path);
-    // Only load resources for Files app.
-    if (base::StartsWith(path, "file_manager/")) {
-      // Files app UI has all paths relative to //ui/file_manager/file_manager/
-      // so we remove the leading file_manager/ to match the existing paths.
-      base::ReplaceFirstSubstringAfterOffset(&path, 0, "file_manager/", "");
-      source->AddResourcePath(path, entries[i].id);
-    }
-  }
-}
-
 FileManagerUI::FileManagerUI(content::WebUI* web_ui,
                              std::unique_ptr<FileManagerUIDelegate> delegate)
     : MojoWebDialogUI(web_ui), delegate_(std::move(delegate)) {
diff --git a/ash/webui/file_manager/resource_loader.cc b/ash/webui/file_manager/resource_loader.cc
new file mode 100644
index 0000000..3633a3f
--- /dev/null
+++ b/ash/webui/file_manager/resource_loader.cc
@@ -0,0 +1,29 @@
+// 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 "ash/webui/file_manager/resource_loader.h"
+
+#include "base/strings/string_util.h"
+
+namespace ash {
+namespace file_manager {
+
+void AddFilesAppResources(content::WebUIDataSource* source,
+                          const webui::ResourcePath* entries,
+                          size_t size) {
+  for (size_t i = 0; i < size; ++i) {
+    std::string path(entries[i].path);
+    // Only load resources for Files app.
+    if (base::StartsWith(path, "file_manager/") &&
+        path.find("sandboxed/") == std::string::npos) {
+      // Files app UI has all paths relative to //ui/file_manager/file_manager/
+      // so we remove the leading file_manager/ to match the existing paths.
+      base::ReplaceFirstSubstringAfterOffset(&path, 0, "file_manager/", "");
+      source->AddResourcePath(path, entries[i].id);
+    }
+  }
+}
+
+}  // namespace file_manager
+}  // namespace ash
diff --git a/ash/webui/file_manager/resource_loader.h b/ash/webui/file_manager/resource_loader.h
new file mode 100644
index 0000000..d7a2a407
--- /dev/null
+++ b/ash/webui/file_manager/resource_loader.h
@@ -0,0 +1,23 @@
+// 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 ASH_WEBUI_FILE_MANAGER_RESOURCE_LOADER_H_
+#define ASH_WEBUI_FILE_MANAGER_RESOURCE_LOADER_H_
+
+#include <stddef.h>
+
+#include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/webui/resource_path.h"
+
+namespace ash {
+namespace file_manager {
+
+void AddFilesAppResources(content::WebUIDataSource* source,
+                          const webui::ResourcePath* entries,
+                          size_t size);
+
+}  // namespace file_manager
+}  // namespace ash
+
+#endif  // ASH_WEBUI_FILE_MANAGER_RESOURCE_LOADER_H_
diff --git a/ash/webui/file_manager/resource_loader_unittest.cc b/ash/webui/file_manager/resource_loader_unittest.cc
new file mode 100644
index 0000000..e1ae2895
--- /dev/null
+++ b/ash/webui/file_manager/resource_loader_unittest.cc
@@ -0,0 +1,53 @@
+// 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 "ash/webui/file_manager/resource_loader.h"
+
+#include "base/cxx17_backports.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_web_ui_data_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/webui/resource_path.h"
+
+namespace ash {
+namespace file_manager {
+
+class ResourceLoaderTest : public testing::Test {
+ public:
+  ResourceLoaderTest() = default;
+
+  content::TestWebUIDataSource* source() { return source_.get(); }
+
+ private:
+  void SetUp() override {
+    source_ = content::TestWebUIDataSource::Create("test-file-manager-host");
+  }
+
+  content::BrowserTaskEnvironment task_environment_;
+  std::unique_ptr<content::TestWebUIDataSource> source_;
+};
+
+TEST_F(ResourceLoaderTest, AddFilesAppResources) {
+  const webui::ResourcePath kTestResources[] = {
+      {"file_manager/images/icon192.png", 8},
+      {"file_manager_fakes.js", 9},
+      {"file_manager/sandboxed_files_img_content.css", 10},
+      {"file_manager/sandboxed/files_img_content.css", 11},
+  };
+
+  const size_t kTestResourcesSize = base::size(kTestResources);
+
+  AddFilesAppResources(source()->GetWebUIDataSource(), kTestResources,
+                       kTestResourcesSize);
+
+  EXPECT_EQ(8, source()->PathToIdrOrDefault("images/icon192.png"));
+  EXPECT_EQ(-1, source()->PathToIdrOrDefault("file_manager_fakes.js"));
+  EXPECT_EQ(10,
+            source()->PathToIdrOrDefault("sandboxed_files_img_content.css"));
+  EXPECT_EQ(-1,
+            source()->PathToIdrOrDefault("sandboxed/files_img_content.css"));
+}
+
+}  // namespace file_manager
+}  // namespace ash
diff --git a/base/android/COMMON_METADATA b/base/android/COMMON_METADATA
new file mode 100644
index 0000000..7a2580a
--- /dev/null
+++ b/base/android/COMMON_METADATA
@@ -0,0 +1 @@
+os: ANDROID
diff --git a/base/android/DIR_METADATA b/base/android/DIR_METADATA
index 7a2580a..70d749fa 100644
--- a/base/android/DIR_METADATA
+++ b/base/android/DIR_METADATA
@@ -1 +1 @@
-os: ANDROID
+mixins: "//base/android/COMMON_METADATA"
diff --git a/base/fuchsia/DIR_METADATA b/base/fuchsia/DIR_METADATA
index d537e1b..9fa1ad6 100644
--- a/base/fuchsia/DIR_METADATA
+++ b/base/fuchsia/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Fuchsia"
-}
-team_email: "cr-fuchsia@chromium.org"
+mixins: "//build/fuchsia/COMMON_METADATA"
 os: FUCHSIA
diff --git a/base/metrics/COMMON_METADATA b/base/metrics/COMMON_METADATA
new file mode 100644
index 0000000..540f41c
--- /dev/null
+++ b/base/metrics/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Metrics"
+}
diff --git a/base/metrics/DIR_METADATA b/base/metrics/DIR_METADATA
index 540f41c..e99cb759 100644
--- a/base/metrics/DIR_METADATA
+++ b/base/metrics/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Metrics"
-}
+mixins: "//base/metrics/COMMON_METADATA"
diff --git a/base/test/android/DIR_METADATA b/base/test/android/DIR_METADATA
index 5abea21..79f3e40 100644
--- a/base/test/android/DIR_METADATA
+++ b/base/test/android/DIR_METADATA
@@ -1,3 +1,4 @@
+mixins: "//base/android/COMMON_METADATA"
 monorail {
   component: "Test>Android"
 }
diff --git a/base/test/metrics/DIR_METADATA b/base/test/metrics/DIR_METADATA
index 540f41c..e99cb759 100644
--- a/base/test/metrics/DIR_METADATA
+++ b/base/test/metrics/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Metrics"
-}
+mixins: "//base/metrics/COMMON_METADATA"
diff --git a/build/android/COMMON_METADATA b/build/android/COMMON_METADATA
new file mode 100644
index 0000000..7a2580a
--- /dev/null
+++ b/build/android/COMMON_METADATA
@@ -0,0 +1 @@
+os: ANDROID
diff --git a/build/android/DIR_METADATA b/build/android/DIR_METADATA
index 7a2580a..cdc2d6fb 100644
--- a/build/android/DIR_METADATA
+++ b/build/android/DIR_METADATA
@@ -1 +1 @@
-os: ANDROID
+mixins: "//build/android/COMMON_METADATA"
diff --git a/build/config/android/DIR_METADATA b/build/config/android/DIR_METADATA
new file mode 100644
index 0000000..cdc2d6fb
--- /dev/null
+++ b/build/config/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//build/android/COMMON_METADATA"
diff --git a/build/config/fuchsia/DIR_METADATA b/build/config/fuchsia/DIR_METADATA
index 6d8f079..7dbde80 100644
--- a/build/config/fuchsia/DIR_METADATA
+++ b/build/config/fuchsia/DIR_METADATA
@@ -1,7 +1,3 @@
-monorail {
-  component: "Fuchsia"
-}
-
-team_email: "cr-fuchsia@chromium.org"
+mixins: "//build/fuchsia/COMMON_METADATA"
 
 os: FUCHSIA
diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn
index 2ed6149..6d63abf3 100644
--- a/build/config/ios/BUILD.gn
+++ b/build/config/ios/BUILD.gn
@@ -122,6 +122,20 @@
   asmflags = common_flags
   cflags = common_flags
   ldflags = common_flags
+
+  # TODO(crbug.com/1223481): Temporarily use a different
+  # libclang_rt.iossim.a for arm64 simulator builds. This can be
+  # removed when an arm64 slice is added to upstream Clang.
+  if (target_environment == "simulator" && current_cpu == "arm64") {
+    assert(xcode_version_int == 1300)
+    ldflags += [
+      "-lSystem",
+      rebase_path("$ios_toolchains_path/usr/lib/clang/13.0.0/" +
+                      "lib/darwin/libclang_rt.iossim.a",
+                  root_build_dir),
+      "-nodefaultlibs",
+    ]
+  }
 }
 
 config("ios_executable_flags") {
diff --git a/build/config/ios/swift_source_set.gni b/build/config/ios/swift_source_set.gni
new file mode 100644
index 0000000..0fa8bce
--- /dev/null
+++ b/build/config/ios/swift_source_set.gni
@@ -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.
+
+# Defines a template for Swift source files. The default module_name
+# of the target is the entire target label (without the leading //)
+# with all "/" and ":" replaced with "_".
+template("swift_source_set") {
+  _target_name = target_name
+  source_set(target_name) {
+    forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
+    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
+    if (!defined(module_name)) {
+      _target_label = get_label_info(":$_target_name", "label_no_toolchain")
+
+      # Strip the // from the beginning of the label.
+      _target_label = string_replace(_target_label, "//", "", 1)
+      module_name =
+          string_replace(string_replace(_target_label, "/", "_"), ":", "_")
+    }
+  }
+}
diff --git a/build/fuchsia/COMMON_METADATA b/build/fuchsia/COMMON_METADATA
new file mode 100644
index 0000000..fe8198a
--- /dev/null
+++ b/build/fuchsia/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Fuchsia"
+}
+
+team_email: "cr-fuchsia@chromium.org"
diff --git a/build/fuchsia/DIR_METADATA b/build/fuchsia/DIR_METADATA
index fe8198a..05b12cf 100644
--- a/build/fuchsia/DIR_METADATA
+++ b/build/fuchsia/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Fuchsia"
-}
+mixins: "//build/fuchsia/COMMON_METADATA"
 
-team_email: "cr-fuchsia@chromium.org"
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 6603ff7..66a3a2c 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-6.20210927.2.1
+6.20210928.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 6603ff7..66a3a2c 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-6.20210927.2.1
+6.20210928.0.1
diff --git a/build/toolchain/android/DIR_METADATA b/build/toolchain/android/DIR_METADATA
new file mode 100644
index 0000000..cdc2d6fb
--- /dev/null
+++ b/build/toolchain/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//build/android/COMMON_METADATA"
diff --git a/build/toolchain/apple/toolchain.gni b/build/toolchain/apple/toolchain.gni
index f914d8d4..0ad5014 100644
--- a/build/toolchain/apple/toolchain.gni
+++ b/build/toolchain/apple/toolchain.gni
@@ -546,7 +546,7 @@
           # order.
           "{{target_gen_dir}}/{{module_name}}.swiftmodule",
 
-          "{{target_gen_dir}}/{{module_name}}.h",
+          "{{target_gen_dir}}/{{target_output_name}}.h",
           "{{target_gen_dir}}/{{module_name}}.swiftdoc",
           "{{target_gen_dir}}/{{module_name}}.swiftsourceinfo",
         ]
@@ -572,7 +572,7 @@
             "$_env_vars $python_path $_tool -module-name {{module_name}} " +
             "-object-dir $_objects_dir " +
             "-module-path {{target_gen_dir}}/{{module_name}}.swiftmodule " +
-            "-header-path {{target_gen_dir}}/{{module_name}}.h " +
+            "-header-path {{target_gen_dir}}/{{target_output_name}}.h " +
             "-depfile {{target_out_dir}}/{{module_name}}.d " +
             "-depfile-filter {{target_gen_dir}}/{{module_name}}.swiftmodule " +
             "-bridge-header {{bridge_header}} $_extra_flags " +
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index 2563e867..8d6973cd0 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -82,12 +82,10 @@
 }
 
 // static
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    bool
-    PaintOpReader::ReadAndValidateOpHeader(const volatile void* input,
-                                           size_t input_size,
-                                           uint8_t* type,
-                                           uint32_t* skip) {
+bool PaintOpReader::ReadAndValidateOpHeader(const volatile void* input,
+                                            size_t input_size,
+                                            uint8_t* type,
+                                            uint32_t* skip) {
   if (input_size < 4)
     return false;
   uint32_t first_word = reinterpret_cast<const volatile uint32_t*>(input)[0];
@@ -104,9 +102,7 @@
 }
 
 template <typename T>
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadSimple(T* val) {
+void PaintOpReader::ReadSimple(T* val) {
   static_assert(base::is_trivially_copyable<T>::value,
                 "Not trivially copyable");
 
@@ -140,12 +136,10 @@
 }
 
 template <typename T>
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadFlattenable(
-        sk_sp<T>* val,
-        Factory<T> factory,
-        DeserializationError error_on_factory_failure) {
+void PaintOpReader::ReadFlattenable(
+    sk_sp<T>* val,
+    Factory<T> factory,
+    DeserializationError error_on_factory_failure) {
   size_t bytes = 0;
   ReadSize(&bytes);
   if (remaining_bytes_ < bytes)
@@ -165,9 +159,7 @@
   remaining_bytes_ -= bytes;
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadData(size_t bytes, void* data) {
+void PaintOpReader::ReadData(size_t bytes, void* data) {
   if (remaining_bytes_ < bytes)
     SetInvalid(DeserializationError::kInsufficientRemainingBytes_ReadData);
   if (!valid_)
@@ -180,66 +172,47 @@
   remaining_bytes_ -= bytes;
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadSize(size_t* size) {
+void PaintOpReader::ReadSize(size_t* size) {
   AlignMemory(8);
   uint64_t size64 = 0;
   ReadSimple(&size64);
   *size = size64;
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkScalar* data) {
+void PaintOpReader::Read(SkScalar* data) {
   ReadSimple(data);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
     void
     PaintOpReader::Read(uint8_t* data) {
   ReadSimple(data);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(uint32_t* data) {
+void PaintOpReader::Read(uint32_t* data) {
   ReadSimple(data);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(uint64_t* data) {
+void PaintOpReader::Read(uint64_t* data) {
   ReadSimple(data);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(int32_t* data) {
+void PaintOpReader::Read(int32_t* data) {
   ReadSimple(data);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkRect* rect) {
+void PaintOpReader::Read(SkRect* rect) {
   ReadSimple(rect);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkIRect* rect) {
+void PaintOpReader::Read(SkIRect* rect) {
   ReadSimple(rect);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkRRect* rect) {
+void PaintOpReader::Read(SkRRect* rect) {
   ReadSimple(rect);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkPath* path) {
+void PaintOpReader::Read(SkPath* path) {
   uint32_t path_id;
   ReadSimple(&path_id);
   if (!valid_)
@@ -293,9 +266,7 @@
   }
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(PaintFlags* flags) {
+void PaintOpReader::Read(PaintFlags* flags) {
   ReadSimple(&flags->color_);
   Read(&flags->width_);
   Read(&flags->miter_limit_);
@@ -327,9 +298,7 @@
   Read(&flags->shader_);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(PaintImage* image) {
+void PaintOpReader::Read(PaintImage* image) {
   uint8_t serialized_type_int = 0u;
   Read(&serialized_type_int);
   if (serialized_type_int >
@@ -489,9 +458,7 @@
   remaining_bytes_ -= bytes;
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(sk_sp<SkColorSpace>* color_space) {
+void PaintOpReader::Read(sk_sp<SkColorSpace>* color_space) {
   size_t size = 0;
   ReadSize(&size);
   if (remaining_bytes_ < size)
@@ -509,9 +476,7 @@
   remaining_bytes_ -= size;
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(sk_sp<SkTextBlob>* blob) {
+void PaintOpReader::Read(sk_sp<SkTextBlob>* blob) {
   AlignMemory(4);
   uint32_t blob_id = 0u;
   Read(&blob_id);
@@ -560,9 +525,7 @@
   remaining_bytes_ -= data_bytes;
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(sk_sp<PaintShader>* shader) {
+void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
   bool has_shader = false;
   ReadSimple(&has_shader);
   if (!has_shader) {
@@ -696,22 +659,16 @@
   }
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkMatrix* matrix) {
+void PaintOpReader::Read(SkMatrix* matrix) {
   ReadSimple(matrix);
   FixupMatrixPostSerialization(matrix);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkM44* matrix) {
+void PaintOpReader::Read(SkM44* matrix) {
   ReadSimple(matrix);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkSamplingOptions* sampling) {
+void PaintOpReader::Read(SkSamplingOptions* sampling) {
   bool useCubic;
   Read(&useCubic);
   if (useCubic) {
@@ -728,9 +685,7 @@
   }
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkYUVColorSpace* yuv_color_space) {
+void PaintOpReader::Read(SkYUVColorSpace* yuv_color_space) {
   uint32_t raw_yuv_color_space = kIdentity_SkYUVColorSpace;
   ReadSimple(&raw_yuv_color_space);
 
@@ -742,9 +697,7 @@
   *yuv_color_space = static_cast<SkYUVColorSpace>(raw_yuv_color_space);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkYUVAInfo::PlaneConfig* plane_config) {
+void PaintOpReader::Read(SkYUVAInfo::PlaneConfig* plane_config) {
   uint32_t raw_plane_config =
       static_cast<uint32_t>(SkYUVAInfo::PlaneConfig::kUnknown);
   ReadSimple(&raw_plane_config);
@@ -758,9 +711,7 @@
   *plane_config = static_cast<SkYUVAInfo::PlaneConfig>(raw_plane_config);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkYUVAInfo::Subsampling* subsampling) {
+void PaintOpReader::Read(SkYUVAInfo::Subsampling* subsampling) {
   uint32_t raw_subsampling =
       static_cast<uint32_t>(SkYUVAInfo::Subsampling::kUnknown);
   ReadSimple(&raw_subsampling);
@@ -773,18 +724,14 @@
   *subsampling = static_cast<SkYUVAInfo::Subsampling>(raw_subsampling);
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(gpu::Mailbox* mailbox) {
+void PaintOpReader::Read(gpu::Mailbox* mailbox) {
   ReadData(sizeof(gpu::Mailbox::Name), (*mailbox).name);
 }
 
 // Android does not use skottie. Remove below section to keep binary size to a
 // minimum.
 #if !defined(OS_ANDROID)
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(scoped_refptr<SkottieWrapper>* skottie) {
+void PaintOpReader::Read(scoped_refptr<SkottieWrapper>* skottie) {
   if (!options_.is_privileged) {
     valid_ = false;
     return;
@@ -855,9 +802,7 @@
   return extracted_memory;
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(sk_sp<PaintFilter>* filter) {
+void PaintOpReader::Read(sk_sp<PaintFilter>* filter) {
   PaintFilter::Type type;
   ReadEnum(&type);
   if (!valid_)
@@ -954,11 +899,9 @@
   }
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadColorFilterPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadColorFilterPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   sk_sp<SkColorFilter> color_filter;
   sk_sp<PaintFilter> input;
 
@@ -974,11 +917,9 @@
                                            base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadBlurPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadBlurPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkScalar sigma_x = 0.f;
   SkScalar sigma_y = 0.f;
   SkTileMode tile_mode;
@@ -995,11 +936,9 @@
                                     base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadDropShadowPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadDropShadowPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkScalar dx = 0.f;
   SkScalar dy = 0.f;
   SkScalar sigma_x = 0.f;
@@ -1023,11 +962,9 @@
                                           base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadMagnifierPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadMagnifierPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkRect src_rect = SkRect::MakeEmpty();
   SkScalar inset = 0.f;
   sk_sp<PaintFilter> input;
@@ -1041,11 +978,9 @@
                                          base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadComposePaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadComposePaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   sk_sp<PaintFilter> outer;
   sk_sp<PaintFilter> inner;
 
@@ -1056,11 +991,9 @@
   filter->reset(new ComposePaintFilter(std::move(outer), std::move(inner)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadAlphaThresholdPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadAlphaThresholdPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkRegion region;
   SkScalar inner_min = 0.f;
   SkScalar outer_max = 0.f;
@@ -1077,11 +1010,9 @@
       base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadXfermodePaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadXfermodePaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkBlendMode blend_mode;
   sk_sp<PaintFilter> background;
   sk_sp<PaintFilter> foreground;
@@ -1097,11 +1028,9 @@
                                         base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadArithmeticPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadArithmeticPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   float k1 = 0.f;
   float k2 = 0.f;
   float k3 = 0.f;
@@ -1123,11 +1052,9 @@
       std::move(foreground), base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadMatrixConvolutionPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadMatrixConvolutionPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkISize kernel_size = SkISize::MakeEmpty();
   SkScalar gain = 0.f;
   SkScalar bias = 0.f;
@@ -1163,11 +1090,9 @@
       convolve_alpha, std::move(input), base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadDisplacementMapEffectPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadDisplacementMapEffectPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkColorChannel channel_x;
   SkColorChannel channel_y;
   SkScalar scale = 0.f;
@@ -1187,11 +1112,9 @@
       base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadImagePaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadImagePaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   PaintImage image;
   Read(&image);
   if (!image) {
@@ -1212,11 +1135,9 @@
       new ImagePaintFilter(std::move(image), src_rect, dst_rect, quality));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadRecordPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadRecordPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   bool has_filter = false;
   ReadSimple(&has_filter);
   if (!has_filter) {
@@ -1250,11 +1171,9 @@
                                       raster_scale, scaling_behavior));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadMergePaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadMergePaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   size_t input_count = 0;
   ReadSize(&input_count);
 
@@ -1276,11 +1195,9 @@
                                      base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadMorphologyPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadMorphologyPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   MorphologyPaintFilter::MorphType morph_type;
   float radius_x = 0;
   float radius_y = 0;
@@ -1296,11 +1213,9 @@
                                           base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadOffsetPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadOffsetPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkScalar dx = 0.f;
   SkScalar dy = 0.f;
   sk_sp<PaintFilter> input;
@@ -1314,11 +1229,9 @@
                                       base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadTilePaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadTilePaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkRect src = SkRect::MakeEmpty();
   SkRect dst = SkRect::MakeEmpty();
   sk_sp<PaintFilter> input;
@@ -1331,11 +1244,9 @@
   filter->reset(new TilePaintFilter(src, dst, std::move(input)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadTurbulencePaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadTurbulencePaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   TurbulencePaintFilter::TurbulenceType turbulence_type;
   SkScalar base_frequency_x = 0.f;
   SkScalar base_frequency_y = 0.f;
@@ -1356,11 +1267,9 @@
       &tile_size, base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadShaderPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadShaderPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   using Dither = SkImageFilters::Dither;
 
   sk_sp<PaintShader> shader;
@@ -1380,11 +1289,9 @@
                                       base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadMatrixPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadMatrixPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkMatrix matrix = SkMatrix::I();
   PaintFlags::FilterQuality filter_quality = PaintFlags::FilterQuality::kNone;
   sk_sp<PaintFilter> input;
@@ -1398,11 +1305,9 @@
       new MatrixPaintFilter(matrix, filter_quality, std::move(input)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadLightingDistantPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadLightingDistantPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   PaintFilter::LightingType lighting_type;
   SkPoint3 direction = SkPoint3::Make(0.f, 0.f, 0.f);
   SkColor light_color = SK_ColorBLACK;
@@ -1425,11 +1330,9 @@
       shininess, std::move(input), base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadLightingPointPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadLightingPointPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   PaintFilter::LightingType lighting_type;
   SkPoint3 location = SkPoint3::Make(0.f, 0.f, 0.f);
   SkColor light_color = SK_ColorBLACK;
@@ -1452,11 +1355,9 @@
       std::move(input), base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadLightingSpotPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadLightingSpotPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   PaintFilter::LightingType lighting_type;
   SkPoint3 location = SkPoint3::Make(0.f, 0.f, 0.f);
   SkPoint3 target = SkPoint3::Make(0.f, 0.f, 0.f);
@@ -1487,11 +1388,9 @@
       base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::ReadStretchPaintFilter(
-        sk_sp<PaintFilter>* filter,
-        const absl::optional<PaintFilter::CropRect>& crop_rect) {
+void PaintOpReader::ReadStretchPaintFilter(
+    sk_sp<PaintFilter>* filter,
+    const absl::optional<PaintFilter::CropRect>& crop_rect) {
   SkScalar stretch_x = 0.f;
   SkScalar stretch_y = 0.f;
   SkScalar width = 0.f;
@@ -1511,9 +1410,7 @@
                                        base::OptionalOrNullptr(crop_rect)));
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    size_t
-    PaintOpReader::Read(sk_sp<PaintRecord>* record) {
+size_t PaintOpReader::Read(sk_sp<PaintRecord>* record) {
   size_t size_bytes = 0;
   ReadSize(&size_bytes);
   AlignMemory(PaintOpBuffer::PaintOpAlign);
@@ -1544,9 +1441,7 @@
   return size_bytes;
 }
 
-NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-    void
-    PaintOpReader::Read(SkRegion* region) {
+void PaintOpReader::Read(SkRegion* region) {
   size_t region_bytes = 0;
   ReadSize(&region_bytes);
   if (region_bytes == 0)
diff --git a/cc/paint/paint_op_reader.h b/cc/paint/paint_op_reader.h
index c0748bc..60be547 100644
--- a/cc/paint/paint_op_reader.h
+++ b/cc/paint/paint_op_reader.h
@@ -200,9 +200,7 @@
                        DeserializationError error_on_factory_failure);
 
   template <typename Enum, Enum kMaxValue = Enum::kMaxValue>
-  NOINLINE  // TODO(crbug.com/1245368): Remove when done investigating.
-      void
-      ReadEnum(Enum* enum_value) {
+  void ReadEnum(Enum* enum_value) {
     static_assert(static_cast<unsigned>(kMaxValue) <= 255,
                   "Max value must fit in uint8_t");
     uint8_t value = 0u;
diff --git a/chrome/android/COMMON_METADATA b/chrome/android/COMMON_METADATA
new file mode 100644
index 0000000..829bff2
--- /dev/null
+++ b/chrome/android/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Mobile"
+}
+team_email: "clank-dev@google.com"
+os: ANDROID
diff --git a/chrome/android/DIR_METADATA b/chrome/android/DIR_METADATA
index 829bff2..c69388e 100644
--- a/chrome/android/DIR_METADATA
+++ b/chrome/android/DIR_METADATA
@@ -1,5 +1 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-team_email: "clank-dev@google.com"
-os: ANDROID
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/chrome/android/features/autofill_assistant/DIR_METADATA b/chrome/android/features/autofill_assistant/DIR_METADATA
new file mode 100644
index 0000000..a5aa36b6
--- /dev/null
+++ b/chrome/android/features/autofill_assistant/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/autofill_assistant/COMMON_METADATA"
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantSnackbar.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantSnackbar.java
index ed8794c9..7726f1c8 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantSnackbar.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantSnackbar.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.autofill_assistant;
 
 import android.content.Context;
+import android.text.TextUtils;
 
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
@@ -27,7 +28,7 @@
 
     /** Shows the snackbar and reports the result to {@code callback}. */
     static SnackbarController show(Context context, SnackbarManager snackbarManager, int delayMs,
-            String message, Callback callback) {
+            String message, String undoString, Callback callback) {
         SnackbarController controller = new SnackbarController() {
             @Override
             public void onAction(Object actionData) {
@@ -39,10 +40,12 @@
                 callback.onDismiss(/* undo= */ false);
             }
         };
-        Snackbar snackBar =
-                Snackbar.make(message, controller, Snackbar.TYPE_ACTION,
-                                Snackbar.UMA_AUTOFILL_ASSISTANT_STOP_UNDO)
-                        .setAction(context.getString(R.string.undo), /* actionData= */ null);
+        Snackbar snackBar = Snackbar.make(message, controller, Snackbar.TYPE_ACTION,
+                                            Snackbar.UMA_AUTOFILL_ASSISTANT_STOP_UNDO)
+                                    .setAction(!TextUtils.isEmpty(undoString)
+                                                    ? undoString
+                                                    : context.getString(R.string.undo),
+                                            /* actionData= */ null);
         snackBar.setSingleLine(false);
         snackBar.setDuration(delayMs);
         snackbarManager.showSnackbar(snackBar);
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTextUtils.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTextUtils.java
index 735ef01..fd7fe51 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTextUtils.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantTextUtils.java
@@ -82,7 +82,6 @@
                 Log.d(TAG, "Mismatching span", e);
             }
         }
-
         view.setText(SpanApplier.applySpans(
                 text, successfulSpans.toArray(new SpanApplier.SpanInfo[successfulSpans.size()])));
         view.setMovementMethod(linkIds.isEmpty() ? null : LinkMovementMethod.getInstance());
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
index 54dd642..479dc93 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -324,9 +324,9 @@
     }
 
     @CalledByNative
-    private void showSnackbar(int delayMs, String message) {
+    private void showSnackbar(int delayMs, String message, String undoString) {
         mSnackbarController = AssistantSnackbar.show(mActivity, mActivity.getSnackbarManager(),
-                delayMs, message, this::safeSnackbarResult);
+                delayMs, message, undoString, this::safeSnackbarResult);
     }
 
     private void dismissSnackbar() {
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java
index 16d3b55..7de07e5 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/generic_ui/AssistantViewInteractions.java
@@ -98,14 +98,22 @@
     }
 
     @CalledByNative
+    // TODO(HLUCA): EditorTextField is VisibleForTesting. Find a solution that does not require to
+    // suppress this warning.
+    @SuppressWarnings("VisibleForTests")
     static boolean setViewText(View view, String text, AssistantGenericUiDelegate delegate) {
         if (view instanceof TextView) {
             AssistantTextUtils.applyVisualAppearanceTags(
                     (TextView) view, text, delegate::onTextLinkClicked);
             return true;
         } else if (view instanceof EditorTextField) {
-            AssistantTextUtils.applyVisualAppearanceTags(
-                    ((EditorTextField) view).getEditText(), text, delegate::onTextLinkClicked);
+            // If the current text is already up to date (e.g. because the model change was
+            // triggered by the user typing), don't set the text again. Setting the text causes the
+            // cursor to be moved to the start of the field which makes typing inconvenient.
+            if (!((EditorTextField) view).getEditText().getText().toString().equals(text)) {
+                AssistantTextUtils.applyVisualAppearanceTags(
+                        ((EditorTextField) view).getEditText(), text, delegate::onTextLinkClicked);
+            }
             return true;
         }
         return false;
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
index bcf32d5..70b3930 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantBottomsheetTest.java
@@ -405,6 +405,46 @@
 
     @Test
     @MediumTest
+    public void testCancelSnackbarWithStringUndo() {
+        ArrayList<ActionProto> list = new ArrayList<>();
+        list.add(ActionProto.newBuilder()
+                         .setPrompt(PromptProto.newBuilder().addChoices(Choice.newBuilder().setChip(
+                                 ChipProto.newBuilder()
+                                         .setType(ChipType.CANCEL_ACTION)
+                                         .setIcon(ChipIcon.ICON_CLEAR)
+                                         .setText("Cancel"))))
+                         .build());
+        AutofillAssistantTestScript script = new AutofillAssistantTestScript(
+                SupportedScriptProto.newBuilder()
+                        .setPath("bottomsheet_behaviour_target_website.html")
+                        .setPresentation(PresentationProto.newBuilder().setAutostart(true).setChip(
+                                ChipProto.newBuilder().setText("Autostart")))
+                        .build(),
+                list);
+
+        AutofillAssistantTestService testService = new AutofillAssistantTestService(
+                Collections.singletonList(script),
+                ClientSettingsProto.newBuilder()
+                        .setIntegrationTestSettings(
+                                ClientSettingsProto.IntegrationTestSettings.newBuilder()
+                                        .setDisableHeaderAnimations(true)
+                                        .setDisableCarouselChangeAnimations(true))
+                        .setDisplayStringsLocale("fr-FR")
+                        .addDisplayStrings(ClientSettingsProto.DisplayString.newBuilder()
+                                                   .setId(ClientSettingsProto.DisplayStringId.UNDO)
+                                                   .setValue("fr_undo"))
+                        .build());
+        startAutofillAssistant(mTestRule.getActivity(), testService);
+        waitUntilViewMatchesCondition(withText("Cancel"), isDisplayingAtLeast(90));
+        onView(withText("Cancel")).perform(click());
+        waitUntilViewMatchesCondition(withText("fr_undo"), isDisplayingAtLeast(90));
+        onView(withText("Cancel")).check(doesNotExist());
+        onView(withText("fr_undo")).perform(click());
+        waitUntilViewMatchesCondition(withText("Cancel"), isDisplayed());
+    }
+
+    @Test
+    @MediumTest
     public void testCancelSnackbarTimeout() {
         ClientSettingsProto clientSettings =
                 ClientSettingsProto.newBuilder().setCancelDelayMs(2000).build();
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java
index cb333197..6bc356ec 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantGenericUiTest.java
@@ -8,8 +8,9 @@
 import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
 
 import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.clearText;
 import static androidx.test.espresso.action.ViewActions.click;
-import static androidx.test.espresso.action.ViewActions.replaceText;
+import static androidx.test.espresso.action.ViewActions.typeText;
 import static androidx.test.espresso.assertion.PositionAssertions.isLeftAlignedWith;
 import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
@@ -1733,10 +1734,11 @@
         startAutofillAssistant(mTestRule.getActivity(), testService);
 
         waitUntilViewMatchesCondition(withContentDescription("Type here"), isCompletelyDisplayed());
-        onView(withContentDescription("Type here")).perform(replaceText("test 1"));
-        onView(withText("test 1")).check(matches(isDisplayed()));
-        onView(withContentDescription("Type here")).perform(replaceText("test 2"));
-        onView(withText("test 2")).check(matches(isDisplayed()));
+        onView(withContentDescription("Type here")).perform(typeText("test 1"));
+        waitUntilViewMatchesCondition(withText("test 1"), isDisplayed());
+        onView(withContentDescription("Type here")).perform(clearText());
+        onView(withContentDescription("Type here")).perform(typeText("test 2"));
+        waitUntilViewMatchesCondition(withText("test 2"), isDisplayed());
 
         int numNextActionsCalled = testService.getNextActionsCounter();
         onView(withContentDescription("Done")).perform(click());
diff --git a/chrome/android/feed/DIR_METADATA b/chrome/android/feed/DIR_METADATA
index 2ecd29e..aa7a67e 100644
--- a/chrome/android/feed/DIR_METADATA
+++ b/chrome/android/feed/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>ContentSuggestions>Feed"
-}
-team_email: "feed@chromium.org"
+mixins: "//components/feed/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/about_settings/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/COMMON_METADATA
new file mode 100644
index 0000000..8472c81
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Mobile>Settings"
+}
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/about_settings/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/DIR_METADATA
index 8472c81..88afdc9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/about_settings/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>Settings"
-}
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/about_settings/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/accessibility/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/accessibility/COMMON_METADATA
new file mode 100644
index 0000000..07b6999
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/accessibility/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Accessibility"
+}
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/accessibility/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/accessibility/DIR_METADATA
index 07b6999..5153b281 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/accessibility/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/accessibility/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Accessibility"
-}
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/accessibility/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/COMMON_METADATA
new file mode 100644
index 0000000..f3e3811
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Mobile>TabSwitcher"
+}
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA
index f3e3811..8a6516f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>TabSwitcher"
-}
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/DIR_METADATA
new file mode 100644
index 0000000..9421435f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ui/android/appmenu/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/DIR_METADATA
index dd20d9d..4931f239 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Flags"
-}
-team_email: "clank-modularization@chromium.org"
+mixins: "//chrome/browser/flags/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
index 60d8c56..e4c6644 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Upboarding>VideoTutorials"
-}
+mixins: "//chrome/browser/video_tutorials/COMMON_METADATA"
 team_email: "chrome-upboarding@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA
new file mode 100644
index 0000000..8dc897c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Autofill>UI"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/autofill/DIR_METADATA
index 8dc897c..cb63906 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/DIR_METADATA
@@ -1,3 +1,2 @@
-monorail {
-  component: "UI>Browser>Autofill>UI"
-}
+mixins: "//components/autofill/COMMON_METADATA"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/DIR_METADATA
index 2c84cedc..a5aa36b6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Autofill>Assistant"
-}
+mixins: "//components/autofill_assistant/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/background_sync/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
index 6bafd754..8a6d80f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>BackgroundSync"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//components/background_sync/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/DIR_METADATA
new file mode 100644
index 0000000..ff006ee1
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/background_task_scheduler/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/banners/DIR_METADATA
index 320129e..3d423c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/banners/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls"
-}
+mixins: "//chrome/browser/banners/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/COMMON_METADATA
new file mode 100644
index 0000000..8c227be
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Bookmarks"
+}
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA
index 8c227be..0488c08 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Bookmarks"
-}
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/bookmarks/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/COMMON_METADATA
new file mode 100644
index 0000000..cc86b52
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Mobile>CustomTabs"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
index cc86b52..a2406d8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>CustomTabs"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/browserservices/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/COMMON_METADATA
new file mode 100644
index 0000000..db7a5c4a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Privacy"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/DIR_METADATA
index db7a5c4a..7c759f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Privacy"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/browsing_data/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/component_updater/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/component_updater/DIR_METADATA
new file mode 100644
index 0000000..5eda730
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/component_updater/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/component_updater/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/compositor/COMMON_METADATA
new file mode 100644
index 0000000..193fd45
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Mobile>CompositedUI"
+}
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/compositor/DIR_METADATA
index 193fd45..0fd0ee3d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>CompositedUI"
-}
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/compositor/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/COMMON_METADATA
new file mode 100644
index 0000000..f0cdfe5
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Search>ContextualSearch"
+}
+team_email: "contextual-search-dev@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/DIR_METADATA
index f0cdfe5..519120a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Search>ContextualSearch"
-}
-team_email: "contextual-search-dev@chromium.org"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/content_capture/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/content_capture/DIR_METADATA
new file mode 100644
index 0000000..91c786d2
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/content_capture/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/content_capture/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/COMMON_METADATA
new file mode 100644
index 0000000..691cac2e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Mobile>ContextMenu"
+}
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
index 691cac2e..50d01c6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>ContextMenu"
-}
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/contextmenu/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/cryptids/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/cryptids/COMMON_METADATA
new file mode 100644
index 0000000..a91e22e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/cryptids/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Joy"
+}
+team_email: "chrome-creation@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/cryptids/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/cryptids/DIR_METADATA
index a91e22e..0e5474e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/cryptids/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/cryptids/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Joy"
-}
-team_email: "chrome-creation@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/cryptids/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/COMMON_METADATA
new file mode 100644
index 0000000..3ab39f0
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Mobile>CustomTabs"
+}
+team_email: "mobile-web-install-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
index 3ab39f0..4974e3d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>CustomTabs"
-}
-team_email: "mobile-web-install-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/customtabs/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/COMMON_METADATA
new file mode 100644
index 0000000..53108245
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Layout"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA
index 53108245..2064f2d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Layout"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/display_cutout/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/COMMON_METADATA
new file mode 100644
index 0000000..56645bbf
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>ReaderMode"
+}
+team_email: "dom-distiller-eng@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
index 56645bbf..c9eb2576 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>ReaderMode"
-}
-team_email: "dom-distiller-eng@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA
new file mode 100644
index 0000000..d0e05ef
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/android/explore_sites/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/COMMON_METADATA
new file mode 100644
index 0000000..c6b1123
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/COMMON_METADATA
@@ -0,0 +1 @@
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
index c6b1123..0408fc8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
@@ -1 +1 @@
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/gesturenav/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/infobar/COMMON_METADATA
new file mode 100644
index 0000000..cb4bf41
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Infobars"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DIR_METADATA
index cb4bf41..9913bdd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Infobars"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/infobar/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/installedapp/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/installedapp/COMMON_METADATA
new file mode 100644
index 0000000..e4c8934
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/installedapp/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Platform>Apps>AppLauncher>Install"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/installedapp/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/installedapp/DIR_METADATA
index e4c8934..545fdf75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/installedapp/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/installedapp/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>AppLauncher>Install"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/installedapp/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/messages/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/messages/DIR_METADATA
index b7d3703..df92a4dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/messages/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/messages/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>Messages"
-}
-team_email: "clank-app-team@google.com"
\ No newline at end of file
+mixins: "//components/messages/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA
new file mode 100644
index 0000000..6c2d418
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//ui/android/java/src/org/chromium/ui/modaldialog/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/net/nqe/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/net/nqe/DIR_METADATA
index 821c8e5..7832678 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/net/nqe/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/net/nqe/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Internals>Network>NetworkQuality"
-}
+mixins: "//net/nqe/COMMON_METADATA"
 team_email: "net-dev@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/notifications/COMMON_METADATA
new file mode 100644
index 0000000..a90e42f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Notifications"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/notifications/DIR_METADATA
index a90e42f..087037e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Notifications"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/notifications/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/ntp/COMMON_METADATA
new file mode 100644
index 0000000..685524d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>NewTabPage"
+}
+team_email: "ntp-dev@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/ntp/DIR_METADATA
index 685524d..30ceb7d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>NewTabPage"
-}
-team_email: "ntp-dev@chromium.org"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/ntp/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/COMMON_METADATA
new file mode 100644
index 0000000..f9c15e5
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Offline"
+}
+team_email: "offline-dev@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA
index f9c15e5..97d464e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Offline"
-}
-team_email: "offline-dev@chromium.org"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/offlinepages/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/omaha/COMMON_METADATA
new file mode 100644
index 0000000..d4c3202
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Installer"
+}
+team_email: "chrome-updates-dev@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/omaha/DIR_METADATA
index d4c3202..0e541ab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Installer"
-}
-team_email: "chrome-updates-dev@chromium.org"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/omaha/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/DIR_METADATA
index 2782d66..1148592 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/paint_preview/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>FreezeDriedTabs"
-}
+mixins: "//components/paint_preview/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/COMMON_METADATA
new file mode 100644
index 0000000..087172e2
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Bookmarks"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA
index 087172e2..b38f8e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Bookmarks"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/COMMON_METADATA
new file mode 100644
index 0000000..43d76b8
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Passwords"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA
index 43d76b8..10c6e39a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Passwords"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/payments/DIR_METADATA
new file mode 100644
index 0000000..9dddbb4
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/payments/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/COMMON_METADATA
new file mode 100644
index 0000000..4752c120
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Mobile>Settings"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA
index 4752c120..59aa64f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>Settings"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/push_messaging/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/push_messaging/DIR_METADATA
index b193ae0..a684b81 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/push_messaging/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/push_messaging/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>PushAPI"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//content/browser/push_messaging/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/COMMON_METADATA
new file mode 100644
index 0000000..55d46d6
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Mobile>SearchWidget"
+}
+team_email: "clank-app-team@google.com"
+os: ANDROID
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/DIR_METADATA
index 55d46d6..b4c6e69 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/DIR_METADATA
@@ -1,5 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>SearchWidget"
-}
-team_email: "clank-app-team@google.com"
-os: ANDROID
\ No newline at end of file
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/DIR_METADATA
index 2f1c93c..7a5b14a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/DIR_METADATA
@@ -1,3 +1,4 @@
+mixins: "//chrome/browser/safe_browsing/COMMON_METADATA"
 monorail {
   component: "Services>SafeBrowsing"
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/COMMON_METADATA
new file mode 100644
index 0000000..0adba788
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Mobile>SearchWidget"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/DIR_METADATA
index 0adba788..69533cf0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>SearchWidget"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/searchwidget/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/settings/COMMON_METADATA
new file mode 100644
index 0000000..8472c81
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Mobile>Settings"
+}
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/settings/DIR_METADATA
index 8472c81..971e38c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>Settings"
-}
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/settings/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/share/COMMON_METADATA
new file mode 100644
index 0000000..a9bcd18a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Mobile>Share"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/share/DIR_METADATA
index a9bcd18a..d4f5fbd1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>Share"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/share/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/sharing/DIR_METADATA
index 167ca6e..c1d4532f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Sharing"
-}
+mixins: "//chrome/browser/sharing/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/DIR_METADATA
new file mode 100644
index 0000000..ea846f1
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/browser_ui/site_settings/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/COMMON_METADATA
new file mode 100644
index 0000000..cbcab5d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Mobile>StatusIndicator"
+}
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA
index cbcab5d..3a3f2cc3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>StatusIndicator"
-}
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/status_indicator/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/sync/DIR_METADATA
index 1a6d7ee6..4a58e65 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Services>Sync"
-}
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/COMMON_METADATA
new file mode 100644
index 0000000..c6b1123
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/COMMON_METADATA
@@ -0,0 +1 @@
+team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA
index c6b1123..e60ac4f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA
@@ -1 +1 @@
-team_email: "clank-app-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/tasks/COMMON_METADATA
new file mode 100644
index 0000000..22dbdc6
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Mobile>TabSwitcher>Grid"
+}
+team_email: "memex-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/tasks/DIR_METADATA
index 22dbdc6..e54f5ef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>TabSwitcher>Grid"
-}
-team_email: "memex-team@google.com"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/tasks/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/translate/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/translate/DIR_METADATA
new file mode 100644
index 0000000..58ea368c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/translate/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/translate/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/COMMON_METADATA
new file mode 100644
index 0000000..3347e00
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>UsageStats"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/DIR_METADATA
index 3347e00..ef94d49 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>UsageStats"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/usage_stats/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/webapps/COMMON_METADATA
new file mode 100644
index 0000000..320129e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>WebAppInstalls"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/webapps/DIR_METADATA
index 320129e..1bfc477 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/webapps/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/webauth/COMMON_METADATA
new file mode 100644
index 0000000..4717c96d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>WebAuthentication"
+}
+team_email: "identity-dev@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/webauth/DIR_METADATA
index 4717c96d..e218121 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>WebAuthentication"
-}
-team_email: "identity-dev@chromium.org"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/webauth/COMMON_METADATA"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webshare/COMMON_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/webshare/COMMON_METADATA
new file mode 100644
index 0000000..51b47f7
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webshare/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebShare"
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webshare/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/webshare/DIR_METADATA
index 51b47f7..f669c241 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webshare/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webshare/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebShare"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/webshare/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility/DIR_METADATA
new file mode 100644
index 0000000..5153b281
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/accessibility/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA
new file mode 100644
index 0000000..8a6516f
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/DIR_METADATA
new file mode 100644
index 0000000..cb63906
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/DIR_METADATA
@@ -0,0 +1,2 @@
+mixins: "//components/autofill/COMMON_METADATA"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/DIR_METADATA
index 2c84cedc..a5aa36b6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill_assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Autofill>Assistant"
-}
+mixins: "//components/autofill_assistant/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/background_sync/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
new file mode 100644
index 0000000..8a6d80f
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/background_sync/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA
new file mode 100644
index 0000000..0488c08
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/bookmarks/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
new file mode 100644
index 0000000..a2406d8
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/browserservices/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/DIR_METADATA
index db7a5c4a..7c759f0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Privacy"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/browsing_data/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/DIR_METADATA
new file mode 100644
index 0000000..0fd0ee3d
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/compositor/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
new file mode 100644
index 0000000..50d01c6
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/contextmenu/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/continuous_search/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/continuous_search/DIR_METADATA
new file mode 100644
index 0000000..78deea4
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/continuous_search/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/continuous_search/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
new file mode 100644
index 0000000..4974e3d
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/customtabs/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA
index 53108245..2064f2d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Layout"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/display_cutout/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
new file mode 100644
index 0000000..c9eb2576
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DIR_METADATA
new file mode 100644
index 0000000..8b1c141
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/download/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA
index 25e00b20..f35f760 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//chrome/browser/android/explore_sites/COMMON_METADATA"
 monorail {
   component: "UI>Browser>NewTabPage>ExploreSites"
 }
-team_email: "offline-dev@chromium.org"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
index e22413d..9cfe395 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/gesturenav/COMMON_METADATA"
 monorail {
   component: "UI>Browser>Mobile"
 }
-team_email: "clank-app-team@google.com"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/DIR_METADATA
new file mode 100644
index 0000000..9913bdd
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/infobar/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DIR_METADATA
new file mode 100644
index 0000000..8dd9fb2f
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/locale/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/locale/java/src/org/chromium/chrome/browser/locale/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/DIR_METADATA
new file mode 100644
index 0000000..087037e
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/notifications/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DIR_METADATA
new file mode 100644
index 0000000..30ceb7d
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/ntp/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA
index f9c15e5..97d464e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Offline"
-}
-team_email: "offline-dev@chromium.org"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/offlinepages/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/DIR_METADATA
new file mode 100644
index 0000000..0e541ab
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/omaha/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
index cdf5d93..6a077e0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -509,6 +509,24 @@
     }
 
     /**
+     * Tests the permissions page of the PageInfo UI with sound permissions.
+     */
+    @Test
+    @MediumTest
+    public void testShowPermissionsSubpageWithSound() throws IOException {
+        GURL url = new GURL(mTestServerRule.getServer().getURL("/"));
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            WebsitePreferenceBridge.setContentSettingDefaultScope(
+                    Profile.getLastUsedRegularProfile(), ContentSettingsType.SOUND, url, url,
+                    ContentSettingValues.BLOCK);
+        });
+        loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
+        onView(withId(R.id.page_info_permissions_row)).perform(click());
+        onViewWaiting(allOf(withText("Control this site's access to your device"), isDisplayed()));
+        onView(allOf(withText(containsString("Sound")), isDisplayed()));
+    }
+
+    /**
      * Tests the cookies page of the PageInfo UI.
      */
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/DIR_METADATA
index 2782d66..1148592 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>FreezeDriedTabs"
-}
+mixins: "//components/paint_preview/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA
new file mode 100644
index 0000000..10c6e39a
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA
new file mode 100644
index 0000000..59aa64f
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/profiles/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/profiles/DIR_METADATA
new file mode 100644
index 0000000..3a626e1
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/profiles/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/profiles/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/DIR_METADATA
index b193ae0..a684b81 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>PushAPI"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//content/browser/push_messaging/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/query_tiles/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/query_tiles/DIR_METADATA
new file mode 100644
index 0000000..98d4b501
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/query_tiles/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/query_tiles/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/DIR_METADATA
new file mode 100644
index 0000000..69533cf0
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/searchwidget/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/searchwidget/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/DIR_METADATA
new file mode 100644
index 0000000..971e38c
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/settings/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/share/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/share/DIR_METADATA
new file mode 100644
index 0000000..d4f5fbd1
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/share/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/share/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java
index 6ad5488..452aff5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninFirstRunFragmentRenderTest.java
@@ -134,6 +134,24 @@
     @MediumTest
     @Feature("RenderTest")
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
+    public void testFragmentWithAccountOnManagedDevice(boolean nightModeEnabled)
+            throws IOException {
+        when(mPolicyLoadListenerMock.get()).thenReturn(true);
+        mAccountManagerTestRule.addAccountWithNameAndAvatar(TEST_EMAIL1);
+
+        launchActivityWithFragment();
+
+        CriteriaHelper.pollUiThread(() -> {
+            return mFragment.getView().findViewById(R.id.account_text_secondary).isShown();
+        });
+        mRenderTestRule.render(
+                mFragment.getView(), "signin_first_run_fragment_with_account_managed");
+    }
+
+    @Test
+    @MediumTest
+    @Feature("RenderTest")
+    @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
     public void testFragmentWithoutAccount(boolean nightModeEnabled) throws IOException {
         launchActivityWithFragment();
 
@@ -144,6 +162,19 @@
     @MediumTest
     @Feature("RenderTest")
     @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
+    public void testFragmentWithoutAccountOnManagedDevice(boolean nightModeEnabled)
+            throws IOException {
+        when(mPolicyLoadListenerMock.get()).thenReturn(true);
+        launchActivityWithFragment();
+
+        mRenderTestRule.render(
+                mFragment.getView(), "signin_first_run_fragment_without_account_managed");
+    }
+
+    @Test
+    @MediumTest
+    @Feature("RenderTest")
+    @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class)
     public void testFragmentWithChildAccount(boolean nightModeEnabled) throws IOException {
         mAccountManagerTestRule.addAccountWithNameAndAvatar(CHILD_EMAIL);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/DIR_METADATA
new file mode 100644
index 0000000..ea846f1
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/browser_ui/site_settings/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sms/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/sms/DIR_METADATA
index e0891bf..b635094 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sms/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sms/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//content/browser/sms/COMMON_METADATA"
 monorail {
   component: "Blink>SMS"
 }
-team_email: "fugu-dev@chromium.org"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA
new file mode 100644
index 0000000..3a3f2cc3
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/status_indicator/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/subresource_filter/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/subresource_filter/DIR_METADATA
new file mode 100644
index 0000000..2ada13c
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/subresource_filter/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/subresource_filter/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/DIR_METADATA
index 1a6d7ee6..4a58e65 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Services>Sync"
-}
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/DIR_METADATA
new file mode 100644
index 0000000..e54f5ef
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/tasks/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/DIR_METADATA
new file mode 100644
index 0000000..0d3fa4a0
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ui/android/toolbar/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/DIR_METADATA
new file mode 100644
index 0000000..58ea368c
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/translate/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/DIR_METADATA
new file mode 100644
index 0000000..ef94d49
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/usage_stats/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/DIR_METADATA
index 4717c96d..e218121 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>WebAuthentication"
-}
-team_email: "identity-dev@chromium.org"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/webauth/COMMON_METADATA"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webshare/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/webshare/DIR_METADATA
new file mode 100644
index 0000000..f669c241
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webshare/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/webshare/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/about_settings/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/about_settings/DIR_METADATA
new file mode 100644
index 0000000..88afdc9
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/about_settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/about_settings/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
index 60d8c56..e4c6644 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Upboarding>VideoTutorials"
-}
+mixins: "//chrome/browser/video_tutorials/COMMON_METADATA"
 team_email: "chrome-upboarding@chromium.org"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/DIR_METADATA
new file mode 100644
index 0000000..cb63906
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/DIR_METADATA
@@ -0,0 +1,2 @@
+mixins: "//components/autofill/COMMON_METADATA"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
new file mode 100644
index 0000000..8a6d80f
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/background_sync/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
new file mode 100644
index 0000000..a2406d8
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/browserservices/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/DIR_METADATA
new file mode 100644
index 0000000..0fd0ee3d
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/compositor/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
new file mode 100644
index 0000000..50d01c6
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/contextmenu/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/cryptids/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/cryptids/DIR_METADATA
new file mode 100644
index 0000000..0e5474e
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/cryptids/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/cryptids/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
new file mode 100644
index 0000000..4974e3d
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/customtabs/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA
index 53108245..2064f2d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/display_cutout/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Layout"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/display_cutout/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
new file mode 100644
index 0000000..c9eb2576
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA
new file mode 100644
index 0000000..d0e05ef
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/explore_sites/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/android/explore_sites/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/feed/DIR_METADATA
new file mode 100644
index 0000000..aa7a67e
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/feed/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/DIR_METADATA
new file mode 100644
index 0000000..eacf064
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/image_fetcher/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/image_fetcher/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/notifications/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/DIR_METADATA
new file mode 100644
index 0000000..087037e
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/notifications/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/notifications/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/DIR_METADATA
new file mode 100644
index 0000000..30ceb7d
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/ntp/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA
index f9c15e5..97d464e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Offline"
-}
-team_email: "offline-dev@chromium.org"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/offlinepages/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA
new file mode 100644
index 0000000..b38f8e2
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA
new file mode 100644
index 0000000..10c6e39a
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/password_manager/settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/password_manager/settings/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/preferences/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/DIR_METADATA
new file mode 100644
index 0000000..0f0f251
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/preferences/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/preferences/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA
new file mode 100644
index 0000000..59aa64f
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/privacy/settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/quickactionsearchwidget/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/quickactionsearchwidget/DIR_METADATA
new file mode 100644
index 0000000..b4c6e69
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/quickactionsearchwidget/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/quickactionsearchwidget/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/safe_browsing/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/safe_browsing/DIR_METADATA
new file mode 100644
index 0000000..645a0c1
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/safe_browsing/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/safe_browsing/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/settings/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/settings/DIR_METADATA
new file mode 100644
index 0000000..971e38c
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/settings/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/share/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/share/DIR_METADATA
new file mode 100644
index 0000000..d4f5fbd1
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/share/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/share/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/sharing/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/sharing/DIR_METADATA
index 167ca6e..c1d4532f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/sharing/DIR_METADATA
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/sharing/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Sharing"
-}
+mixins: "//chrome/browser/sharing/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/site_settings/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/site_settings/DIR_METADATA
new file mode 100644
index 0000000..ea846f1
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/site_settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/browser_ui/site_settings/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/sync/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/sync/DIR_METADATA
index 1a6d7ee6..4a58e65 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/sync/DIR_METADATA
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/sync/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Services>Sync"
-}
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA
new file mode 100644
index 0000000..e60ac4f5
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tasks/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/tasks/DIR_METADATA
new file mode 100644
index 0000000..e54f5ef
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tasks/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/tasks/COMMON_METADATA"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/DIR_METADATA
new file mode 100644
index 0000000..1bfc477
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/webapps/COMMON_METADATA"
diff --git a/chrome/android/native_java_unittests/src/org/chromium/chrome/browser/installedapp/DIR_METADATA b/chrome/android/native_java_unittests/src/org/chromium/chrome/browser/installedapp/DIR_METADATA
new file mode 100644
index 0000000..545fdf75
--- /dev/null
+++ b/chrome/android/native_java_unittests/src/org/chromium/chrome/browser/installedapp/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/installedapp/COMMON_METADATA"
diff --git a/chrome/app/android/DIR_METADATA b/chrome/app/android/DIR_METADATA
new file mode 100644
index 0000000..c69388e
--- /dev/null
+++ b/chrome/app/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index c2e6471..7b5e2b2 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1259,12 +1259,6 @@
   <message name="IDS_LOGIN_RECOMMEND_APPS_SCREEN_LOADING" desc="Message shown while the recommended app list is being downloaded.">
     Please wait...
   </message>
-  <message name="IDS_LOGIN_APP_DOWNLOADING_SCREEN_TITLE_SINGULAR" desc="The title of the dialog that tells the user the selected Android App is downloading.">
-    We'll install that app for you
-  </message>
-  <message name="IDS_LOGIN_APP_DOWNLOADING_SCREEN_TITLE_PLURAL" desc="The title of the dialog that tells the user the selected Android Apps are downloading.">
-    We'll install those <ph name="NUMBER_OF_APPS">$1<ex>10</ex></ph> apps for you
-  </message>
   <message name="IDS_LOGIN_APP_DOWNLOADING_SCREEN_TITLE" desc="The title of the dialog that tells the user the selected Android Apps are downloading.">
     Apps downloading
   </message>
diff --git a/chrome/app/vector_icons/DIR_METADATA b/chrome/app/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/chrome/app/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/chrome/app_shim/COMMON_METADATA b/chrome/app_shim/COMMON_METADATA
new file mode 100644
index 0000000..c8b762a
--- /dev/null
+++ b/chrome/app_shim/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org"
diff --git a/chrome/app_shim/DIR_METADATA b/chrome/app_shim/DIR_METADATA
index c8b762a..4587b23 100644
--- a/chrome/app_shim/DIR_METADATA
+++ b/chrome/app_shim/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
+mixins: "//chrome/app_shim/COMMON_METADATA"
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f3eb534..e65b3a8 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3516,8 +3516,12 @@
       "apps/app_discovery_service/play_extras.h",
       "apps/app_discovery_service/recommended_arc_app_fetcher.cc",
       "apps/app_discovery_service/recommended_arc_app_fetcher.h",
+      "apps/app_discovery_service/remote_url_search/remote_url_client.cc",
+      "apps/app_discovery_service/remote_url_search/remote_url_client.h",
       "apps/app_discovery_service/remote_url_search/remote_url_fetcher.cc",
       "apps/app_discovery_service/remote_url_search/remote_url_fetcher.h",
+      "apps/app_discovery_service/remote_url_search/remote_url_index.cc",
+      "apps/app_discovery_service/remote_url_search/remote_url_index.h",
       "apps/app_discovery_service/result.cc",
       "apps/app_discovery_service/result.h",
       "apps/app_discovery_service/test_fetcher.cc",
@@ -3618,6 +3622,10 @@
       "certificate_viewer.h",
       "chrome_process_singleton.cc",
       "chrome_process_singleton.h",
+      "commerce/coupons/coupon_service.cc",
+      "commerce/coupons/coupon_service.h",
+      "commerce/coupons/coupon_service_factory.cc",
+      "commerce/coupons/coupon_service_factory.h",
       "component_updater/desktop_sharing_hub_component_installer.cc",
       "component_updater/desktop_sharing_hub_component_installer.h",
       "component_updater/intervention_policy_database_component_installer.cc",
diff --git a/chrome/browser/accessibility/DIR_METADATA b/chrome/browser/accessibility/DIR_METADATA
index 6849a4f8..173f7e6 100644
--- a/chrome/browser/accessibility/DIR_METADATA
+++ b/chrome/browser/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail: {
   component: "UI>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/chrome/browser/accuracy_tips/DIR_METADATA b/chrome/browser/accuracy_tips/DIR_METADATA
new file mode 100644
index 0000000..1ed35b0
--- /dev/null
+++ b/chrome/browser/accuracy_tips/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/accuracy_tips/COMMON_METADATA"
diff --git a/chrome/browser/android/DIR_METADATA b/chrome/browser/android/DIR_METADATA
new file mode 100644
index 0000000..c69388e
--- /dev/null
+++ b/chrome/browser/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/chrome/browser/android/accessibility/DIR_METADATA b/chrome/browser/android/accessibility/DIR_METADATA
new file mode 100644
index 0000000..5153b281
--- /dev/null
+++ b/chrome/browser/android/accessibility/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/accessibility/COMMON_METADATA"
diff --git a/chrome/browser/android/autofill_assistant/DIR_METADATA b/chrome/browser/android/autofill_assistant/DIR_METADATA
new file mode 100644
index 0000000..a5aa36b6
--- /dev/null
+++ b/chrome/browser/android/autofill_assistant/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/autofill_assistant/COMMON_METADATA"
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index 33cb8680..25962144 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -563,6 +563,7 @@
 
 void UiControllerAndroid::ShowSnackbar(base::TimeDelta delay,
                                        const std::string& message,
+                                       const std::string& undo_string,
                                        base::OnceCallback<void()> action) {
   if (delay.is_zero()) {
     std::move(action).Run();
@@ -580,7 +581,8 @@
   snackbar_action_ = std::move(action);
   Java_AutofillAssistantUiController_showSnackbar(
       env, java_object_, static_cast<jint>(delay.InMilliseconds()),
-      ConvertUTF8ToJavaString(env, message));
+      ConvertUTF8ToJavaString(env, message),
+      ConvertUTF8ToJavaString(env, undo_string));
 }
 
 void UiControllerAndroid::SnackbarResult(
@@ -974,6 +976,8 @@
   ShowSnackbar(ui_delegate_->GetClientSettings().cancel_delay,
                GetDisplayStringUTF8(ClientSettingsProto::STOPPED,
                                     ui_delegate_->GetClientSettings()),
+               GetDisplayStringUTF8(ClientSettingsProto::UNDO,
+                                    ui_delegate_->GetClientSettings()),
                base::BindOnce(&UiControllerAndroid::OnCancel,
                               weak_ptr_factory_.GetWeakPtr(), action_index,
                               std::move(trigger_context), dropout_reason));
@@ -1099,6 +1103,8 @@
   ShowSnackbar(ui_delegate_->GetClientSettings().tap_shutdown_delay,
                GetDisplayStringUTF8(ClientSettingsProto::MAYBE_GIVE_UP,
                                     ui_delegate_->GetClientSettings()),
+               GetDisplayStringUTF8(ClientSettingsProto::UNDO,
+                                    ui_delegate_->GetClientSettings()),
                base::BindOnce(&UiControllerAndroid::Shutdown,
                               weak_ptr_factory_.GetWeakPtr(),
                               Metrics::DropOutReason::OVERLAY_STOP));
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index e46e3bc..eed2ccc 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -272,6 +272,7 @@
   // action after a short delay unless the user taps the undo button.
   void ShowSnackbar(base::TimeDelta delay,
                     const std::string& message,
+                    const std::string& undo_string,
                     base::OnceCallback<void()> action);
 
   void OnCancel(int action_index,
diff --git a/chrome/browser/android/background_task_scheduler/DIR_METADATA b/chrome/browser/android/background_task_scheduler/DIR_METADATA
new file mode 100644
index 0000000..ff006ee1
--- /dev/null
+++ b/chrome/browser/android/background_task_scheduler/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/background_task_scheduler/COMMON_METADATA"
diff --git a/chrome/browser/android/bookmarks/DIR_METADATA b/chrome/browser/android/bookmarks/DIR_METADATA
new file mode 100644
index 0000000..0488c08
--- /dev/null
+++ b/chrome/browser/android/bookmarks/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/bookmarks/COMMON_METADATA"
diff --git a/chrome/browser/android/bottombar/DIR_METADATA b/chrome/browser/android/bottombar/DIR_METADATA
new file mode 100644
index 0000000..519120a
--- /dev/null
+++ b/chrome/browser/android/bottombar/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/COMMON_METADATA"
diff --git a/chrome/browser/android/browserservices/DIR_METADATA b/chrome/browser/android/browserservices/DIR_METADATA
index 60d64a50..f1f352e 100644
--- a/chrome/browser/android/browserservices/DIR_METADATA
+++ b/chrome/browser/android/browserservices/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>TrustedWebActivities"
 }
 team_email: "mwi-team-core@google.com"
-os: ANDROID
diff --git a/chrome/browser/android/browsing_data/DIR_METADATA b/chrome/browser/android/browsing_data/DIR_METADATA
index db7a5c4a..7c759f0 100644
--- a/chrome/browser/android/browsing_data/DIR_METADATA
+++ b/chrome/browser/android/browsing_data/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Privacy"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/browsing_data/COMMON_METADATA"
diff --git a/chrome/browser/android/compositor/DIR_METADATA b/chrome/browser/android/compositor/DIR_METADATA
index c5e1e3e..193fd45 100644
--- a/chrome/browser/android/compositor/DIR_METADATA
+++ b/chrome/browser/android/compositor/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>CompositedUI"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/browser/android/consent_auditor/DIR_METADATA b/chrome/browser/android/consent_auditor/DIR_METADATA
index 7a2580a..c75f2f8 100644
--- a/chrome/browser/android/consent_auditor/DIR_METADATA
+++ b/chrome/browser/android/consent_auditor/DIR_METADATA
@@ -1 +1 @@
-os: ANDROID
+mixins: "//components/consent_auditor/COMMON_METADATA"
diff --git a/chrome/browser/android/cookies/DIR_METADATA b/chrome/browser/android/cookies/DIR_METADATA
index a012b93..99fcdc2 100644
--- a/chrome/browser/android/cookies/DIR_METADATA
+++ b/chrome/browser/android/cookies/DIR_METADATA
@@ -1 +1 @@
-os: ANDROID
\ No newline at end of file
+mixins: "//net/cookies/COMMON_METADATA"
diff --git a/chrome/browser/android/customtabs/DIR_METADATA b/chrome/browser/android/customtabs/DIR_METADATA
index 217d7c3..3ab39f0 100644
--- a/chrome/browser/android/customtabs/DIR_METADATA
+++ b/chrome/browser/android/customtabs/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>CustomTabs"
 }
 team_email: "mobile-web-install-team@google.com"
-os: ANDROID
diff --git a/chrome/browser/android/dom_distiller/DIR_METADATA b/chrome/browser/android/dom_distiller/DIR_METADATA
new file mode 100644
index 0000000..c9eb2576
--- /dev/null
+++ b/chrome/browser/android/dom_distiller/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/COMMON_METADATA"
diff --git a/chrome/browser/android/examples/custom_tabs_client/DIR_METADATA b/chrome/browser/android/examples/custom_tabs_client/DIR_METADATA
index 8749cf8..cc86b52 100644
--- a/chrome/browser/android/examples/custom_tabs_client/DIR_METADATA
+++ b/chrome/browser/android/examples/custom_tabs_client/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Mobile>CustomTabs"
 }
-os: ANDROID
diff --git a/chrome/browser/android/explore_sites/COMMON_METADATA b/chrome/browser/android/explore_sites/COMMON_METADATA
new file mode 100644
index 0000000..e2fc81eff
--- /dev/null
+++ b/chrome/browser/android/explore_sites/COMMON_METADATA
@@ -0,0 +1 @@
+team_email: "offline-dev@chromium.org"
diff --git a/chrome/browser/android/explore_sites/DIR_METADATA b/chrome/browser/android/explore_sites/DIR_METADATA
index e2fc81eff..d0e05ef 100644
--- a/chrome/browser/android/explore_sites/DIR_METADATA
+++ b/chrome/browser/android/explore_sites/DIR_METADATA
@@ -1 +1 @@
-team_email: "offline-dev@chromium.org"
+mixins: "//chrome/browser/android/explore_sites/COMMON_METADATA"
diff --git a/chrome/browser/android/feature_engagement/DIR_METADATA b/chrome/browser/android/feature_engagement/DIR_METADATA
new file mode 100644
index 0000000..02a82b3
--- /dev/null
+++ b/chrome/browser/android/feature_engagement/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/feature_engagement/COMMON_METADATA"
diff --git a/chrome/browser/android/feed/DIR_METADATA b/chrome/browser/android/feed/DIR_METADATA
new file mode 100644
index 0000000..aa7a67e
--- /dev/null
+++ b/chrome/browser/android/feed/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/feed/COMMON_METADATA"
diff --git a/chrome/browser/android/lifecycle/DIR_METADATA b/chrome/browser/android/lifecycle/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/browser/android/lifecycle/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/browser/android/ntp/DIR_METADATA b/chrome/browser/android/ntp/DIR_METADATA
new file mode 100644
index 0000000..30ceb7d
--- /dev/null
+++ b/chrome/browser/android/ntp/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/ntp/COMMON_METADATA"
diff --git a/chrome/browser/android/omnibox/DIR_METADATA b/chrome/browser/android/omnibox/DIR_METADATA
index 07a4669..7a9dec1 100644
--- a/chrome/browser/android/omnibox/DIR_METADATA
+++ b/chrome/browser/android/omnibox/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Omnibox"
-}
+mixins: "//components/omnibox/COMMON_METADATA"
diff --git a/chrome/browser/android/oom_intervention/DIR_METADATA b/chrome/browser/android/oom_intervention/DIR_METADATA
index 4f1a286d..72b25b2 100644
--- a/chrome/browser/android/oom_intervention/DIR_METADATA
+++ b/chrome/browser/android/oom_intervention/DIR_METADATA
@@ -1,2 +1 @@
 team_email: "memory-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/browser/android/preferences/autofill/DIR_METADATA b/chrome/browser/android/preferences/autofill/DIR_METADATA
new file mode 100644
index 0000000..bc280336
--- /dev/null
+++ b/chrome/browser/android/preferences/autofill/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/autofill/COMMON_METADATA"
diff --git a/chrome/browser/android/send_tab_to_self/DIR_METADATA b/chrome/browser/android/send_tab_to_self/DIR_METADATA
index 167ca6e..024779e 100644
--- a/chrome/browser/android/send_tab_to_self/DIR_METADATA
+++ b/chrome/browser/android/send_tab_to_self/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Sharing"
-}
+mixins: "//components/send_tab_to_self/COMMON_METADATA"
diff --git a/chrome/browser/android/vr/DIR_METADATA b/chrome/browser/android/vr/DIR_METADATA
index 804da8e1..51a7b01a 100644
--- a/chrome/browser/android/vr/DIR_METADATA
+++ b/chrome/browser/android/vr/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>VR"
 }
 team_email: "xr-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/browser/android/webapk/DIR_METADATA b/chrome/browser/android/webapk/DIR_METADATA
index d775ce4a..8fc9473 100644
--- a/chrome/browser/android/webapk/DIR_METADATA
+++ b/chrome/browser/android/webapk/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Mobile>WebAPKs"
-}
-team_email: "webapk-team@chromium.org"
+mixins: "//components/webapk/COMMON_METADATA"
diff --git a/chrome/browser/android/webapps/DIR_METADATA b/chrome/browser/android/webapps/DIR_METADATA
index 178ffc9..1c772ca 100644
--- a/chrome/browser/android/webapps/DIR_METADATA
+++ b/chrome/browser/android/webapps/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>WebAppInstalls"
 }
 team_email: "mwi-team-core@google.com"
-os: ANDROID
diff --git a/chrome/browser/apps/app_discovery_service/DIR_METADATA b/chrome/browser/apps/app_discovery_service/DIR_METADATA
index 3ff1ec0..218618b 100644
--- a/chrome/browser/apps/app_discovery_service/DIR_METADATA
+++ b/chrome/browser/apps/app_discovery_service/DIR_METADATA
@@ -1,5 +1,4 @@
 monorail: {
   component: "Platform>Apps>Foundation>Stores"
 }
-team_email: "chromeos-apps-foundation-team@google.com"
 os: CHROME_OS
diff --git a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client.cc b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client.cc
new file mode 100644
index 0000000..8e9fd58
--- /dev/null
+++ b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client.cc
@@ -0,0 +1,16 @@
+// 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/apps/app_discovery_service/remote_url_search/remote_url_client.h"
+
+namespace apps {
+
+RemoteUrlClient::RemoteUrlClient(const GURL& url) : url_(url) {}
+
+void RemoteUrlClient::Fetch(ResultsCallback callback) {
+  // TODO(crbug.com/1244221): Unimplemented.
+  std::move(callback).Run(Status::kOk, base::Value());
+}
+
+}  // namespace apps
diff --git a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client.h b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client.h
new file mode 100644
index 0000000..1514830
--- /dev/null
+++ b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client.h
@@ -0,0 +1,46 @@
+// 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_APPS_APP_DISCOVERY_SERVICE_REMOTE_URL_SEARCH_REMOTE_URL_CLIENT_H_
+#define CHROME_BROWSER_APPS_APP_DISCOVERY_SERVICE_REMOTE_URL_SEARCH_REMOTE_URL_CLIENT_H_
+
+#include "base/callback.h"
+#include "base/values.h"
+#include "url/gurl.h"
+
+namespace apps {
+
+// A client that queries the URL provided at construction for app
+// recommendations. The intended usage here is to periodically call Fetch, which
+// will pass results or an error to its callback.
+class RemoteUrlClient {
+ public:
+  // Possible outcomes of a call to the URL. These values persist to logs.
+  // Entries should not be renumbered and numeric values should never be reused.
+  enum class Status {
+    kOk = 0,
+    kMaxValue = kOk,
+  };
+
+  using ResultsCallback = base::OnceCallback<void(Status, base::Value)>;
+
+  explicit RemoteUrlClient(const GURL& url);
+  ~RemoteUrlClient() = default;
+
+  RemoteUrlClient(const RemoteUrlClient&) = delete;
+  RemoteUrlClient& operator=(const RemoteUrlClient&) = delete;
+
+  // Fetch results from the given URL. |callback| will be called in one of two
+  // ways:
+  // - with Status::kOk and a valid base::Value* if the fetch was successful
+  // - with any other Status and a nullptr base::Value* otherwise
+  void Fetch(ResultsCallback callback);
+
+ private:
+  GURL url_;
+};
+
+}  // namespace apps
+
+#endif  // CHROME_BROWSER_APPS_APP_DISCOVERY_SERVICE_REMOTE_URL_SEARCH_REMOTE_URL_CLIENT_H_
diff --git a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client_unittest.cc b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client_unittest.cc
new file mode 100644
index 0000000..fa2f9480
--- /dev/null
+++ b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client_unittest.cc
@@ -0,0 +1,23 @@
+// 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/apps/app_discovery_service/remote_url_search/remote_url_client.h"
+
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace apps {
+
+// TODO(crbug.com/1244221): This test just exercises the unimplemented Fetch
+// method as a stand-in for proper tests once the logic is implemented.
+TEST(RemoteUrlClientTest, FetchReturnsOk) {
+  RemoteUrlClient client(GURL("test.url"));
+  client.Fetch(
+      base::BindOnce([](RemoteUrlClient::Status status, base::Value value) {
+        EXPECT_EQ(status, RemoteUrlClient::Status::kOk);
+      }));
+}
+
+}  // namespace apps
diff --git a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_fetcher.cc b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_fetcher.cc
index 3ec780d9..8508f04 100644
--- a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_fetcher.cc
+++ b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_fetcher.cc
@@ -6,10 +6,30 @@
 
 #include "base/values.h"
 #include "chrome/browser/apps/app_discovery_service/app_discovery_features.h"
+#include "chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client.h"
+#include "chrome/browser/profiles/profile.h"
 
 namespace apps {
+namespace {
 
-RemoteUrlFetcher::RemoteUrlFetcher(Profile* profile) {}
+constexpr char kIndexStoragePath[] = "launcher/remote_url_index.json";
+
+}
+
+RemoteUrlFetcher::RemoteUrlFetcher(Profile* profile) {
+  GURL url;
+
+  // TODO(crbug.com/1244221): Enabled state should also depend on whether we can
+  // find a url.
+  enabled_ = IsRemoteUrlSearchEnabled();
+  if (enabled_) {
+    index_ = std::make_unique<RemoteUrlIndex>(
+        std::make_unique<RemoteUrlClient>(url),
+        profile->GetPath().AppendASCII(kIndexStoragePath));
+  }
+}
+
+RemoteUrlFetcher::~RemoteUrlFetcher() = default;
 
 void RemoteUrlFetcher::GetApps(ResultCallback callback) {
   if (!IsRemoteUrlSearchEnabled()) {
diff --git a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_fetcher.h b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_fetcher.h
index 63eced4..31052a2 100644
--- a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_fetcher.h
+++ b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_fetcher.h
@@ -7,19 +7,29 @@
 
 #include "chrome/browser/apps/app_discovery_service/app_discovery_util.h"
 #include "chrome/browser/apps/app_discovery_service/app_fetcher_manager.h"
+#include "chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index.h"
+
+class Profile;
 
 namespace apps {
 
-// Adds
+// A fetcher for app recommendations coming from a hardcoded URL. This manages
+// the querying the URL, and indexing and searching the results.
 class RemoteUrlFetcher : public AppFetcher {
  public:
   explicit RemoteUrlFetcher(Profile* profile);
-  ~RemoteUrlFetcher() override = default;
+  ~RemoteUrlFetcher() override;
+
   RemoteUrlFetcher(const RemoteUrlFetcher&) = delete;
   RemoteUrlFetcher& operator=(const RemoteUrlFetcher&) = delete;
 
   // AppFetcher:
   void GetApps(ResultCallback callback) override;
+
+ private:
+  std::unique_ptr<RemoteUrlIndex> index_;
+
+  bool enabled_ = false;
 };
 
 }  // namespace apps
diff --git a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index.cc b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index.cc
new file mode 100644
index 0000000..6072a2e
--- /dev/null
+++ b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index.cc
@@ -0,0 +1,46 @@
+// 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/apps/app_discovery_service/remote_url_search/remote_url_index.h"
+
+#include "base/time/time.h"
+#include "base/values.h"
+
+namespace apps {
+namespace {
+
+constexpr base::TimeDelta kUpdateInterval = base::TimeDelta::FromHours(24);
+
+}  // namespace
+
+RemoteUrlIndex::RemoteUrlIndex(std::unique_ptr<RemoteUrlClient> client,
+                               const base::FilePath& storage_path)
+    : client_(std::move(client)), storage_path_(storage_path) {
+  MaybeUpdateAndReschedule();
+}
+
+RemoteUrlIndex::~RemoteUrlIndex() = default;
+
+base::Value* RemoteUrlIndex::GetApps(const std::string& query) {
+  // TODO(crbug.com/1244221): Unimplemented.
+  return nullptr;
+}
+
+void RemoteUrlIndex::MaybeUpdateAndReschedule() {
+  client_->Fetch(base::BindOnce(&RemoteUrlIndex::OnUpdateComplete,
+                                weak_factory_.GetWeakPtr()));
+
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&RemoteUrlIndex::MaybeUpdateAndReschedule,
+                     weak_factory_.GetWeakPtr()),
+      kUpdateInterval);
+}
+
+void RemoteUrlIndex::OnUpdateComplete(RemoteUrlClient::Status status,
+                                      base::Value value) {
+  // TODO(crbug.com/1244221): Unimplemented.
+}
+
+}  // namespace apps
diff --git a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index.h b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index.h
new file mode 100644
index 0000000..50832b8
--- /dev/null
+++ b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index.h
@@ -0,0 +1,51 @@
+// 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_APPS_APP_DISCOVERY_SERVICE_REMOTE_URL_SEARCH_REMOTE_URL_INDEX_H_
+#define CHROME_BROWSER_APPS_APP_DISCOVERY_SERVICE_REMOTE_URL_SEARCH_REMOTE_URL_INDEX_H_
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client.h"
+
+namespace base {
+class Value;
+}  // namespace base
+
+namespace apps {
+class RemoteUrlClient;
+
+// An index of app recommendations. Uses the RemoteUrlClient given at
+// construction to periodically request app recommendations. The results are
+// then indexed and made available for querying via the GetApps method.
+class RemoteUrlIndex {
+ public:
+  RemoteUrlIndex(std::unique_ptr<RemoteUrlClient> client,
+                 const base::FilePath& storage_path);
+  ~RemoteUrlIndex();
+
+  RemoteUrlIndex(const RemoteUrlIndex&) = delete;
+  RemoteUrlIndex& operator=(const RemoteUrlIndex&) = delete;
+
+  base::Value* GetApps(const std::string& query);
+
+ private:
+  void MaybeUpdateAndReschedule();
+  void OnUpdateComplete(RemoteUrlClient::Status status, base::Value value);
+
+  const std::unique_ptr<RemoteUrlClient> client_;
+
+  const base::FilePath storage_path_;
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  base::WeakPtrFactory<RemoteUrlIndex> weak_factory_{this};
+};
+
+}  // namespace apps
+
+#endif  // CHROME_BROWSER_APPS_APP_DISCOVERY_SERVICE_REMOTE_URL_SEARCH_REMOTE_URL_INDEX_H_
diff --git a/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index_unittest.cc b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index_unittest.cc
new file mode 100644
index 0000000..2c7bee16
--- /dev/null
+++ b/chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_index_unittest.cc
@@ -0,0 +1,54 @@
+// 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/apps/app_discovery_service/remote_url_search/remote_url_index.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/simple_test_clock.h"
+#include "base/test/task_environment.h"
+#include "chrome/browser/apps/app_discovery_service/remote_url_search/remote_url_client.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace apps {
+
+class RemoteUrlIndexTest : public testing::Test {
+ protected:
+  RemoteUrlIndexTest() = default;
+  ~RemoteUrlIndexTest() override = default;
+
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+  base::FilePath GetPath() {
+    return temp_dir_.GetPath().AppendASCII("storage.json");
+  }
+
+  void Wait() { task_environment_.RunUntilIdle(); }
+
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::MainThreadType::UI,
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME,
+      base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED};
+  base::ScopedTempDir temp_dir_;
+};
+
+// TODO(crbug.com/1244221): This test just exercises the unimplemented GetApps
+// method as a stand-in for proper tests once the logic is implemented.
+TEST_F(RemoteUrlIndexTest, GetApps) {
+  auto client = std::make_unique<RemoteUrlClient>(GURL("test.url"));
+  RemoteUrlIndex index(std::move(client), GetPath());
+  EXPECT_EQ(index.GetApps(""), nullptr);
+}
+
+// Tests that one iteration of the update loop doesn't crash.
+TEST_F(RemoteUrlIndexTest, WaitForUpdate) {
+  auto client = std::make_unique<RemoteUrlClient>(GURL("test.url"));
+  RemoteUrlIndex index(std::move(client), GetPath());
+  task_environment_.AdvanceClock(base::TimeDelta::FromDays(2));
+  Wait();
+  SUCCEED();
+}
+
+}  // namespace apps
diff --git a/chrome/browser/apps/app_service/DIR_METADATA b/chrome/browser/apps/app_service/DIR_METADATA
index 21dfabe8..c0404074 100644
--- a/chrome/browser/apps/app_service/DIR_METADATA
+++ b/chrome/browser/apps/app_service/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Platform>Apps>Foundation>AppService"
-}
-team_email: "chromeos-apps-foundation-team@google.com"
+mixins: "//components/services/app_service/COMMON_METADATA"
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 af0f517..161c66c 100644
--- a/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc
+++ b/chrome/browser/apps/app_service/app_service_proxy_chromeos.cc
@@ -127,8 +127,8 @@
   // profile and ensures there is only one instance of StandaloneBrowserApps.
   if (crosapi::browser_util::IsLacrosEnabled() &&
       chromeos::ProfileHelper::IsPrimaryProfile(profile_)) {
-    standalone_browser_apps_ =
-        std::make_unique<StandaloneBrowserApps>(app_service_, profile_);
+    standalone_browser_apps_ = std::make_unique<StandaloneBrowserApps>(
+        app_service_, profile_, browser_app_instance_registry_.get());
   }
   web_apps_ = std::make_unique<web_app::WebApps>(app_service_,
                                                  &instance_registry_, profile_);
diff --git a/chrome/browser/apps/app_service/browser_app_instance_registry.cc b/chrome/browser/apps/app_service/browser_app_instance_registry.cc
index 9a21017..4b31e85 100644
--- a/chrome/browser/apps/app_service/browser_app_instance_registry.cc
+++ b/chrome/browser/apps/app_service/browser_app_instance_registry.cc
@@ -71,6 +71,15 @@
   return ash_instance_tracker_.GetBrowserWindowInstanceById(id);
 }
 
+std::set<const BrowserWindowInstance*>
+BrowserAppInstanceRegistry::GetLacrosBrowserWindowInstances() const {
+  std::set<const BrowserWindowInstance*> result;
+  for (const auto& pair : lacros_window_instances_) {
+    result.insert(pair.second.get());
+  }
+  return result;
+}
+
 const BrowserAppInstance*
 BrowserAppInstanceRegistry::GetActiveAppInstanceForWindow(
     aura::Window* window) {
diff --git a/chrome/browser/apps/app_service/browser_app_instance_registry.h b/chrome/browser/apps/app_service/browser_app_instance_registry.h
index 6cc9966..a6ae101 100644
--- a/chrome/browser/apps/app_service/browser_app_instance_registry.h
+++ b/chrome/browser/apps/app_service/browser_app_instance_registry.h
@@ -68,6 +68,10 @@
   const BrowserWindowInstance* GetBrowserWindowInstanceById(
       base::UnguessableToken id) const;
 
+  // Get all instances of lacros browser window instances.
+  std::set<const BrowserWindowInstance*> GetLacrosBrowserWindowInstances()
+      const;
+
   // Get the currently active app instance for a window (Ash or Lacros).
   const BrowserAppInstance* GetActiveAppInstanceForWindow(aura::Window* window);
 
diff --git a/chrome/browser/apps/app_service/publishers/standalone_browser_apps.cc b/chrome/browser/apps/app_service/publishers/standalone_browser_apps.cc
index a9e5565..7da65c6 100644
--- a/chrome/browser/apps/app_service/publishers/standalone_browser_apps.cc
+++ b/chrome/browser/apps/app_service/publishers/standalone_browser_apps.cc
@@ -10,20 +10,24 @@
 #include "base/bind.h"
 #include "build/branding_buildflags.h"
 #include "chrome/browser/apps/app_service/app_icon_factory.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_registry.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
 #include "chrome/browser/ash/crosapi/browser_manager.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "extensions/common/constants.h"
+#include "ui/views/widget/widget.h"
 
 namespace apps {
 
 StandaloneBrowserApps::StandaloneBrowserApps(
     const mojo::Remote<apps::mojom::AppService>& app_service,
-    Profile* profile)
-    : profile_(profile) {
+    Profile* profile,
+    BrowserAppInstanceRegistry* registry)
+    : profile_(profile), browser_app_instance_registry_(registry) {
   DCHECK(crosapi::browser_util::IsLacrosEnabled());
   PublisherBase::Initialize(app_service,
                             apps::mojom::AppType::kStandaloneBrowser);
@@ -122,6 +126,25 @@
   std::move(callback).Run(CreateBrowserMenuItems(menu_type, profile_));
 }
 
+void StandaloneBrowserApps::StopApp(const std::string& app_id) {
+  DCHECK_EQ(extension_misc::kLacrosAppId, app_id);
+  if (!features::IsBrowserAppInstanceTrackingEnabled()) {
+    return;
+  }
+  DCHECK(browser_app_instance_registry_);
+  for (const BrowserWindowInstance* instance :
+       browser_app_instance_registry_->GetLacrosBrowserWindowInstances()) {
+    views::Widget* widget =
+        views::Widget::GetWidgetForNativeView(instance->window);
+    DCHECK(widget);
+    // TODO(crbug.com/1252688): kUnspecified is only supposed to be used for
+    // backwards compatibility with (deprecated) Close(), but there is no enum
+    // for other cases where StopApp may be invoked, for example, closing the
+    // app from a menu.
+    widget->CloseWithReason(views::Widget::ClosedReason::kUnspecified);
+  }
+}
+
 void StandaloneBrowserApps::OnLoadComplete(bool success) {
   apps::mojom::AppPtr app = apps::mojom::App::New();
   app->app_type = apps::mojom::AppType::kStandaloneBrowser;
diff --git a/chrome/browser/apps/app_service/publishers/standalone_browser_apps.h b/chrome/browser/apps/app_service/publishers/standalone_browser_apps.h
index b3c813be..c36072b 100644
--- a/chrome/browser/apps/app_service/publishers/standalone_browser_apps.h
+++ b/chrome/browser/apps/app_service/publishers/standalone_browser_apps.h
@@ -17,6 +17,8 @@
 
 namespace apps {
 
+class BrowserAppInstanceRegistry;
+
 // An app publisher (in the App Service sense) for the "LaCrOS" app icon,
 // which launches the lacros-chrome binary.
 //
@@ -25,7 +27,8 @@
  public:
   StandaloneBrowserApps(
       const mojo::Remote<apps::mojom::AppService>& app_service,
-      Profile* profile);
+      Profile* profile,
+      BrowserAppInstanceRegistry* registry);
   ~StandaloneBrowserApps() override;
 
   StandaloneBrowserApps(const StandaloneBrowserApps&) = delete;
@@ -59,9 +62,11 @@
                     apps::mojom::MenuType menu_type,
                     int64_t display_id,
                     GetMenuModelCallback callback) override;
+  void StopApp(const std::string& app_id) override;
 
   mojo::RemoteSet<apps::mojom::Subscriber> subscribers_;
   Profile* const profile_;
+  BrowserAppInstanceRegistry* browser_app_instance_registry_;
   apps_util::IncrementingIconKeyFactory icon_key_factory_;
   base::WeakPtrFactory<StandaloneBrowserApps> weak_factory_{this};
 };
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
index e5cee2b..1a7645c 100644
--- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
+++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/apps/app_service/app_icon_factory.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_registry.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_features.h"
@@ -153,10 +154,19 @@
                                &menu_items);
   }
 
-  if (menu_type == apps::mojom::MenuType::kShelf &&
-      proxy->InstanceRegistry().ContainsAppId(app_id)) {
-    apps::AddCommandItem(ash::MENU_CLOSE, IDS_SHELF_CONTEXT_MENU_CLOSE,
-                         &menu_items);
+  if (menu_type == apps::mojom::MenuType::kShelf) {
+    // TODO(crbug.com/1203992): We cannot use InstanceRegistry with lacros yet,
+    // because InstanceRegistry updates for lacros isn't implemented yet, so we
+    // need to check BrowserAppInstanceRegistry directly. Remove this when
+    // InstanceRegistry updates are implemented.
+    bool app_running =
+        base::FeatureList::IsEnabled(features::kWebAppsCrosapi)
+            ? proxy->BrowserAppInstanceRegistry()->IsAppRunning(app_id)
+            : proxy->InstanceRegistry().ContainsAppId(app_id);
+    if (app_running) {
+      apps::AddCommandItem(ash::MENU_CLOSE, IDS_SHELF_CONTEXT_MENU_CLOSE,
+                           &menu_items);
+    }
   }
 
   if (can_use_uninstall) {
diff --git a/chrome/browser/apps/app_shim/DIR_METADATA b/chrome/browser/apps/app_shim/DIR_METADATA
new file mode 100644
index 0000000..4587b23
--- /dev/null
+++ b/chrome/browser/apps/app_shim/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/app_shim/COMMON_METADATA"
diff --git a/chrome/browser/apps/digital_goods/DIR_METADATA b/chrome/browser/apps/digital_goods/DIR_METADATA
index 3ff1ec0..218618b 100644
--- a/chrome/browser/apps/digital_goods/DIR_METADATA
+++ b/chrome/browser/apps/digital_goods/DIR_METADATA
@@ -1,5 +1,4 @@
 monorail: {
   component: "Platform>Apps>Foundation>Stores"
 }
-team_email: "chromeos-apps-foundation-team@google.com"
 os: CHROME_OS
diff --git a/chrome/browser/apps/guest_view/DIR_METADATA b/chrome/browser/apps/guest_view/DIR_METADATA
index df25159e..38cda2d 100644
--- a/chrome/browser/apps/guest_view/DIR_METADATA
+++ b/chrome/browser/apps/guest_view/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Platform>Apps>BrowserTag"
-}
+mixins: "//components/guest_view/COMMON_METADATA"
diff --git a/chrome/browser/apps/intent_helper/DIR_METADATA b/chrome/browser/apps/intent_helper/DIR_METADATA
index 6a024f2..d65ef929 100644
--- a/chrome/browser/apps/intent_helper/DIR_METADATA
+++ b/chrome/browser/apps/intent_helper/DIR_METADATA
@@ -1,5 +1,4 @@
 monorail: {
   component: "Platform>Apps>Foundation>Intents"
 }
-team_email: "chromeos-apps-foundation-team@google.com"
 os: CHROME_OS
diff --git a/chrome/browser/apps/platform_apps/api/media_galleries/DIR_METADATA b/chrome/browser/apps/platform_apps/api/media_galleries/DIR_METADATA
new file mode 100644
index 0000000..a9173fc
--- /dev/null
+++ b/chrome/browser/apps/platform_apps/api/media_galleries/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/media_galleries/COMMON_METADATA"
diff --git a/chrome/browser/ash/accessibility/DIR_METADATA b/chrome/browser/ash/accessibility/DIR_METADATA
index 6849a4f8..173f7e6 100644
--- a/chrome/browser/ash/accessibility/DIR_METADATA
+++ b/chrome/browser/ash/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail: {
   component: "UI>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/chrome/browser/ash/accessibility/spoken_feedback_app_list_browsertest.cc b/chrome/browser/ash/accessibility/spoken_feedback_app_list_browsertest.cc
index 1aac9e6..b36c51b 100644
--- a/chrome/browser/ash/accessibility/spoken_feedback_app_list_browsertest.cc
+++ b/chrome/browser/ash/accessibility/spoken_feedback_app_list_browsertest.cc
@@ -15,6 +15,8 @@
 #include "chrome/browser/ash/accessibility/spoken_feedback_browsertest.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
+#include "chrome/browser/ui/app_list/app_list_model_updater.h"
+#include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/common/chrome_switches.h"
@@ -94,7 +96,11 @@
   }
 
   // Populate apps grid with |num| items.
-  void PopulateApps(size_t num) { app_list_test_model_->PopulateApps(num); }
+  virtual void PopulateApps(size_t num) {
+    // TODO(https://crbug.com/1251617): use `ChromeAppListModelUpdater` instead
+    // of `app_list_test_model_` to populate apps.
+    app_list_test_model_->PopulateApps(num);
+  }
 
   // Populate |num| suggestion chips.
   void PopulateChips(size_t num) {
@@ -549,78 +555,6 @@
   sm_.Replay();
 }
 
-// Checks that app list keyboard reordering is announced.
-// TODO(mmourgos): The current method of accessibility announcements for item
-// reordering uses alerts, this works for spoken feedback but does not work as
-// well for braille users. The preferred way to handle this is to actually
-// change focus as the user navigates, and to have each object's
-// accessible name describe its position. (See crbug.com/1098495)
-IN_PROC_BROWSER_TEST_P(SpokenFeedbackAppListTest, AppListReordering) {
-  // Add 7 apps.
-  PopulateApps(22);
-
-  EnableChromeVox();
-
-  sm_.Call([this]() {
-    EXPECT_TRUE(PerformAcceleratorAction(AcceleratorAction::FOCUS_SHELF));
-  });
-  sm_.ExpectSpeech("Shelf");
-  // Press space on the launcher button in shelf, this opens peeking
-  // launcher.
-  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); });
-  sm_.ExpectSpeech("Launcher, partial view");
-  // Send a key press to enable keyboard traversal
-  sm_.Call([this]() { SendKeyPressWithSearchAndShift(ui::VKEY_TAB); });
-  // Move focus to expand all apps button.
-  sm_.Call([this]() { SendKeyPressWithSearchAndShift(ui::VKEY_TAB); });
-  sm_.ExpectSpeech("Expand to all apps");
-  // Press space on expand arrow to go to fullscreen launcher.
-  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); });
-  sm_.ExpectSpeech("Launcher, all apps");
-
-  // Move focus to first app;
-  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); });
-  sm_.ExpectSpeech("Item 0");
-  sm_.ExpectSpeech("Button");
-
-  // Move the first item to the right.
-  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_RIGHT); });
-  sm_.ExpectNextSpeechIsNot("Alert");
-  sm_.ExpectSpeech("Moved to Page 1, row 1, column 2.");
-
-  // Move the focused item down.
-  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_DOWN); });
-  sm_.ExpectNextSpeechIsNot("Alert");
-  sm_.ExpectSpeech("Moved to Page 1, row 2, column 2.");
-
-  // Move the focused item down.
-  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_DOWN); });
-  sm_.ExpectNextSpeechIsNot("Alert");
-  sm_.ExpectSpeech("Moved to Page 1, row 3, column 2.");
-
-  // Move the focused item down.
-  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_DOWN); });
-  sm_.ExpectNextSpeechIsNot("Alert");
-  sm_.ExpectSpeech("Moved to Page 1, row 4, column 2.");
-
-  // Move the focused item down to page 2.
-  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_DOWN); });
-  sm_.ExpectNextSpeechIsNot("Alert");
-  sm_.ExpectSpeech("Moved to Page 2, row 1, column 2.");
-
-  // Move the focused item to the left.
-  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_LEFT); });
-  sm_.ExpectNextSpeechIsNot("Alert");
-  sm_.ExpectSpeech("Moved to Page 2, row 1, column 1.");
-
-  // Move the focused item back up to page 1..
-  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_UP); });
-  sm_.ExpectNextSpeechIsNot("Alert");
-  sm_.ExpectSpeech("Moved to Page 1, row 4, column 1.");
-
-  sm_.Replay();
-}
-
 IN_PROC_BROWSER_TEST_P(SpokenFeedbackAppListTest,
                        LauncherWindowTitleAnnouncement) {
   EnableChromeVox();
@@ -658,4 +592,131 @@
   sm_.Replay();
 }
 
+// The test with `ChromeAppListModelUpdater` set.
+class SpokenFeedbackWithChromeAppListModelUpdaterTest
+    : public SpokenFeedbackAppListTest {
+ public:
+  SpokenFeedbackWithChromeAppListModelUpdaterTest() = default;
+  ~SpokenFeedbackWithChromeAppListModelUpdaterTest() override = default;
+
+  void SetUpOnMainThread() override {
+    SpokenFeedbackAppListTest::SetUpOnMainThread();
+    AppListClientImpl::GetInstance()->UpdateProfile();
+  }
+  void PopulateApps(size_t num) override {
+    // Only folders or page breaks are allowed to be added from the Ash side.
+    // Therefore new apps should be added through `ChromeAppListModelUpdater`.
+    ::test::PopulateDummyAppListItems(num);
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(TestAsNormalAndGuestUser,
+                         SpokenFeedbackWithChromeAppListModelUpdaterTest,
+                         ::testing::Values(kTestAsNormalUser,
+                                           kTestAsGuestUser));
+
+// Checks that app list keyboard reordering is announced.
+// TODO(mmourgos): The current method of accessibility announcements for item
+// reordering uses alerts, this works for spoken feedback but does not work as
+// well for braille users. The preferred way to handle this is to actually
+// change focus as the user navigates, and to have each object's
+// accessible name describe its position. (See crbug.com/1098495)
+IN_PROC_BROWSER_TEST_P(SpokenFeedbackWithChromeAppListModelUpdaterTest,
+                       AppListReordering) {
+  const int default_app_count =
+      AppListClientImpl::GetInstance()->GetModelUpdaterForTest()->ItemCount();
+
+  PopulateApps(22);
+  EnableChromeVox();
+
+  sm_.Call([this]() {
+    EXPECT_TRUE(PerformAcceleratorAction(AcceleratorAction::FOCUS_SHELF));
+  });
+  sm_.ExpectSpeech("Shelf");
+  // Press space on the launcher button in shelf, this opens peeking
+  // launcher.
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); });
+  sm_.ExpectSpeech("Launcher, partial view");
+  // Send a key press to enable keyboard traversal
+  sm_.Call([this]() { SendKeyPressWithSearchAndShift(ui::VKEY_TAB); });
+  // Move focus to expand all apps button.
+  sm_.Call([this]() { SendKeyPressWithSearchAndShift(ui::VKEY_TAB); });
+  sm_.ExpectSpeech("Expand to all apps");
+  // Press space on expand arrow to go to fullscreen launcher.
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); });
+  sm_.ExpectSpeech("Launcher, all apps");
+
+  // Move focus to first app;
+  sm_.Call([this, &default_app_count]() {
+    SendKeyPressWithSearch(ui::VKEY_DOWN);
+    if (default_app_count) {
+      // Skip the suggestion chips.
+      SendKeyPressWithSearch(ui::VKEY_DOWN);
+
+      // Skip the default installed apps.
+      for (int i = 0; i < default_app_count; ++i)
+        SendKeyPressWithSearch(ui::VKEY_RIGHT);
+    }
+  });
+  sm_.ExpectSpeech("app 0");
+  sm_.ExpectSpeech("Button");
+
+  // The default column of app 0.
+  const int original_column = default_app_count + 1;
+
+  // The column of app 0 after rightward move.
+  const int column_after_horizontal_move = original_column + 1;
+
+  // Move the first item to the right.
+  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_RIGHT); });
+  sm_.ExpectNextSpeechIsNot("Alert");
+
+  std::string expected_text;
+  sm_.ExpectSpeech(base::SStringPrintf(&expected_text,
+                                       "Moved to Page 1, row 1, column %d.",
+                                       column_after_horizontal_move));
+
+  // Move the focused item down.
+  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_DOWN); });
+  sm_.ExpectNextSpeechIsNot("Alert");
+  sm_.ExpectSpeech(base::SStringPrintf(&expected_text,
+                                       "Moved to Page 1, row 2, column %d.",
+                                       column_after_horizontal_move));
+
+  // Move the focused item down.
+  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_DOWN); });
+  sm_.ExpectNextSpeechIsNot("Alert");
+  sm_.ExpectSpeech(base::SStringPrintf(&expected_text,
+                                       "Moved to Page 1, row 3, column %d.",
+                                       column_after_horizontal_move));
+
+  // Move the focused item down.
+  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_DOWN); });
+  sm_.ExpectNextSpeechIsNot("Alert");
+  sm_.ExpectSpeech(base::SStringPrintf(&expected_text,
+                                       "Moved to Page 1, row 4, column %d.",
+                                       column_after_horizontal_move));
+
+  // Move the focused item down to page 2.
+  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_DOWN); });
+  sm_.ExpectNextSpeechIsNot("Alert");
+  sm_.ExpectSpeech(base::SStringPrintf(&expected_text,
+                                       "Moved to Page 2, row 1, column %d.",
+                                       column_after_horizontal_move));
+
+  // Move the focused item to the left.
+  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_LEFT); });
+  sm_.ExpectNextSpeechIsNot("Alert");
+  sm_.ExpectSpeech(base::SStringPrintf(
+      &expected_text, "Moved to Page 2, row 1, column %d.", original_column));
+
+  // Move the focused item back up to page 1..
+  sm_.Call([this]() { SendKeyPressWithControl(ui::VKEY_UP); });
+  sm_.ExpectNextSpeechIsNot("Alert");
+  sm_.ExpectSpeech(base::SStringPrintf(
+      &expected_text, "Moved to Page 1, row 4, column %d.", original_column));
+
+  sm_.Replay();
+}
+
 }  // namespace ash
diff --git a/chrome/browser/ash/app_mode/COMMON_METADATA b/chrome/browser/ash/app_mode/COMMON_METADATA
new file mode 100644
index 0000000..a940a13
--- /dev/null
+++ b/chrome/browser/ash/app_mode/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Shell>Kiosk"
+}
diff --git a/chrome/browser/ash/app_mode/DIR_METADATA b/chrome/browser/ash/app_mode/DIR_METADATA
index a940a13..d4effef 100644
--- a/chrome/browser/ash/app_mode/DIR_METADATA
+++ b/chrome/browser/ash/app_mode/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Shell>Kiosk"
-}
+mixins: "//chrome/browser/ash/app_mode/COMMON_METADATA"
diff --git a/chrome/browser/ash/arc/DIR_METADATA b/chrome/browser/ash/arc/DIR_METADATA
new file mode 100644
index 0000000..54a0fa6
--- /dev/null
+++ b/chrome/browser/ash/arc/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/arc/COMMON_METADATA"
diff --git a/chrome/browser/ash/arc/accessibility/DIR_METADATA b/chrome/browser/ash/arc/accessibility/DIR_METADATA
index 6849a4f8..173f7e6 100644
--- a/chrome/browser/ash/arc/accessibility/DIR_METADATA
+++ b/chrome/browser/ash/arc/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail: {
   component: "UI>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
index 2cd5c2c..2987ad1 100644
--- a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
+++ b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
@@ -356,8 +356,6 @@
   // Initializes |test_system_slot_|.
   void SetUpTestSystemSlot();
 
-  void SetUpTestSystemSlotOnIO(bool* out_system_slot_constructed_successfully);
-
   // Destroys |test_system_slot_|.
   void TearDownTestSystemSlot();
 
@@ -380,6 +378,9 @@
   MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
   chromeos::platform_keys::PlatformKeysServiceFactory::GetInstance()
       ->SetTestingMode(true);
+
+  // Set up a system slot so tests can access device certs.
+  ASSERT_NO_FATAL_FAILURE(SetUpTestSystemSlot());
 }
 
 void CertStoreServiceTest::SetUpOnMainThread() {
@@ -405,8 +406,6 @@
       profile(), base::BindRepeating(&BuildCertStoreService,
                                      base::Passed(std::move(installer))));
 
-  // Set up a system slot so tests can access device certs.
-  ASSERT_NO_FATAL_FAILURE(SetUpTestSystemSlot());
   ASSERT_TRUE(IsSystemSlotAvailable(profile()));
 }
 
@@ -579,24 +578,9 @@
 }
 
 void CertStoreServiceTest::SetUpTestSystemSlot() {
-  bool system_slot_constructed_successfully = false;
-  base::RunLoop loop;
-  content::GetIOThreadTaskRunner({})->PostTaskAndReply(
-      FROM_HERE,
-      base::BindOnce(&CertStoreServiceTest::SetUpTestSystemSlotOnIO,
-                     base::Unretained(this),
-                     &system_slot_constructed_successfully),
-      loop.QuitClosure());
-  loop.Run();
-  ASSERT_TRUE(system_slot_constructed_successfully);
-}
-
-void CertStoreServiceTest::SetUpTestSystemSlotOnIO(
-    bool* out_system_slot_constructed_successfully) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>();
-  *out_system_slot_constructed_successfully =
-      test_system_slot_->ConstructedSuccessfully();
+  test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>(
+      /*simulate_token_loader=*/false);
+  ASSERT_TRUE(test_system_slot_->ConstructedSuccessfully());
 }
 
 void CertStoreServiceTest::TearDownTestSystemSlot() {
diff --git a/chrome/browser/ash/assistant/DIR_METADATA b/chrome/browser/ash/assistant/DIR_METADATA
index 0267debb..cfb0c371 100644
--- a/chrome/browser/ash/assistant/DIR_METADATA
+++ b/chrome/browser/ash/assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Shell>Assistant"
-}
+mixins: "//chromeos/assistant/COMMON_METADATA"
diff --git a/chrome/browser/ash/dbus/DIR_METADATA b/chrome/browser/ash/dbus/DIR_METADATA
new file mode 100644
index 0000000..40779e6
--- /dev/null
+++ b/chrome/browser/ash/dbus/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chromeos/dbus/COMMON_METADATA"
diff --git a/chrome/browser/ash/file_manager/DIR_METADATA b/chrome/browser/ash/file_manager/DIR_METADATA
new file mode 100644
index 0000000..e9400b87
--- /dev/null
+++ b/chrome/browser/ash/file_manager/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//ui/file_manager/COMMON_METADATA"
diff --git a/chrome/browser/ash/guest_os/COMMON_METADATA b/chrome/browser/ash/guest_os/COMMON_METADATA
new file mode 100644
index 0000000..f461eb4
--- /dev/null
+++ b/chrome/browser/ash/guest_os/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Shell>Containers"
+}
diff --git a/chrome/browser/ash/guest_os/DIR_METADATA b/chrome/browser/ash/guest_os/DIR_METADATA
index f461eb4..06e627f 100644
--- a/chrome/browser/ash/guest_os/DIR_METADATA
+++ b/chrome/browser/ash/guest_os/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Shell>Containers"
-}
+mixins: "//chrome/browser/ash/guest_os/COMMON_METADATA"
diff --git a/chrome/browser/ash/kerberos/COMMON_METADATA b/chrome/browser/ash/kerberos/COMMON_METADATA
new file mode 100644
index 0000000..688c545
--- /dev/null
+++ b/chrome/browser/ash/kerberos/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "OS>Software>Enterprise>ActiveDirectory"
+}
diff --git a/chrome/browser/ash/kerberos/DIR_METADATA b/chrome/browser/ash/kerberos/DIR_METADATA
index 688c545..3f20e21c 100644
--- a/chrome/browser/ash/kerberos/DIR_METADATA
+++ b/chrome/browser/ash/kerberos/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "OS>Software>Enterprise>ActiveDirectory"
-}
+mixins: "//chrome/browser/ash/kerberos/COMMON_METADATA"
diff --git a/chrome/browser/ash/login/app_mode/DIR_METADATA b/chrome/browser/ash/login/app_mode/DIR_METADATA
index c2d19384..7863cf59 100644
--- a/chrome/browser/ash/login/app_mode/DIR_METADATA
+++ b/chrome/browser/ash/login/app_mode/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "UI>Shell>Kiosk"
-}
+mixins: "//chrome/browser/ash/app_mode/COMMON_METADATA"
diff --git a/chrome/browser/ash/login/easy_unlock/chrome_proximity_auth_client.cc b/chrome/browser/ash/login/easy_unlock/chrome_proximity_auth_client.cc
index f95e5ac..09366d4f 100644
--- a/chrome/browser/ash/login/easy_unlock/chrome_proximity_auth_client.cc
+++ b/chrome/browser/ash/login/easy_unlock/chrome_proximity_auth_client.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/ash/device_sync/device_sync_client_factory.h"
 #include "chrome/browser/ash/login/easy_unlock/easy_unlock_service.h"
 #include "chrome/browser/ash/login/easy_unlock/easy_unlock_service_regular.h"
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin_chromeos.h"
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_window.h"
 #include "chromeos/components/multidevice/logging/logging.h"
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_notification_controller_chromeos_unittest.cc b/chrome/browser/ash/login/easy_unlock/easy_unlock_notification_controller_unittest.cc
similarity index 100%
rename from chrome/browser/ash/login/easy_unlock/easy_unlock_notification_controller_chromeos_unittest.cc
rename to chrome/browser/ash/login/easy_unlock/easy_unlock_notification_controller_unittest.cc
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_factory.cc b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_factory.cc
index 71b28da..6a2a28b 100644
--- a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_factory.cc
+++ b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_factory.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/ash/device_sync/device_sync_client_factory.h"
 #include "chrome/browser/ash/login/easy_unlock/easy_unlock_service.h"
 #include "chrome/browser/ash/login/easy_unlock/easy_unlock_service_regular.h"
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin_chromeos.h"
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin.h"
 #include "chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
 #include "chrome/browser/ash/multidevice_setup/multidevice_setup_client_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin.cc b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin.cc
new file mode 100644
index 0000000..0504f5c7
--- /dev/null
+++ b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin.cc
@@ -0,0 +1,634 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin.h"
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "ash/public/cpp/smartlock_state.h"
+#include "base/base64url.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/containers/contains.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/system/sys_info.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_challenge_wrapper.h"
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_key_manager.h"
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_metrics.h"
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager.h"
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
+#include "chrome/browser/ash/login/session/user_session_manager.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/common/pref_names.h"
+#include "chromeos/components/multidevice/logging/logging.h"
+#include "chromeos/components/multidevice/remote_device.h"
+#include "chromeos/components/multidevice/remote_device_cache.h"
+#include "chromeos/components/multidevice/remote_device_ref.h"
+#include "chromeos/components/multidevice/software_feature_state.h"
+#include "chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.h"
+#include "chromeos/components/proximity_auth/smart_lock_metrics_recorder.h"
+#include "chromeos/login/auth/user_context.h"
+#include "chromeos/login/login_state/login_state.h"
+#include "chromeos/tpm/tpm_token_loader.h"
+
+namespace ash {
+namespace {
+
+// TODO(https://crbug.com/1164001): remove after moving to ash::
+using ::chromeos::TPMTokenLoader;
+
+// The maximum allowed backoff interval when waiting for cryptohome to start.
+uint32_t kMaxCryptohomeBackoffIntervalMs = 10000u;
+
+// If the data load fails, the initial interval after which the load will be
+// retried. Further intervals will exponentially increas by factor 2.
+uint32_t kInitialCryptohomeBackoffIntervalMs = 200u;
+
+// Calculates the backoff interval that should be used next.
+// `backoff` The last backoff interval used.
+uint32_t GetNextBackoffInterval(uint32_t backoff) {
+  if (backoff == 0u)
+    return kInitialCryptohomeBackoffIntervalMs;
+  return backoff * 2;
+}
+
+void LoadDataForUser(const AccountId& account_id,
+                     uint32_t backoff_ms,
+                     EasyUnlockKeyManager::GetDeviceDataListCallback callback);
+
+// Callback passed to `LoadDataForUser()`.
+// If `LoadDataForUser` function succeeded, it invokes `callback` with the
+// results.
+// If `LoadDataForUser` failed and further retries are allowed, schedules new
+// `LoadDataForUser` call with some backoff. If no further retires are allowed,
+// it invokes `callback` with the `LoadDataForUser` results.
+void RetryDataLoadOnError(
+    const AccountId& account_id,
+    uint32_t backoff_ms,
+    EasyUnlockKeyManager::GetDeviceDataListCallback callback,
+    bool success,
+    const EasyUnlockDeviceKeyDataList& data_list) {
+  if (success) {
+    std::move(callback).Run(success, data_list);
+    return;
+  }
+
+  uint32_t next_backoff_ms = GetNextBackoffInterval(backoff_ms);
+  if (next_backoff_ms > kMaxCryptohomeBackoffIntervalMs) {
+    std::move(callback).Run(false, data_list);
+    return;
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&LoadDataForUser, account_id, next_backoff_ms,
+                     std::move(callback)),
+      base::TimeDelta::FromMilliseconds(next_backoff_ms));
+}
+
+// Loads device data list associated with the user's Easy unlock keys.
+void LoadDataForUser(const AccountId& account_id,
+                     uint32_t backoff_ms,
+                     EasyUnlockKeyManager::GetDeviceDataListCallback callback) {
+  EasyUnlockKeyManager* key_manager =
+      UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
+  DCHECK(key_manager);
+
+  const user_manager::User* const user =
+      user_manager::UserManager::Get()->FindUser(account_id);
+  DCHECK(user);
+  key_manager->GetDeviceDataList(
+      UserContext(*user), base::BindOnce(&RetryDataLoadOnError, account_id,
+                                         backoff_ms, std::move(callback)));
+}
+
+// Deserializes a vector of BeaconSeeds. If an error occurs, an empty vector
+// will be returned. Note: The logic to serialize BeaconSeeds lives in
+// EasyUnlockServiceRegular.
+// Note: The serialization of device data inside a user session is different
+// than outside the user session (sign-in). RemoteDevices are serialized as
+// protocol buffers inside the user session, but we have a custom serialization
+// scheme for sign-in due to slightly different data requirements.
+std::vector<multidevice::BeaconSeed> DeserializeBeaconSeeds(
+    const std::string& serialized_beacon_seeds) {
+  std::vector<multidevice::BeaconSeed> beacon_seeds;
+
+  JSONStringValueDeserializer deserializer(serialized_beacon_seeds);
+  std::string error;
+  std::unique_ptr<base::Value> deserialized_value =
+      deserializer.Deserialize(nullptr, &error);
+  if (!deserialized_value) {
+    PA_LOG(ERROR) << "Unable to deserialize BeaconSeeds: " << error;
+    return beacon_seeds;
+  }
+
+  if (!deserialized_value->is_list()) {
+    PA_LOG(ERROR) << "Deserialized BeaconSeeds value is not list.";
+    return beacon_seeds;
+  }
+
+  for (const base::Value& beacon_seed_value : deserialized_value->GetList()) {
+    if (!beacon_seed_value.is_string()) {
+      PA_LOG(ERROR) << "Expected Base64 BeaconSeed.";
+      continue;
+    }
+    const std::string& b64_beacon_seed = beacon_seed_value.GetString();
+
+    std::string proto_serialized_beacon_seed;
+    if (!base::Base64UrlDecode(b64_beacon_seed,
+                               base::Base64UrlDecodePolicy::REQUIRE_PADDING,
+                               &proto_serialized_beacon_seed)) {
+      PA_LOG(ERROR) << "Unable to decode BeaconSeed.";
+      continue;
+    }
+
+    cryptauth::BeaconSeed beacon_seed;
+    if (!beacon_seed.ParseFromString(proto_serialized_beacon_seed)) {
+      PA_LOG(ERROR) << "Unable to parse BeaconSeed proto.";
+      continue;
+    }
+
+    beacon_seeds.push_back(
+        chromeos::multidevice::FromCryptAuthSeed(beacon_seed));
+  }
+
+  PA_LOG(VERBOSE) << "Deserialized " << beacon_seeds.size() << " BeaconSeeds.";
+  return beacon_seeds;
+}
+
+}  // namespace
+
+EasyUnlockServiceSignin::UserData::UserData()
+    : state(EasyUnlockServiceSignin::USER_DATA_STATE_INITIAL) {}
+
+EasyUnlockServiceSignin::UserData::~UserData() {}
+
+EasyUnlockServiceSignin::EasyUnlockServiceSignin(
+    Profile* profile,
+    secure_channel::SecureChannelClient* secure_channel_client)
+    : EasyUnlockService(profile, secure_channel_client),
+      account_id_(EmptyAccountId()),
+      user_pod_last_focused_timestamp_(base::TimeTicks::Now()),
+      remote_device_cache_(multidevice::RemoteDeviceCache::Factory::Create()) {}
+
+EasyUnlockServiceSignin::~EasyUnlockServiceSignin() {}
+
+void EasyUnlockServiceSignin::WrapChallengeForUserAndDevice(
+    const AccountId& account_id,
+    const std::string& device_public_key,
+    const std::string& channel_binding_data,
+    base::OnceCallback<void(const std::string& wraped_challenge)> callback) {
+  auto it = user_data_.find(account_id);
+  if (it == user_data_.end() || it->second->state != USER_DATA_STATE_LOADED) {
+    PA_LOG(ERROR) << "TPM data not loaded for " << account_id.Serialize();
+    std::move(callback).Run(std::string());
+    return;
+  }
+
+  std::string device_public_key_base64;
+  base::Base64UrlEncode(device_public_key,
+                        base::Base64UrlEncodePolicy::INCLUDE_PADDING,
+                        &device_public_key_base64);
+  for (const auto& device_data : it->second->devices) {
+    if (device_data.public_key == device_public_key_base64) {
+      PA_LOG(VERBOSE) << "Wrapping challenge for " << account_id.Serialize()
+                      << "...";
+      challenge_wrapper_ = std::make_unique<EasyUnlockChallengeWrapper>(
+          device_data.challenge, channel_binding_data, account_id,
+          EasyUnlockTpmKeyManagerFactory::GetInstance()->Get(profile()));
+      challenge_wrapper_->WrapChallenge(std::move(callback));
+      return;
+    }
+  }
+
+  PA_LOG(ERROR) << "Unable to find device record for "
+                << account_id.Serialize();
+  std::move(callback).Run(std::string());
+}
+
+proximity_auth::ProximityAuthPrefManager*
+EasyUnlockServiceSignin::GetProximityAuthPrefManager() {
+  return pref_manager_.get();
+}
+
+EasyUnlockService::Type EasyUnlockServiceSignin::GetType() const {
+  return EasyUnlockService::TYPE_SIGNIN;
+}
+
+AccountId EasyUnlockServiceSignin::GetAccountId() const {
+  return account_id_;
+}
+
+const base::ListValue* EasyUnlockServiceSignin::GetRemoteDevices() const {
+  const UserData* data = FindLoadedDataForCurrentUser();
+  if (!data)
+    return nullptr;
+  return &data->remote_devices_value;
+}
+
+std::string EasyUnlockServiceSignin::GetChallenge() const {
+  const UserData* data = FindLoadedDataForCurrentUser();
+  if (!data)
+    return std::string();
+
+  for (const auto& device : data->devices) {
+    if (device.unlock_key)
+      return device.challenge;
+  }
+
+  return std::string();
+}
+
+std::string EasyUnlockServiceSignin::GetWrappedSecret() const {
+  const UserData* data = FindLoadedDataForCurrentUser();
+  if (!data)
+    return std::string();
+
+  for (const auto& device : data->devices) {
+    if (device.unlock_key)
+      return device.wrapped_secret;
+  }
+
+  return std::string();
+}
+
+void EasyUnlockServiceSignin::RecordEasySignInOutcome(
+    const AccountId& account_id,
+    bool success) const {
+  DCHECK(GetAccountId() == account_id)
+      << "GetAccountId()=" << GetAccountId().Serialize()
+      << " != account_id=" << account_id.Serialize();
+
+  RecordEasyUnlockSigninEvent(success ? EASY_UNLOCK_SUCCESS
+                                      : EASY_UNLOCK_FAILURE);
+  if (success) {
+    RecordEasyUnlockSigninDuration(base::TimeTicks::Now() -
+                                   user_pod_last_focused_timestamp_);
+  }
+  DVLOG(1) << "Easy sign-in " << (success ? "success" : "failure");
+}
+
+void EasyUnlockServiceSignin::RecordPasswordLoginEvent(
+    const AccountId& account_id) const {
+  // This happens during tests, where a user could log in without the user pod
+  // being focused.
+  if (GetAccountId() != account_id)
+    return;
+
+  if (!IsEnabled())
+    return;
+
+  EasyUnlockAuthEvent event = GetPasswordAuthEvent();
+  RecordEasyUnlockSigninEvent(event);
+
+  SmartLockMetricsRecorder::RecordAuthMethodChoiceSignInPasswordState(
+      GetSmartUnlockPasswordAuthEvent());
+
+  DVLOG(1) << "Easy Sign-in password login event, event=" << event;
+}
+
+void EasyUnlockServiceSignin::InitializeInternal() {
+  if (LoginState::Get()->IsUserLoggedIn())
+    return;
+
+  service_active_ = true;
+
+  pref_manager_ =
+      std::make_unique<proximity_auth::ProximityAuthLocalStatePrefManager>(
+          g_browser_process->local_state());
+
+  proximity_auth::ScreenlockBridge* screenlock_bridge =
+      proximity_auth::ScreenlockBridge::Get();
+  screenlock_bridge->AddObserver(this);
+  if (screenlock_bridge->focused_account_id().is_valid())
+    OnFocusedUserChanged(screenlock_bridge->focused_account_id());
+}
+
+void EasyUnlockServiceSignin::ShutdownInternal() {
+  if (!service_active_)
+    return;
+  service_active_ = false;
+
+  remote_device_cache_.reset();
+  challenge_wrapper_.reset();
+  pref_manager_.reset();
+
+  weak_ptr_factory_.InvalidateWeakPtrs();
+  proximity_auth::ScreenlockBridge::Get()->RemoveObserver(this);
+  user_data_.clear();
+}
+
+bool EasyUnlockServiceSignin::IsAllowedInternal() const {
+  return service_active_ && account_id_.is_valid() &&
+         !LoginState::Get()->IsUserLoggedIn() &&
+         (pref_manager_ && pref_manager_->IsEasyUnlockAllowed() &&
+          pref_manager_->IsChromeOSLoginAllowed());
+}
+
+bool EasyUnlockServiceSignin::IsEnabled() const {
+  return pref_manager_ && pref_manager_->IsEasyUnlockEnabled();
+}
+
+bool EasyUnlockServiceSignin::IsChromeOSLoginEnabled() const {
+  return pref_manager_ && pref_manager_->IsChromeOSLoginEnabled();
+}
+
+void EasyUnlockServiceSignin::OnSuspendDoneInternal() {
+  // Ignored.
+}
+
+void EasyUnlockServiceSignin::OnScreenDidLock(
+    proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
+  // In production code, the screen type should always be the signin screen; but
+  // in tests, the screen type might be different.
+  if (screen_type !=
+      proximity_auth::ScreenlockBridge::LockHandler::SIGNIN_SCREEN)
+    return;
+
+  // Update initial UI is when the account picker on login screen is ready.
+  ShowInitialUserPodState();
+  user_pod_last_focused_timestamp_ = base::TimeTicks::Now();
+}
+
+void EasyUnlockServiceSignin::OnScreenDidUnlock(
+    proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
+  // In production code, the screen type should always be the signin screen; but
+  // in tests, the screen type might be different.
+  if (screen_type !=
+      proximity_auth::ScreenlockBridge::LockHandler::SIGNIN_SCREEN)
+    return;
+
+  // TODO(crbug.com/1171972): Deprecate this metric. Note also that checking
+  // IsEnabled() here often incorrectly returns false, because
+  // OnScreenDidUnlock() is occurring during user session startup. See
+  // https://crbug.com/1154766 for more.
+  if (IsEnabled()) {
+    SmartLockMetricsRecorder::RecordSmartLockSignInAuthMethodChoice(
+        will_authenticate_using_easy_unlock()
+            ? SmartLockMetricsRecorder::SmartLockAuthMethodChoice::kSmartLock
+            : SmartLockMetricsRecorder::SmartLockAuthMethodChoice::kOther);
+  }
+
+  // TODO(crbug.com/972156): A KeyedService shutting itself seems dangerous;
+  // look into other ways to "reset state" besides this.
+  Shutdown();
+}
+
+void EasyUnlockServiceSignin::OnFocusedUserChanged(
+    const AccountId& account_id) {
+  if (account_id_ == account_id)
+    return;
+
+  // Even if |pref_manager_| is not present, continue resetting state for
+  // |account_id| below. The function will return once IsAllowed() below
+  // returns false (because |pref_manager_| is not present).
+  if (pref_manager_) {
+    pref_manager_->SetActiveUser(account_id);
+  }
+
+  account_id_ = account_id;
+  user_pod_last_focused_timestamp_ = base::TimeTicks::Now();
+  SetProximityAuthDevices(account_id_, multidevice::RemoteDeviceRefList(),
+                          absl::nullopt /* local_device */);
+  ResetSmartLockState();
+
+  // Changing the "Active User" above changes the return values of IsAllowed()
+  // and IsEnabled() below.
+  if (!IsAllowed() || !IsEnabled())
+    return;
+
+  ShowInitialUserPodState();
+
+  // If there is a hardlock, then there is no point in loading the devices.
+  SmartLockStateHandler::HardlockState hardlock_state;
+  if (GetPersistedHardlockState(&hardlock_state) &&
+      hardlock_state != SmartLockStateHandler::NO_HARDLOCK) {
+    PA_LOG(VERBOSE) << "Hardlock present, skipping remaining login flow.";
+    return;
+  }
+
+  UpdateAppState();
+  LoadCurrentUserDataIfNeeded();
+
+  // Start loading TPM system token.
+  // The system token will be needed to sign a nonce using TPM private key
+  // during the sign-in protocol.
+  TPMTokenLoader::Get()->EnsureStarted();
+}
+
+void EasyUnlockServiceSignin::LoadCurrentUserDataIfNeeded() {
+  // TODO(xiyuan): Revisit this when adding tests.
+  if (!base::SysInfo::IsRunningOnChromeOS())
+    return;
+
+  if (!account_id_.is_valid() || !service_active_)
+    return;
+
+  const auto it = user_data_.find(account_id_);
+  if (it == user_data_.end())
+    user_data_.insert(
+        std::make_pair(account_id_, std::make_unique<UserData>()));
+
+  UserData* data = user_data_[account_id_].get();
+
+  if (data->state == USER_DATA_STATE_LOADING)
+    return;
+  data->state = USER_DATA_STATE_LOADING;
+
+  LoadDataForUser(
+      account_id_,
+      allow_cryptohome_backoff_ ? 0u : kMaxCryptohomeBackoffIntervalMs,
+      base::BindOnce(&EasyUnlockServiceSignin::OnUserDataLoaded,
+                     weak_ptr_factory_.GetWeakPtr(), account_id_));
+}
+
+// TODO(crbug.com/856387): Write tests for device retrieval from the TPM.
+void EasyUnlockServiceSignin::OnUserDataLoaded(
+    const AccountId& account_id,
+    bool success,
+    const EasyUnlockDeviceKeyDataList& devices) {
+  allow_cryptohome_backoff_ = false;
+
+  UserData* data = user_data_[account_id].get();
+  data->state = USER_DATA_STATE_LOADED;
+  if (success) {
+    data->devices = devices;
+    EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList(
+        account_id, devices, &data->remote_devices_value);
+
+    // User could have a NO_HARDLOCK state but has no remote devices if
+    // previous user session shuts down before
+    // CheckCryptohomeKeysAndMaybeHardlock finishes. Set NO_PAIRING state
+    // and update UI to remove the confusing spinner in this case.
+    SmartLockStateHandler::HardlockState hardlock_state;
+    if (devices.empty() && GetPersistedHardlockState(&hardlock_state) &&
+        hardlock_state == SmartLockStateHandler::NO_HARDLOCK) {
+      SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
+    }
+  }
+
+  if (devices.empty())
+    return;
+
+  multidevice::RemoteDeviceList remote_devices;
+  for (const auto& device : devices) {
+    std::string decoded_public_key, decoded_psk;
+    if (!base::Base64UrlDecode(device.public_key,
+                               base::Base64UrlDecodePolicy::REQUIRE_PADDING,
+                               &decoded_public_key) ||
+        !base::Base64UrlDecode(device.psk,
+                               base::Base64UrlDecodePolicy::REQUIRE_PADDING,
+                               &decoded_psk)) {
+      PA_LOG(ERROR) << "Unable to decode stored remote device:\n"
+                    << "  public_key: " << device.public_key << "\n"
+                    << "  psk: " << device.psk;
+      continue;
+    }
+
+    std::map<multidevice::SoftwareFeature, multidevice::SoftwareFeatureState>
+        software_features;
+    software_features[multidevice::SoftwareFeature::kSmartLockHost] =
+        device.unlock_key ? multidevice::SoftwareFeatureState::kEnabled
+                          : multidevice::SoftwareFeatureState::kNotSupported;
+
+    std::vector<multidevice::BeaconSeed> beacon_seeds;
+    if (!device.serialized_beacon_seeds.empty()) {
+      PA_LOG(VERBOSE) << "Deserializing BeaconSeeds: "
+                      << device.serialized_beacon_seeds;
+      beacon_seeds = DeserializeBeaconSeeds(device.serialized_beacon_seeds);
+    } else {
+      PA_LOG(WARNING) << "No BeaconSeeds were loaded.";
+    }
+
+    // Values such as the `instance_id` and `name` of the device are not
+    // provided in the device dictionary that is persisted to the TPM during the
+    // user session. However, in this particular scenario, we do not need these
+    // values to safely construct and use the RemoteDevice objects.
+    multidevice::RemoteDevice remote_device(
+        account_id.GetUserEmail(), std::string() /* instance_id */,
+        std::string() /* name */, std::string() /* pii_free_name */,
+        decoded_public_key, decoded_psk /* persistent_symmetric_key */,
+        0L /* last_update_time_millis */, software_features, beacon_seeds,
+        std::string() /* bluetooth_public_address */);
+
+    remote_devices.push_back(remote_device);
+    PA_LOG(VERBOSE) << "Loaded Remote Device:\n"
+                    << "  user email: " << remote_device.user_email << "\n"
+                    << "  device id: "
+                    << multidevice::RemoteDeviceRef::TruncateDeviceIdForLogs(
+                           remote_device.GetDeviceId());
+  }
+
+  // Both a remote device and local device are expected, and this service cannot
+  // continue unless both are present.
+  // TODO(crbug.com/856380): The remote and local devices need to be passed in a
+  // less hacky way.
+  if (remote_devices.size() > 2u) {
+    PA_LOG(ERROR)
+        << "Expected a device list of size 1 or 2, received list of size "
+        << remote_devices.size();
+    SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
+    return;
+  }
+
+  if (remote_devices.size() != 2u) {
+    PA_LOG(ERROR) << "Expected a device list of size 2, received list of size "
+                  << remote_devices.size();
+    SetHardlockStateForUser(account_id, SmartLockStateHandler::PAIRING_CHANGED);
+    return;
+  }
+
+  std::string unlock_key_id;
+  // This may be left unset if the local device was not passed along.
+  std::string local_device_id;
+
+  for (const auto& remote_device : remote_devices) {
+    if (base::Contains(remote_device.software_features,
+                       multidevice::SoftwareFeature::kSmartLockHost) &&
+        remote_device.software_features.at(
+            multidevice::SoftwareFeature::kSmartLockHost) ==
+            multidevice::SoftwareFeatureState::kEnabled) {
+      if (!unlock_key_id.empty()) {
+        PA_LOG(ERROR) << "Only one of the devices should be an unlock key.";
+        SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
+        return;
+      }
+
+      unlock_key_id = remote_device.GetDeviceId();
+    } else {
+      if (!local_device_id.empty()) {
+        PA_LOG(ERROR) << "Only one of the devices should be the local device.";
+        SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
+        return;
+      }
+
+      local_device_id = remote_device.GetDeviceId();
+    }
+  }
+
+  remote_device_cache_->SetRemoteDevices(remote_devices);
+
+  absl::optional<multidevice::RemoteDeviceRef> unlock_key_device =
+      remote_device_cache_->GetRemoteDevice(
+          absl::nullopt /* instance_id */,
+          unlock_key_id /* legacy_device_id */);
+  absl::optional<multidevice::RemoteDeviceRef> local_device =
+      remote_device_cache_->GetRemoteDevice(
+          absl::nullopt /* instance_id */,
+          local_device_id /* legacy_device_id */);
+
+  // TODO(hansberry): It is possible that there may not be an unlock key by this
+  // point. If this occurs, it is due to a bug in how device metadata is
+  // persisted in CryptoHome. See https://crbug.com/856380 for more details. For
+  // now, simply return early here to prevent a potential crash which can occur
+  // in this situation (see https://crbug.com/866711).
+  if (!unlock_key_device) {
+    SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
+    return;
+  }
+
+  if (!local_device) {
+    SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
+    return;
+  }
+
+  SetProximityAuthDevices(account_id, {*unlock_key_device}, local_device);
+}
+
+const EasyUnlockServiceSignin::UserData*
+EasyUnlockServiceSignin::FindLoadedDataForCurrentUser() const {
+  if (!account_id_.is_valid())
+    return nullptr;
+
+  const auto it = user_data_.find(account_id_);
+  if (it == user_data_.end())
+    return nullptr;
+  if (it->second->state != USER_DATA_STATE_LOADED)
+    return nullptr;
+  return it->second.get();
+}
+
+void EasyUnlockServiceSignin::ShowInitialUserPodState() {
+  if (!IsAllowed() || !IsEnabled())
+    return;
+
+  if (!pref_manager_->IsChromeOSLoginEnabled()) {
+    // Show a hardlock state if the user has not enabled Smart Lock to the log
+    // in to the user's Google account.
+    SetHardlockStateForUser(account_id_, SmartLockStateHandler::LOGIN_DISABLED);
+  } else {
+    // This UI is simply a placeholder until the RemoteDevices are loaded from
+    // cryptohome and the ProximityAuthSystem is started. Hardlock states are
+    // automatically taken into account.
+    UpdateSmartLockState(SmartLockState::kConnectingToPhone);
+  }
+}
+
+}  // namespace ash
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin.h b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin.h
new file mode 100644
index 0000000..b923ba6
--- /dev/null
+++ b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin.h
@@ -0,0 +1,164 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_SIGNIN_H_
+#define CHROME_BROWSER_ASH_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_SIGNIN_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_service.h"
+#include "chrome/browser/ash/login/easy_unlock/easy_unlock_types.h"
+// TODO(https://crbug.com/1164001): move to forward declaration
+#include "chromeos/components/multidevice/remote_device_cache.h"
+#include "chromeos/components/proximity_auth/screenlock_bridge.h"
+// TODO(https://crbug.com/1164001): move to forward declaration
+#include "chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h"
+
+namespace proximity_auth {
+class ProximityAuthLocalStatePrefManager;
+}  // namespace proximity_auth
+
+namespace ash {
+class EasyUnlockChallengeWrapper;
+
+// EasyUnlockService instance that should be used for signin profile.
+class EasyUnlockServiceSignin
+    : public EasyUnlockService,
+      public proximity_auth::ScreenlockBridge::Observer {
+ public:
+  EasyUnlockServiceSignin(
+      Profile* profile,
+      secure_channel::SecureChannelClient* secure_channel_client);
+
+  EasyUnlockServiceSignin(const EasyUnlockServiceSignin&) = delete;
+  EasyUnlockServiceSignin& operator=(const EasyUnlockServiceSignin&) = delete;
+
+  ~EasyUnlockServiceSignin() override;
+
+  // Wraps the challenge for the remote device identified by `account_id` and
+  // the
+  // `device_public_key`. The `channel_binding_data` is signed by the TPM
+  // included in the wrapped challenge.
+  // `callback` will be invoked when wrapping is complete. If the user data is
+  // not loaded yet, then `callback` will be invoked with an empty string.
+  void WrapChallengeForUserAndDevice(
+      const AccountId& account_id,
+      const std::string& device_public_key,
+      const std::string& channel_binding_data,
+      base::OnceCallback<void(const std::string& wraped_challenge)> callback);
+
+ private:
+  // The load state of a user's cryptohome key data.
+  enum UserDataState {
+    // Initial state, the key data is empty and not being loaded.
+    USER_DATA_STATE_INITIAL,
+    // The key data is empty, but being loaded.
+    USER_DATA_STATE_LOADING,
+    // The key data has been loaded.
+    USER_DATA_STATE_LOADED
+  };
+
+  // Structure containing a user's key data loaded from cryptohome.
+  struct UserData {
+    UserData();
+
+    UserData(const UserData&) = delete;
+    UserData& operator=(const UserData&) = delete;
+
+    ~UserData();
+
+    // The loading state of the data.
+    UserDataState state;
+
+    // The data as returned from cryptohome.
+    EasyUnlockDeviceKeyDataList devices;
+
+    // The list of remote device dictionaries understood by Easy unlock app.
+    // This will be returned by `GetRemoteDevices` method.
+    base::ListValue remote_devices_value;
+  };
+
+  // EasyUnlockService implementation:
+  proximity_auth::ProximityAuthPrefManager* GetProximityAuthPrefManager()
+      override;
+  EasyUnlockService::Type GetType() const override;
+  AccountId GetAccountId() const override;
+  const base::ListValue* GetRemoteDevices() const override;
+  std::string GetChallenge() const override;
+  std::string GetWrappedSecret() const override;
+  void RecordEasySignInOutcome(const AccountId& account_id,
+                               bool success) const override;
+  void RecordPasswordLoginEvent(const AccountId& account_id) const override;
+  void InitializeInternal() override;
+  void ShutdownInternal() override;
+  bool IsAllowedInternal() const override;
+  bool IsEnabled() const override;
+  bool IsChromeOSLoginEnabled() const override;
+  void OnSuspendDoneInternal() override;
+
+  // proximity_auth::ScreenlockBridge::Observer implementation:
+  void OnScreenDidLock(proximity_auth::ScreenlockBridge::LockHandler::ScreenType
+                           screen_type) override;
+  void OnScreenDidUnlock(
+      proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type)
+      override;
+  void OnFocusedUserChanged(const AccountId& account_id) override;
+
+  // Loads the device data associated with the user's Easy unlock keys from
+  // crypthome.
+  void LoadCurrentUserDataIfNeeded();
+
+  // Callback invoked when the user's device data is loaded from cryptohome.
+  void OnUserDataLoaded(const AccountId& account_id,
+                        bool success,
+                        const EasyUnlockDeviceKeyDataList& data);
+
+  // If the device data has been loaded for the current user, returns it.
+  // Otherwise, returns NULL.
+  const UserData* FindLoadedDataForCurrentUser() const;
+
+  // Shows the hardlock or connecting state as initial UI before cryptohome
+  // keys checking and state update from the app.
+  void ShowInitialUserPodState();
+
+  // User id of the user currently associated with the service.
+  AccountId account_id_;
+
+  // Maps account ids to their fetched cryptohome key data.
+  std::map<AccountId, std::unique_ptr<UserData>> user_data_;
+
+  // Whether failed attempts to load user data should be retried.
+  // This is to handle case where cryptohome daemon is not started in time the
+  // service attempts to load some data. Retries will be allowed only until the
+  // first data load finishes (even if it fails).
+  bool allow_cryptohome_backoff_ = true;
+
+  // Whether the service has been successfully initialized, and has not been
+  // shut down.
+  bool service_active_ = false;
+
+  // The timestamp for the most recent time when a user pod was focused.
+  base::TimeTicks user_pod_last_focused_timestamp_;
+
+  std::unique_ptr<multidevice::RemoteDeviceCache> remote_device_cache_;
+
+  // Handles wrapping the user's challenge with the TPM.
+  std::unique_ptr<EasyUnlockChallengeWrapper> challenge_wrapper_;
+
+  // Manages the EasyUnlock prefs for the local state.
+  std::unique_ptr<proximity_auth::ProximityAuthLocalStatePrefManager>
+      pref_manager_;
+
+  base::WeakPtrFactory<EasyUnlockServiceSignin> weak_ptr_factory_{this};
+};
+
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_ASH_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_SIGNIN_H_
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin_chromeos.cc b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin_chromeos.cc
deleted file mode 100644
index c61a5ab0..0000000
--- a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin_chromeos.cc
+++ /dev/null
@@ -1,634 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin_chromeos.h"
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "ash/public/cpp/smartlock_state.h"
-#include "base/base64url.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/containers/contains.h"
-#include "base/json/json_string_value_serializer.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/system/sys_info.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_challenge_wrapper.h"
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_key_manager.h"
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_metrics.h"
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager.h"
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
-#include "chrome/browser/ash/login/session/user_session_manager.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/common/pref_names.h"
-#include "chromeos/components/multidevice/logging/logging.h"
-#include "chromeos/components/multidevice/remote_device.h"
-#include "chromeos/components/multidevice/remote_device_cache.h"
-#include "chromeos/components/multidevice/remote_device_ref.h"
-#include "chromeos/components/multidevice/software_feature_state.h"
-#include "chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.h"
-#include "chromeos/components/proximity_auth/smart_lock_metrics_recorder.h"
-#include "chromeos/login/auth/user_context.h"
-#include "chromeos/login/login_state/login_state.h"
-#include "chromeos/tpm/tpm_token_loader.h"
-
-namespace ash {
-namespace {
-
-// TODO(https://crbug.com/1164001): remove after moving to ash::
-using ::chromeos::TPMTokenLoader;
-
-// The maximum allowed backoff interval when waiting for cryptohome to start.
-uint32_t kMaxCryptohomeBackoffIntervalMs = 10000u;
-
-// If the data load fails, the initial interval after which the load will be
-// retried. Further intervals will exponentially increas by factor 2.
-uint32_t kInitialCryptohomeBackoffIntervalMs = 200u;
-
-// Calculates the backoff interval that should be used next.
-// `backoff` The last backoff interval used.
-uint32_t GetNextBackoffInterval(uint32_t backoff) {
-  if (backoff == 0u)
-    return kInitialCryptohomeBackoffIntervalMs;
-  return backoff * 2;
-}
-
-void LoadDataForUser(const AccountId& account_id,
-                     uint32_t backoff_ms,
-                     EasyUnlockKeyManager::GetDeviceDataListCallback callback);
-
-// Callback passed to `LoadDataForUser()`.
-// If `LoadDataForUser` function succeeded, it invokes `callback` with the
-// results.
-// If `LoadDataForUser` failed and further retries are allowed, schedules new
-// `LoadDataForUser` call with some backoff. If no further retires are allowed,
-// it invokes `callback` with the `LoadDataForUser` results.
-void RetryDataLoadOnError(
-    const AccountId& account_id,
-    uint32_t backoff_ms,
-    EasyUnlockKeyManager::GetDeviceDataListCallback callback,
-    bool success,
-    const EasyUnlockDeviceKeyDataList& data_list) {
-  if (success) {
-    std::move(callback).Run(success, data_list);
-    return;
-  }
-
-  uint32_t next_backoff_ms = GetNextBackoffInterval(backoff_ms);
-  if (next_backoff_ms > kMaxCryptohomeBackoffIntervalMs) {
-    std::move(callback).Run(false, data_list);
-    return;
-  }
-
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&LoadDataForUser, account_id, next_backoff_ms,
-                     std::move(callback)),
-      base::TimeDelta::FromMilliseconds(next_backoff_ms));
-}
-
-// Loads device data list associated with the user's Easy unlock keys.
-void LoadDataForUser(const AccountId& account_id,
-                     uint32_t backoff_ms,
-                     EasyUnlockKeyManager::GetDeviceDataListCallback callback) {
-  EasyUnlockKeyManager* key_manager =
-      UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
-  DCHECK(key_manager);
-
-  const user_manager::User* const user =
-      user_manager::UserManager::Get()->FindUser(account_id);
-  DCHECK(user);
-  key_manager->GetDeviceDataList(
-      UserContext(*user), base::BindOnce(&RetryDataLoadOnError, account_id,
-                                         backoff_ms, std::move(callback)));
-}
-
-// Deserializes a vector of BeaconSeeds. If an error occurs, an empty vector
-// will be returned. Note: The logic to serialize BeaconSeeds lives in
-// EasyUnlockServiceRegular.
-// Note: The serialization of device data inside a user session is different
-// than outside the user session (sign-in). RemoteDevices are serialized as
-// protocol buffers inside the user session, but we have a custom serialization
-// scheme for sign-in due to slightly different data requirements.
-std::vector<multidevice::BeaconSeed> DeserializeBeaconSeeds(
-    const std::string& serialized_beacon_seeds) {
-  std::vector<multidevice::BeaconSeed> beacon_seeds;
-
-  JSONStringValueDeserializer deserializer(serialized_beacon_seeds);
-  std::string error;
-  std::unique_ptr<base::Value> deserialized_value =
-      deserializer.Deserialize(nullptr, &error);
-  if (!deserialized_value) {
-    PA_LOG(ERROR) << "Unable to deserialize BeaconSeeds: " << error;
-    return beacon_seeds;
-  }
-
-  if (!deserialized_value->is_list()) {
-    PA_LOG(ERROR) << "Deserialized BeaconSeeds value is not list.";
-    return beacon_seeds;
-  }
-
-  for (const base::Value& beacon_seed_value : deserialized_value->GetList()) {
-    if (!beacon_seed_value.is_string()) {
-      PA_LOG(ERROR) << "Expected Base64 BeaconSeed.";
-      continue;
-    }
-    const std::string& b64_beacon_seed = beacon_seed_value.GetString();
-
-    std::string proto_serialized_beacon_seed;
-    if (!base::Base64UrlDecode(b64_beacon_seed,
-                               base::Base64UrlDecodePolicy::REQUIRE_PADDING,
-                               &proto_serialized_beacon_seed)) {
-      PA_LOG(ERROR) << "Unable to decode BeaconSeed.";
-      continue;
-    }
-
-    cryptauth::BeaconSeed beacon_seed;
-    if (!beacon_seed.ParseFromString(proto_serialized_beacon_seed)) {
-      PA_LOG(ERROR) << "Unable to parse BeaconSeed proto.";
-      continue;
-    }
-
-    beacon_seeds.push_back(
-        chromeos::multidevice::FromCryptAuthSeed(beacon_seed));
-  }
-
-  PA_LOG(VERBOSE) << "Deserialized " << beacon_seeds.size() << " BeaconSeeds.";
-  return beacon_seeds;
-}
-
-}  // namespace
-
-EasyUnlockServiceSignin::UserData::UserData()
-    : state(EasyUnlockServiceSignin::USER_DATA_STATE_INITIAL) {}
-
-EasyUnlockServiceSignin::UserData::~UserData() {}
-
-EasyUnlockServiceSignin::EasyUnlockServiceSignin(
-    Profile* profile,
-    secure_channel::SecureChannelClient* secure_channel_client)
-    : EasyUnlockService(profile, secure_channel_client),
-      account_id_(EmptyAccountId()),
-      user_pod_last_focused_timestamp_(base::TimeTicks::Now()),
-      remote_device_cache_(multidevice::RemoteDeviceCache::Factory::Create()) {}
-
-EasyUnlockServiceSignin::~EasyUnlockServiceSignin() {}
-
-void EasyUnlockServiceSignin::WrapChallengeForUserAndDevice(
-    const AccountId& account_id,
-    const std::string& device_public_key,
-    const std::string& channel_binding_data,
-    base::OnceCallback<void(const std::string& wraped_challenge)> callback) {
-  auto it = user_data_.find(account_id);
-  if (it == user_data_.end() || it->second->state != USER_DATA_STATE_LOADED) {
-    PA_LOG(ERROR) << "TPM data not loaded for " << account_id.Serialize();
-    std::move(callback).Run(std::string());
-    return;
-  }
-
-  std::string device_public_key_base64;
-  base::Base64UrlEncode(device_public_key,
-                        base::Base64UrlEncodePolicy::INCLUDE_PADDING,
-                        &device_public_key_base64);
-  for (const auto& device_data : it->second->devices) {
-    if (device_data.public_key == device_public_key_base64) {
-      PA_LOG(VERBOSE) << "Wrapping challenge for " << account_id.Serialize()
-                      << "...";
-      challenge_wrapper_ = std::make_unique<EasyUnlockChallengeWrapper>(
-          device_data.challenge, channel_binding_data, account_id,
-          EasyUnlockTpmKeyManagerFactory::GetInstance()->Get(profile()));
-      challenge_wrapper_->WrapChallenge(std::move(callback));
-      return;
-    }
-  }
-
-  PA_LOG(ERROR) << "Unable to find device record for "
-                << account_id.Serialize();
-  std::move(callback).Run(std::string());
-}
-
-proximity_auth::ProximityAuthPrefManager*
-EasyUnlockServiceSignin::GetProximityAuthPrefManager() {
-  return pref_manager_.get();
-}
-
-EasyUnlockService::Type EasyUnlockServiceSignin::GetType() const {
-  return EasyUnlockService::TYPE_SIGNIN;
-}
-
-AccountId EasyUnlockServiceSignin::GetAccountId() const {
-  return account_id_;
-}
-
-const base::ListValue* EasyUnlockServiceSignin::GetRemoteDevices() const {
-  const UserData* data = FindLoadedDataForCurrentUser();
-  if (!data)
-    return nullptr;
-  return &data->remote_devices_value;
-}
-
-std::string EasyUnlockServiceSignin::GetChallenge() const {
-  const UserData* data = FindLoadedDataForCurrentUser();
-  if (!data)
-    return std::string();
-
-  for (const auto& device : data->devices) {
-    if (device.unlock_key)
-      return device.challenge;
-  }
-
-  return std::string();
-}
-
-std::string EasyUnlockServiceSignin::GetWrappedSecret() const {
-  const UserData* data = FindLoadedDataForCurrentUser();
-  if (!data)
-    return std::string();
-
-  for (const auto& device : data->devices) {
-    if (device.unlock_key)
-      return device.wrapped_secret;
-  }
-
-  return std::string();
-}
-
-void EasyUnlockServiceSignin::RecordEasySignInOutcome(
-    const AccountId& account_id,
-    bool success) const {
-  DCHECK(GetAccountId() == account_id)
-      << "GetAccountId()=" << GetAccountId().Serialize()
-      << " != account_id=" << account_id.Serialize();
-
-  RecordEasyUnlockSigninEvent(success ? EASY_UNLOCK_SUCCESS
-                                      : EASY_UNLOCK_FAILURE);
-  if (success) {
-    RecordEasyUnlockSigninDuration(base::TimeTicks::Now() -
-                                   user_pod_last_focused_timestamp_);
-  }
-  DVLOG(1) << "Easy sign-in " << (success ? "success" : "failure");
-}
-
-void EasyUnlockServiceSignin::RecordPasswordLoginEvent(
-    const AccountId& account_id) const {
-  // This happens during tests, where a user could log in without the user pod
-  // being focused.
-  if (GetAccountId() != account_id)
-    return;
-
-  if (!IsEnabled())
-    return;
-
-  EasyUnlockAuthEvent event = GetPasswordAuthEvent();
-  RecordEasyUnlockSigninEvent(event);
-
-  SmartLockMetricsRecorder::RecordAuthMethodChoiceSignInPasswordState(
-      GetSmartUnlockPasswordAuthEvent());
-
-  DVLOG(1) << "Easy Sign-in password login event, event=" << event;
-}
-
-void EasyUnlockServiceSignin::InitializeInternal() {
-  if (LoginState::Get()->IsUserLoggedIn())
-    return;
-
-  service_active_ = true;
-
-  pref_manager_ =
-      std::make_unique<proximity_auth::ProximityAuthLocalStatePrefManager>(
-          g_browser_process->local_state());
-
-  proximity_auth::ScreenlockBridge* screenlock_bridge =
-      proximity_auth::ScreenlockBridge::Get();
-  screenlock_bridge->AddObserver(this);
-  if (screenlock_bridge->focused_account_id().is_valid())
-    OnFocusedUserChanged(screenlock_bridge->focused_account_id());
-}
-
-void EasyUnlockServiceSignin::ShutdownInternal() {
-  if (!service_active_)
-    return;
-  service_active_ = false;
-
-  remote_device_cache_.reset();
-  challenge_wrapper_.reset();
-  pref_manager_.reset();
-
-  weak_ptr_factory_.InvalidateWeakPtrs();
-  proximity_auth::ScreenlockBridge::Get()->RemoveObserver(this);
-  user_data_.clear();
-}
-
-bool EasyUnlockServiceSignin::IsAllowedInternal() const {
-  return service_active_ && account_id_.is_valid() &&
-         !LoginState::Get()->IsUserLoggedIn() &&
-         (pref_manager_ && pref_manager_->IsEasyUnlockAllowed() &&
-          pref_manager_->IsChromeOSLoginAllowed());
-}
-
-bool EasyUnlockServiceSignin::IsEnabled() const {
-  return pref_manager_ && pref_manager_->IsEasyUnlockEnabled();
-}
-
-bool EasyUnlockServiceSignin::IsChromeOSLoginEnabled() const {
-  return pref_manager_ && pref_manager_->IsChromeOSLoginEnabled();
-}
-
-void EasyUnlockServiceSignin::OnSuspendDoneInternal() {
-  // Ignored.
-}
-
-void EasyUnlockServiceSignin::OnScreenDidLock(
-    proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
-  // In production code, the screen type should always be the signin screen; but
-  // in tests, the screen type might be different.
-  if (screen_type !=
-      proximity_auth::ScreenlockBridge::LockHandler::SIGNIN_SCREEN)
-    return;
-
-  // Update initial UI is when the account picker on login screen is ready.
-  ShowInitialUserPodState();
-  user_pod_last_focused_timestamp_ = base::TimeTicks::Now();
-}
-
-void EasyUnlockServiceSignin::OnScreenDidUnlock(
-    proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) {
-  // In production code, the screen type should always be the signin screen; but
-  // in tests, the screen type might be different.
-  if (screen_type !=
-      proximity_auth::ScreenlockBridge::LockHandler::SIGNIN_SCREEN)
-    return;
-
-  // TODO(crbug.com/1171972): Deprecate this metric. Note also that checking
-  // IsEnabled() here often incorrectly returns false, because
-  // OnScreenDidUnlock() is occurring during user session startup. See
-  // https://crbug.com/1154766 for more.
-  if (IsEnabled()) {
-    SmartLockMetricsRecorder::RecordSmartLockSignInAuthMethodChoice(
-        will_authenticate_using_easy_unlock()
-            ? SmartLockMetricsRecorder::SmartLockAuthMethodChoice::kSmartLock
-            : SmartLockMetricsRecorder::SmartLockAuthMethodChoice::kOther);
-  }
-
-  // TODO(crbug.com/972156): A KeyedService shutting itself seems dangerous;
-  // look into other ways to "reset state" besides this.
-  Shutdown();
-}
-
-void EasyUnlockServiceSignin::OnFocusedUserChanged(
-    const AccountId& account_id) {
-  if (account_id_ == account_id)
-    return;
-
-  // Even if |pref_manager_| is not present, continue resetting state for
-  // |account_id| below. The function will return once IsAllowed() below
-  // returns false (because |pref_manager_| is not present).
-  if (pref_manager_) {
-    pref_manager_->SetActiveUser(account_id);
-  }
-
-  account_id_ = account_id;
-  user_pod_last_focused_timestamp_ = base::TimeTicks::Now();
-  SetProximityAuthDevices(account_id_, multidevice::RemoteDeviceRefList(),
-                          absl::nullopt /* local_device */);
-  ResetSmartLockState();
-
-  // Changing the "Active User" above changes the return values of IsAllowed()
-  // and IsEnabled() below.
-  if (!IsAllowed() || !IsEnabled())
-    return;
-
-  ShowInitialUserPodState();
-
-  // If there is a hardlock, then there is no point in loading the devices.
-  SmartLockStateHandler::HardlockState hardlock_state;
-  if (GetPersistedHardlockState(&hardlock_state) &&
-      hardlock_state != SmartLockStateHandler::NO_HARDLOCK) {
-    PA_LOG(VERBOSE) << "Hardlock present, skipping remaining login flow.";
-    return;
-  }
-
-  UpdateAppState();
-  LoadCurrentUserDataIfNeeded();
-
-  // Start loading TPM system token.
-  // The system token will be needed to sign a nonce using TPM private key
-  // during the sign-in protocol.
-  TPMTokenLoader::Get()->EnsureStarted();
-}
-
-void EasyUnlockServiceSignin::LoadCurrentUserDataIfNeeded() {
-  // TODO(xiyuan): Revisit this when adding tests.
-  if (!base::SysInfo::IsRunningOnChromeOS())
-    return;
-
-  if (!account_id_.is_valid() || !service_active_)
-    return;
-
-  const auto it = user_data_.find(account_id_);
-  if (it == user_data_.end())
-    user_data_.insert(
-        std::make_pair(account_id_, std::make_unique<UserData>()));
-
-  UserData* data = user_data_[account_id_].get();
-
-  if (data->state == USER_DATA_STATE_LOADING)
-    return;
-  data->state = USER_DATA_STATE_LOADING;
-
-  LoadDataForUser(
-      account_id_,
-      allow_cryptohome_backoff_ ? 0u : kMaxCryptohomeBackoffIntervalMs,
-      base::BindOnce(&EasyUnlockServiceSignin::OnUserDataLoaded,
-                     weak_ptr_factory_.GetWeakPtr(), account_id_));
-}
-
-// TODO(crbug.com/856387): Write tests for device retrieval from the TPM.
-void EasyUnlockServiceSignin::OnUserDataLoaded(
-    const AccountId& account_id,
-    bool success,
-    const EasyUnlockDeviceKeyDataList& devices) {
-  allow_cryptohome_backoff_ = false;
-
-  UserData* data = user_data_[account_id].get();
-  data->state = USER_DATA_STATE_LOADED;
-  if (success) {
-    data->devices = devices;
-    EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList(
-        account_id, devices, &data->remote_devices_value);
-
-    // User could have a NO_HARDLOCK state but has no remote devices if
-    // previous user session shuts down before
-    // CheckCryptohomeKeysAndMaybeHardlock finishes. Set NO_PAIRING state
-    // and update UI to remove the confusing spinner in this case.
-    SmartLockStateHandler::HardlockState hardlock_state;
-    if (devices.empty() && GetPersistedHardlockState(&hardlock_state) &&
-        hardlock_state == SmartLockStateHandler::NO_HARDLOCK) {
-      SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
-    }
-  }
-
-  if (devices.empty())
-    return;
-
-  multidevice::RemoteDeviceList remote_devices;
-  for (const auto& device : devices) {
-    std::string decoded_public_key, decoded_psk;
-    if (!base::Base64UrlDecode(device.public_key,
-                               base::Base64UrlDecodePolicy::REQUIRE_PADDING,
-                               &decoded_public_key) ||
-        !base::Base64UrlDecode(device.psk,
-                               base::Base64UrlDecodePolicy::REQUIRE_PADDING,
-                               &decoded_psk)) {
-      PA_LOG(ERROR) << "Unable to decode stored remote device:\n"
-                    << "  public_key: " << device.public_key << "\n"
-                    << "  psk: " << device.psk;
-      continue;
-    }
-
-    std::map<multidevice::SoftwareFeature, multidevice::SoftwareFeatureState>
-        software_features;
-    software_features[multidevice::SoftwareFeature::kSmartLockHost] =
-        device.unlock_key ? multidevice::SoftwareFeatureState::kEnabled
-                          : multidevice::SoftwareFeatureState::kNotSupported;
-
-    std::vector<multidevice::BeaconSeed> beacon_seeds;
-    if (!device.serialized_beacon_seeds.empty()) {
-      PA_LOG(VERBOSE) << "Deserializing BeaconSeeds: "
-                      << device.serialized_beacon_seeds;
-      beacon_seeds = DeserializeBeaconSeeds(device.serialized_beacon_seeds);
-    } else {
-      PA_LOG(WARNING) << "No BeaconSeeds were loaded.";
-    }
-
-    // Values such as the `instance_id` and `name` of the device are not
-    // provided in the device dictionary that is persisted to the TPM during the
-    // user session. However, in this particular scenario, we do not need these
-    // values to safely construct and use the RemoteDevice objects.
-    multidevice::RemoteDevice remote_device(
-        account_id.GetUserEmail(), std::string() /* instance_id */,
-        std::string() /* name */, std::string() /* pii_free_name */,
-        decoded_public_key, decoded_psk /* persistent_symmetric_key */,
-        0L /* last_update_time_millis */, software_features, beacon_seeds,
-        std::string() /* bluetooth_public_address */);
-
-    remote_devices.push_back(remote_device);
-    PA_LOG(VERBOSE) << "Loaded Remote Device:\n"
-                    << "  user email: " << remote_device.user_email << "\n"
-                    << "  device id: "
-                    << multidevice::RemoteDeviceRef::TruncateDeviceIdForLogs(
-                           remote_device.GetDeviceId());
-  }
-
-  // Both a remote device and local device are expected, and this service cannot
-  // continue unless both are present.
-  // TODO(crbug.com/856380): The remote and local devices need to be passed in a
-  // less hacky way.
-  if (remote_devices.size() > 2u) {
-    PA_LOG(ERROR)
-        << "Expected a device list of size 1 or 2, received list of size "
-        << remote_devices.size();
-    SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
-    return;
-  }
-
-  if (remote_devices.size() != 2u) {
-    PA_LOG(ERROR) << "Expected a device list of size 2, received list of size "
-                  << remote_devices.size();
-    SetHardlockStateForUser(account_id, SmartLockStateHandler::PAIRING_CHANGED);
-    return;
-  }
-
-  std::string unlock_key_id;
-  // This may be left unset if the local device was not passed along.
-  std::string local_device_id;
-
-  for (const auto& remote_device : remote_devices) {
-    if (base::Contains(remote_device.software_features,
-                       multidevice::SoftwareFeature::kSmartLockHost) &&
-        remote_device.software_features.at(
-            multidevice::SoftwareFeature::kSmartLockHost) ==
-            multidevice::SoftwareFeatureState::kEnabled) {
-      if (!unlock_key_id.empty()) {
-        PA_LOG(ERROR) << "Only one of the devices should be an unlock key.";
-        SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
-        return;
-      }
-
-      unlock_key_id = remote_device.GetDeviceId();
-    } else {
-      if (!local_device_id.empty()) {
-        PA_LOG(ERROR) << "Only one of the devices should be the local device.";
-        SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
-        return;
-      }
-
-      local_device_id = remote_device.GetDeviceId();
-    }
-  }
-
-  remote_device_cache_->SetRemoteDevices(remote_devices);
-
-  absl::optional<multidevice::RemoteDeviceRef> unlock_key_device =
-      remote_device_cache_->GetRemoteDevice(
-          absl::nullopt /* instance_id */,
-          unlock_key_id /* legacy_device_id */);
-  absl::optional<multidevice::RemoteDeviceRef> local_device =
-      remote_device_cache_->GetRemoteDevice(
-          absl::nullopt /* instance_id */,
-          local_device_id /* legacy_device_id */);
-
-  // TODO(hansberry): It is possible that there may not be an unlock key by this
-  // point. If this occurs, it is due to a bug in how device metadata is
-  // persisted in CryptoHome. See https://crbug.com/856380 for more details. For
-  // now, simply return early here to prevent a potential crash which can occur
-  // in this situation (see https://crbug.com/866711).
-  if (!unlock_key_device) {
-    SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
-    return;
-  }
-
-  if (!local_device) {
-    SetHardlockStateForUser(account_id, SmartLockStateHandler::NO_PAIRING);
-    return;
-  }
-
-  SetProximityAuthDevices(account_id, {*unlock_key_device}, local_device);
-}
-
-const EasyUnlockServiceSignin::UserData*
-EasyUnlockServiceSignin::FindLoadedDataForCurrentUser() const {
-  if (!account_id_.is_valid())
-    return nullptr;
-
-  const auto it = user_data_.find(account_id_);
-  if (it == user_data_.end())
-    return nullptr;
-  if (it->second->state != USER_DATA_STATE_LOADED)
-    return nullptr;
-  return it->second.get();
-}
-
-void EasyUnlockServiceSignin::ShowInitialUserPodState() {
-  if (!IsAllowed() || !IsEnabled())
-    return;
-
-  if (!pref_manager_->IsChromeOSLoginEnabled()) {
-    // Show a hardlock state if the user has not enabled Smart Lock to the log
-    // in to the user's Google account.
-    SetHardlockStateForUser(account_id_, SmartLockStateHandler::LOGIN_DISABLED);
-  } else {
-    // This UI is simply a placeholder until the RemoteDevices are loaded from
-    // cryptohome and the ProximityAuthSystem is started. Hardlock states are
-    // automatically taken into account.
-    UpdateSmartLockState(SmartLockState::kConnectingToPhone);
-  }
-}
-
-}  // namespace ash
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin_chromeos.h b/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin_chromeos.h
deleted file mode 100644
index 81cd7c0..0000000
--- a/chrome/browser/ash/login/easy_unlock/easy_unlock_service_signin_chromeos.h
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_SIGNIN_CHROMEOS_H_
-#define CHROME_BROWSER_ASH_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_SIGNIN_CHROMEOS_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_service.h"
-#include "chrome/browser/ash/login/easy_unlock/easy_unlock_types.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/components/multidevice/remote_device_cache.h"
-#include "chromeos/components/proximity_auth/screenlock_bridge.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h"
-
-namespace proximity_auth {
-class ProximityAuthLocalStatePrefManager;
-}  // namespace proximity_auth
-
-namespace ash {
-class EasyUnlockChallengeWrapper;
-
-// EasyUnlockService instance that should be used for signin profile.
-class EasyUnlockServiceSignin
-    : public EasyUnlockService,
-      public proximity_auth::ScreenlockBridge::Observer {
- public:
-  EasyUnlockServiceSignin(
-      Profile* profile,
-      secure_channel::SecureChannelClient* secure_channel_client);
-
-  EasyUnlockServiceSignin(const EasyUnlockServiceSignin&) = delete;
-  EasyUnlockServiceSignin& operator=(const EasyUnlockServiceSignin&) = delete;
-
-  ~EasyUnlockServiceSignin() override;
-
-  // Wraps the challenge for the remote device identified by `account_id` and
-  // the
-  // `device_public_key`. The `channel_binding_data` is signed by the TPM
-  // included in the wrapped challenge.
-  // `callback` will be invoked when wrapping is complete. If the user data is
-  // not loaded yet, then `callback` will be invoked with an empty string.
-  void WrapChallengeForUserAndDevice(
-      const AccountId& account_id,
-      const std::string& device_public_key,
-      const std::string& channel_binding_data,
-      base::OnceCallback<void(const std::string& wraped_challenge)> callback);
-
- private:
-  // The load state of a user's cryptohome key data.
-  enum UserDataState {
-    // Initial state, the key data is empty and not being loaded.
-    USER_DATA_STATE_INITIAL,
-    // The key data is empty, but being loaded.
-    USER_DATA_STATE_LOADING,
-    // The key data has been loaded.
-    USER_DATA_STATE_LOADED
-  };
-
-  // Structure containing a user's key data loaded from cryptohome.
-  struct UserData {
-    UserData();
-
-    UserData(const UserData&) = delete;
-    UserData& operator=(const UserData&) = delete;
-
-    ~UserData();
-
-    // The loading state of the data.
-    UserDataState state;
-
-    // The data as returned from cryptohome.
-    EasyUnlockDeviceKeyDataList devices;
-
-    // The list of remote device dictionaries understood by Easy unlock app.
-    // This will be returned by `GetRemoteDevices` method.
-    base::ListValue remote_devices_value;
-  };
-
-  // EasyUnlockService implementation:
-  proximity_auth::ProximityAuthPrefManager* GetProximityAuthPrefManager()
-      override;
-  EasyUnlockService::Type GetType() const override;
-  AccountId GetAccountId() const override;
-  const base::ListValue* GetRemoteDevices() const override;
-  std::string GetChallenge() const override;
-  std::string GetWrappedSecret() const override;
-  void RecordEasySignInOutcome(const AccountId& account_id,
-                               bool success) const override;
-  void RecordPasswordLoginEvent(const AccountId& account_id) const override;
-  void InitializeInternal() override;
-  void ShutdownInternal() override;
-  bool IsAllowedInternal() const override;
-  bool IsEnabled() const override;
-  bool IsChromeOSLoginEnabled() const override;
-  void OnSuspendDoneInternal() override;
-
-  // proximity_auth::ScreenlockBridge::Observer implementation:
-  void OnScreenDidLock(proximity_auth::ScreenlockBridge::LockHandler::ScreenType
-                           screen_type) override;
-  void OnScreenDidUnlock(
-      proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type)
-      override;
-  void OnFocusedUserChanged(const AccountId& account_id) override;
-
-  // Loads the device data associated with the user's Easy unlock keys from
-  // crypthome.
-  void LoadCurrentUserDataIfNeeded();
-
-  // Callback invoked when the user's device data is loaded from cryptohome.
-  void OnUserDataLoaded(const AccountId& account_id,
-                        bool success,
-                        const EasyUnlockDeviceKeyDataList& data);
-
-  // If the device data has been loaded for the current user, returns it.
-  // Otherwise, returns NULL.
-  const UserData* FindLoadedDataForCurrentUser() const;
-
-  // Shows the hardlock or connecting state as initial UI before cryptohome
-  // keys checking and state update from the app.
-  void ShowInitialUserPodState();
-
-  // User id of the user currently associated with the service.
-  AccountId account_id_;
-
-  // Maps account ids to their fetched cryptohome key data.
-  std::map<AccountId, std::unique_ptr<UserData>> user_data_;
-
-  // Whether failed attempts to load user data should be retried.
-  // This is to handle case where cryptohome daemon is not started in time the
-  // service attempts to load some data. Retries will be allowed only until the
-  // first data load finishes (even if it fails).
-  bool allow_cryptohome_backoff_ = true;
-
-  // Whether the service has been successfully initialized, and has not been
-  // shut down.
-  bool service_active_ = false;
-
-  // The timestamp for the most recent time when a user pod was focused.
-  base::TimeTicks user_pod_last_focused_timestamp_;
-
-  std::unique_ptr<multidevice::RemoteDeviceCache> remote_device_cache_;
-
-  // Handles wrapping the user's challenge with the TPM.
-  std::unique_ptr<EasyUnlockChallengeWrapper> challenge_wrapper_;
-
-  // Manages the EasyUnlock prefs for the local state.
-  std::unique_ptr<proximity_auth::ProximityAuthLocalStatePrefManager>
-      pref_manager_;
-
-  base::WeakPtrFactory<EasyUnlockServiceSignin> weak_ptr_factory_{this};
-};
-
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_ASH_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_SIGNIN_CHROMEOS_H_
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager.cc b/chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager.cc
index 656b4c9..333f2a5e 100644
--- a/chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager.cc
+++ b/chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager.cc
@@ -50,16 +50,8 @@
 void GetSystemSlotOnIOThread(
     const scoped_refptr<base::SingleThreadTaskRunner>& response_task_runner,
     base::OnceCallback<void(crypto::ScopedPK11Slot)> callback) {
-  // This callback will only be executed once but must be marked repeating
-  // because it could be discarded by GetSystemNSSKeySlot() and invoked here
-  // instead.
-  auto callback_on_origin_thread = base::BindRepeating(
-      &RunCallbackOnTaskRunner, response_task_runner, base::Passed(&callback));
-
-  crypto::ScopedPK11Slot system_slot =
-      crypto::GetSystemNSSKeySlot(callback_on_origin_thread);
-  if (system_slot)
-    callback_on_origin_thread.Run(std::move(system_slot));
+  crypto::GetSystemNSSKeySlot(base::BindOnce(
+      &RunCallbackOnTaskRunner, response_task_runner, std::move(callback)));
 }
 
 // Relays `EnsureUserTpmInitializedOnIOThread` callback to
@@ -334,7 +326,12 @@
 void EasyUnlockTpmKeyManager::CreateKeyInSystemSlot(
     const std::string& public_key,
     crypto::ScopedPK11Slot system_slot) {
-  CHECK(system_slot);
+  if (!system_slot) {
+    // Emulate timeout, system slot will never be loaded.
+    OnTpmKeyCreated(std::string());
+    return;
+  }
+
   create_tpm_key_state_ = CREATE_TPM_KEY_GOT_SYSTEM_SLOT;
 
   // If there are any delayed tasks posted using `StartGetSystemSlotTimeoutMs`,
@@ -358,7 +355,11 @@
     const std::string& data,
     base::OnceCallback<void(const std::string& data)> callback,
     crypto::ScopedPK11Slot system_slot) {
-  CHECK(system_slot);
+  if (!system_slot) {
+    // Emulate timeout, system slot will never be loaded.
+    OnTpmKeyCreated(std::string());
+    return;
+  }
 
   // This task interacts with the TPM, hence MayBlock().
   base::ThreadPool::PostTask(
diff --git a/chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc b/chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
index a9d3146..1794625 100644
--- a/chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
+++ b/chrome/browser/ash/login/easy_unlock/easy_unlock_tpm_key_manager_unittest.cc
@@ -226,6 +226,8 @@
         base::UTF8ToUTF16(test_account_id_.GetUserEmail()), 0 /* avatar id */,
         std::string() /* supervized user id */,
         TestingProfile::TestingFactories());
+
+    SetUpTestSystemSlot();
   }
 
   void TearDown() override {
@@ -289,9 +291,10 @@
   void ResetTestNssUserOnIOThread() { test_nss_user_.reset(); }
 
   // Creates and sets test system NSS key slot.
-  bool SetUpTestSystemSlot() {
-    test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>();
-    return test_system_slot_->ConstructedSuccessfully();
+  void SetUpTestSystemSlot() {
+    test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>(
+        /*simulate_token_loader=*/true);
+    ASSERT_TRUE(test_system_slot_->ConstructedSuccessfully());
   }
 
   // Imports a private RSA key to the test system slot.
@@ -375,7 +378,6 @@
                                                  run_loop.QuitClosure()));
   EXPECT_TRUE(user_key_manager()->GetPublicTpmKey(test_account_id_).empty());
 
-  ASSERT_TRUE(SetUpTestSystemSlot());
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
   run_loop.Run();
 
@@ -405,7 +407,6 @@
   EXPECT_FALSE(user_key_manager()->PrepareTpmKey(/*check_private_key=*/false,
                                                  base::OnceClosure()));
 
-  ASSERT_TRUE(SetUpTestSystemSlot());
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
   EXPECT_EQ(0, callback_count);
 
@@ -449,7 +450,6 @@
   ASSERT_FALSE(user_key_manager()->PrepareTpmKey(true /* check_private_key */,
                                                  run_loop.QuitClosure()));
 
-  ASSERT_TRUE(SetUpTestSystemSlot());
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
   run_loop.Run();
 
@@ -463,7 +463,6 @@
 
 TEST_F(EasyUnlockTpmKeyManagerTest, PublicKeySetInPrefsCheckPrivateKey_OK) {
   ASSERT_TRUE(InitTestNssUser());
-  ASSERT_TRUE(SetUpTestSystemSlot());
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
   ASSERT_TRUE(ImportPrivateKey(kTestPrivateKey, base::size(kTestPrivateKey)));
   SetLocalStatePublicKey(
@@ -505,7 +504,6 @@
   ASSERT_TRUE(user_key_manager()->StartGetSystemSlotTimeoutMs(0));
   run_loop_get_slot_timeout.RunUntilIdle();
 
-  ASSERT_TRUE(SetUpTestSystemSlot());
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
 
   run_loop.Run();
@@ -521,7 +519,6 @@
 
   base::RunLoop run_loop_slot;
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
-  ASSERT_TRUE(SetUpTestSystemSlot());
   run_loop_slot.RunUntilIdle();
 
   ASSERT_FALSE(user_key_manager()->StartGetSystemSlotTimeoutMs(0));
@@ -550,7 +547,6 @@
   ASSERT_FALSE(user_key_manager()->PrepareTpmKey(false /* check_private_key */,
                                                  run_loop_retry.QuitClosure()));
 
-  ASSERT_TRUE(SetUpTestSystemSlot());
   VerifyKeyGenerationNotStartedAndFinalizeTestNssUser();
 
   run_loop_retry.Run();
@@ -559,7 +555,8 @@
 }
 
 TEST_F(EasyUnlockTpmKeyManagerTest, SignData) {
-  ASSERT_TRUE(SetUpTestSystemSlot());
+  ASSERT_TRUE(InitTestNssUser());
+
   ASSERT_TRUE(ImportPrivateKey(kTestPrivateKey, base::size(kTestPrivateKey)));
   SetLocalStatePublicKey(
       test_account_id_,
@@ -590,6 +587,8 @@
 }
 
 TEST_F(EasyUnlockTpmKeyManagerTest, SignDataNoPrivateKeyPresent) {
+  ASSERT_TRUE(InitTestNssUser());
+
   SetLocalStatePublicKey(
       test_account_id_,
       std::string(reinterpret_cast<const char*>(kTestPublicKey),
@@ -602,8 +601,6 @@
       base::BindOnce(&RecordStringAndRunClosure, &signed_data,
                      loop.QuitClosure()));
 
-  ASSERT_TRUE(SetUpTestSystemSlot());
-
   loop.Run();
 
   EXPECT_TRUE(signed_data.empty());
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter.cc b/chrome/browser/ash/login/reporting/login_logout_reporter.cc
index 1e98632..179f072 100644
--- a/chrome/browser/ash/login/reporting/login_logout_reporter.cc
+++ b/chrome/browser/ash/login/reporting/login_logout_reporter.cc
@@ -125,7 +125,7 @@
     record.mutable_affiliated_user()->set_user_email(user_email);
   }
 
-  reporter_helper_->ReportEvent(&record, ::reporting::Priority::IMMEDIATE);
+  reporter_helper_->ReportEvent(&record, ::reporting::Priority::SECURITY);
 }
 
 void LoginLogoutReporter::OnLogin(Profile* profile) {
diff --git a/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc b/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc
index be06ce0dd..0a815f4 100644
--- a/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc
+++ b/chrome/browser/ash/login/reporting/login_logout_reporter_unittest.cc
@@ -105,7 +105,7 @@
   auto profile = CreateRegularProfile(user_email);
   reporter->OnLogin(profile.get());
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_FALSE(record.is_guest_session());
   EXPECT_FALSE(record.has_logout_event());
@@ -146,7 +146,7 @@
   auto profile = CreateRegularProfile(user_email);
   reporter->OnLogin(profile.get());
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_FALSE(record.is_guest_session());
   EXPECT_FALSE(record.has_logout_event());
@@ -184,7 +184,7 @@
   auto profile = CreatePublicAccountProfile();
   reporter->OnLogin(profile.get());
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_TRUE(record.is_guest_session());
   EXPECT_FALSE(record.has_logout_event());
@@ -244,7 +244,7 @@
   reporter->OnSessionTerminationStarted(
       ProfileHelper::Get()->GetUserByProfile(profile.get()));
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_FALSE(record.is_guest_session());
   EXPECT_FALSE(record.has_login_event());
@@ -285,7 +285,7 @@
   reporter->OnSessionTerminationStarted(
       ProfileHelper::Get()->GetUserByProfile(profile.get()));
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_FALSE(record.is_guest_session());
   EXPECT_FALSE(record.has_login_event());
@@ -323,7 +323,7 @@
   reporter->OnSessionTerminationStarted(
       ProfileHelper::Get()->GetUserByProfile(profile.get()));
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_TRUE(record.is_guest_session());
   EXPECT_FALSE(record.has_login_event());
@@ -382,7 +382,7 @@
           AccountId::FromUserEmail(std::string(user_email))));
   reporter->OnLoginFailure(chromeos::AuthFailure(AuthFailure::OWNER_REQUIRED));
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_FALSE(record.is_guest_session());
   EXPECT_FALSE(record.has_logout_event());
@@ -426,7 +426,7 @@
   reporter->OnLoginFailure(
       chromeos::AuthFailure(AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME));
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_FALSE(record.is_guest_session());
   EXPECT_FALSE(record.has_logout_event());
@@ -469,7 +469,7 @@
           AccountId::FromUserEmail(std::string(user_email))));
   reporter->OnLoginFailure(chromeos::AuthFailure(AuthFailure::TPM_ERROR));
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_FALSE(record.is_guest_session());
   EXPECT_FALSE(record.has_logout_event());
@@ -511,7 +511,7 @@
   reporter->OnLoginFailure(
       chromeos::AuthFailure(AuthFailure::COULD_NOT_MOUNT_TMPFS));
 
-  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::IMMEDIATE));
+  EXPECT_THAT(priority, testing::Eq(::reporting::Priority::SECURITY));
   EXPECT_TRUE(record.has_event_timestamp());
   EXPECT_TRUE(record.is_guest_session());
   EXPECT_FALSE(record.has_logout_event());
diff --git a/chrome/browser/ash/login/webview_login_browsertest.cc b/chrome/browser/ash/login/webview_login_browsertest.cc
index c8dab786..9bcc495 100644
--- a/chrome/browser/ash/login/webview_login_browsertest.cc
+++ b/chrome/browser/ash/login/webview_login_browsertest.cc
@@ -11,6 +11,7 @@
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/files/file_util.h"
 #include "base/guid.h"
 #include "base/json/json_writer.h"
@@ -98,6 +99,7 @@
 #include "crypto/nss_util.h"
 #include "crypto/nss_util_internal.h"
 #include "crypto/scoped_test_nss_db.h"
+#include "crypto/scoped_test_system_nss_key_slot.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "media/base/media_switches.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -1448,12 +1450,11 @@
  private:
   void PrepareSystemSlotOnIO(bool* out_system_slot_prepared_successfully) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    test_system_slot_nss_db_ = std::make_unique<crypto::ScopedTestNSSDB>();
-    crypto::SetSystemKeySlotWithoutInitializingTPMForTesting(
-        crypto::ScopedPK11Slot(
-            PK11_ReferenceSlot(test_system_slot_nss_db_->slot())));
+    test_system_slot_nss_db_ =
+        std::make_unique<crypto::ScopedTestSystemNSSKeySlot>(
+            /*simulate_token_loader=*/false);
     *out_system_slot_prepared_successfully =
-        test_system_slot_nss_db_->is_open();
+        test_system_slot_nss_db_->ConstructedSuccessfully();
   }
 
   void TearDownTestSystemSlot() {
@@ -1467,41 +1468,88 @@
     loop.Run();
   }
 
-  void TearDownTestSystemSlotOnIO() {
-    crypto::SetSystemKeySlotWithoutInitializingTPMForTesting(/*slot=*/nullptr);
-    test_system_slot_nss_db_.reset();
-  }
+  void TearDownTestSystemSlotOnIO() { test_system_slot_nss_db_.reset(); }
 
-  std::unique_ptr<crypto::ScopedTestNSSDB> test_system_slot_nss_db_;
+  std::unique_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_nss_db_;
 };
 
 namespace {
 
-bool IsTpmTokenReady() {
+void GotIsTpmTokenEnabledOnUIThread(base::OnceClosure run_loop_quit_closure,
+                                    bool* is_ready,
+                                    bool is_tpm_token_enabled) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  *is_ready = is_tpm_token_enabled;
+  std::move(run_loop_quit_closure).Run();
+}
+
+void GotIsTpmTokenEnabledOnIOThread(base::OnceCallback<void(bool)> ui_callback,
+                                    bool is_tpm_token_enabled) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  content::GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE, base::BindOnce(std::move(ui_callback), is_tpm_token_enabled));
+}
+
+bool IsTpmTokenEnabled() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
   base::RunLoop run_loop;
   bool is_ready = false;
-  content::GetIOThreadTaskRunner({})->PostTaskAndReplyWithResult(
-      FROM_HERE,
-      base::BindOnce(&crypto::IsTPMTokenReady,
-                     /*callback=*/base::OnceClosure()),
-      base::BindOnce(
-          [](base::OnceClosure run_loop_quit_closure, bool* is_ready,
-             bool is_tpm_token_ready) {
-            *is_ready = is_tpm_token_ready;
-            std::move(run_loop_quit_closure).Run();
-          },
-          run_loop.QuitClosure(), base::Unretained(&is_ready)));
+
+  auto ui_callback =
+      base::BindOnce(&GotIsTpmTokenEnabledOnUIThread, run_loop.QuitClosure(),
+                     base::Unretained(&is_ready));
+
+  content::GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE, base::BindOnce(&crypto::IsTPMTokenEnabled,
+                                base::BindOnce(&GotIsTpmTokenEnabledOnIOThread,
+                                               std::move(ui_callback))));
   run_loop.Run();
   return is_ready;
 }
 
+void GotIsSystemSlotAvailableOnUIThread(base::OnceClosure run_loop_quit_closure,
+                                        bool* result,
+                                        bool is_system_slot_available) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  *result = is_system_slot_available;
+  std::move(run_loop_quit_closure).Run();
+}
+
+void GotSystemSlotOnIOThread(base::OnceCallback<void(bool)> ui_callback,
+                             crypto::ScopedPK11Slot system_slot) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  content::GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE, base::BindOnce(std::move(ui_callback), !!system_slot));
+}
+
+bool IsSystemSlotAvailable() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  base::RunLoop run_loop;
+  bool result = false;
+
+  auto ui_callback =
+      base::BindOnce(&GotIsSystemSlotAvailableOnUIThread,
+                     run_loop.QuitClosure(), base::Unretained(&result));
+
+  content::GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE, base::BindOnce(&crypto::GetSystemNSSKeySlot,
+                                base::BindOnce(&GotSystemSlotOnIOThread,
+                                               std::move(ui_callback))));
+
+  run_loop.Run();
+  return result;
+}
+
 }  // namespace
 
 // Test that the system slot becomes initialized and the client certificate
 // authentication works in the sign-in frame after the TPM gets reported as
 // ready.
 IN_PROC_BROWSER_TEST_F(WebviewClientCertsTokenLoadingLoginTest,
-                       SystemSlotInitialization) {
+                       SystemSlotEnabled) {
   ASSERT_NO_FATAL_FAILURE(PrepareSystemSlot());
   net::SSLServerConfig server_config;
   server_config.client_cert_type = net::SSLServerConfig::OPTIONAL_CLIENT_CERT;
@@ -1513,9 +1561,6 @@
 
   WaitForGaiaPageLoadAndPropertyUpdate();
 
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(IsTpmTokenReady());
-
   // Report the TPM as ready, triggering the system token initialization by
   // SystemTokenCertDBInitializer.
   TpmManagerClient::Get()
@@ -1530,7 +1575,24 @@
   ASSERT_TRUE(ssl_info->cert);
   EXPECT_THAT(*ssl_info->cert, EqualsCert(std::string(kClientCert1Name)));
 
-  EXPECT_TRUE(IsTpmTokenReady());
+  EXPECT_TRUE(IsTpmTokenEnabled());
+  EXPECT_TRUE(IsSystemSlotAvailable());
+}
+
+IN_PROC_BROWSER_TEST_F(WebviewClientCertsTokenLoadingLoginTest,
+                       SystemSlotDisabled) {
+  WaitForGaiaPageLoadAndPropertyUpdate();
+
+  // Report the TPM as ready, triggering the system token initialization by
+  // SystemTokenCertDBInitializer.
+  TpmManagerClient::Get()
+      ->GetTestInterface()
+      ->mutable_nonsensitive_status_reply()
+      ->set_is_owned(false);
+  TpmManagerClient::Get()->GetTestInterface()->EmitOwnershipTakenSignal();
+
+  EXPECT_FALSE(IsTpmTokenEnabled());
+  EXPECT_FALSE(IsSystemSlotAvailable());
 }
 
 class WebviewProxyAuthLoginTest : public WebviewLoginTest {
diff --git a/chrome/browser/ash/nearby/DIR_METADATA b/chrome/browser/ash/nearby/DIR_METADATA
new file mode 100644
index 0000000..24bdd08e
--- /dev/null
+++ b/chrome/browser/ash/nearby/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chromeos/services/nearby/COMMON_METADATA"
diff --git a/chrome/browser/ash/ownership/owner_settings_service_ash.cc b/chrome/browser/ash/ownership/owner_settings_service_ash.cc
index 6ab72e4d..91d9de6 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_ash.cc
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash.cc
@@ -183,6 +183,13 @@
       std::move(callback));
 }
 
+void OnTPMTokenReadyOnIOThread(
+    scoped_refptr<base::SequencedTaskRunner> original_task_runner,
+    base::OnceClosure ready_callback,
+    bool /*is_tpm_token_enabled*/) {
+  original_task_runner->PostTask(FROM_HERE, std::move(ready_callback));
+}
+
 }  // namespace
 
 OwnerSettingsServiceAsh::ManagementSettings::ManagementSettings() = default;
@@ -196,16 +203,6 @@
     : ownership::OwnerSettingsService(owner_key_util),
       device_settings_service_(device_settings_service),
       profile_(profile) {
-  if (chromeos::TPMTokenLoader::IsInitialized()) {
-    chromeos::TPMTokenLoader::TPMTokenStatus tpm_token_status =
-        chromeos::TPMTokenLoader::Get()->IsTPMTokenEnabled(
-            base::BindOnce(&OwnerSettingsServiceAsh::OnTPMTokenReady,
-                           weak_factory_.GetWeakPtr()));
-    waiting_for_tpm_token_ =
-        tpm_token_status ==
-        chromeos::TPMTokenLoader::TPM_TOKEN_STATUS_UNDETERMINED;
-  }
-
   if (chromeos::SessionManagerClient::Get())
     chromeos::SessionManagerClient::Get()->AddObserver(this);
 
@@ -224,6 +221,16 @@
   // The ProfileManager may be null in unit tests.
   if (g_browser_process->profile_manager())
     g_browser_process->profile_manager()->AddObserver(this);
+
+  auto ready_callback = base::BindOnce(
+      &OwnerSettingsServiceAsh::OnTPMTokenReady, weak_factory_.GetWeakPtr());
+  waiting_for_tpm_token_ = true;
+  content::GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(&crypto::IsTPMTokenEnabled,
+                     base::BindOnce(OnTPMTokenReadyOnIOThread,
+                                    base::SequencedTaskRunnerHandle::Get(),
+                                    std::move(ready_callback))));
 }
 
 OwnerSettingsServiceAsh::~OwnerSettingsServiceAsh() {
@@ -250,7 +257,7 @@
   return OwnerSettingsServiceAshFactory::GetForBrowserContext(profile);
 }
 
-void OwnerSettingsServiceAsh::OnTPMTokenReady(bool /* tpm_token_enabled */) {
+void OwnerSettingsServiceAsh::OnTPMTokenReady() {
   DCHECK(thread_checker_.CalledOnValidThread());
   waiting_for_tpm_token_ = false;
 
diff --git a/chrome/browser/ash/ownership/owner_settings_service_ash.h b/chrome/browser/ash/ownership/owner_settings_service_ash.h
index 2b9fe02..96888cf 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_ash.h
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash.h
@@ -67,7 +67,7 @@
 
   static OwnerSettingsServiceAsh* FromWebUI(content::WebUI* web_ui);
 
-  void OnTPMTokenReady(bool tpm_token_enabled);
+  void OnTPMTokenReady();
 
   void OnEasyUnlockKeyOpsFinished();
 
diff --git a/chrome/browser/ash/phonehub/DIR_METADATA b/chrome/browser/ash/phonehub/DIR_METADATA
index 3532c57..fb34eb9 100644
--- a/chrome/browser/ash/phonehub/DIR_METADATA
+++ b/chrome/browser/ash/phonehub/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "OS>Systems>Multidevice>PhoneHub"
-}
+mixins: "//chromeos/components/phonehub/COMMON_METADATA"
diff --git a/chrome/browser/ash/plugin_vm/COMMON_METADATA b/chrome/browser/ash/plugin_vm/COMMON_METADATA
new file mode 100644
index 0000000..73a0e94
--- /dev/null
+++ b/chrome/browser/ash/plugin_vm/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Shell>Containers>PluginVM"
+}
diff --git a/chrome/browser/ash/plugin_vm/DIR_METADATA b/chrome/browser/ash/plugin_vm/DIR_METADATA
index 73a0e94..e21b1ad 100644
--- a/chrome/browser/ash/plugin_vm/DIR_METADATA
+++ b/chrome/browser/ash/plugin_vm/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Shell>Containers>PluginVM"
-}
+mixins: "//chrome/browser/ash/plugin_vm/COMMON_METADATA"
diff --git a/chrome/browser/ash/policy/DIR_METADATA b/chrome/browser/ash/policy/DIR_METADATA
index 543dab0e..50ec60f 100644
--- a/chrome/browser/ash/policy/DIR_METADATA
+++ b/chrome/browser/ash/policy/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "OS>Software>Enterprise"
-}
+mixins: "//chromeos/policy/COMMON_METADATA"
diff --git a/chrome/browser/ash/policy/affiliation/user_affiliation_browsertest.cc b/chrome/browser/ash/policy/affiliation/user_affiliation_browsertest.cc
index fcbcb4c2..1574c5ec 100644
--- a/chrome/browser/ash/policy/affiliation/user_affiliation_browsertest.cc
+++ b/chrome/browser/ash/policy/affiliation/user_affiliation_browsertest.cc
@@ -218,7 +218,8 @@
  private:
   void SetUpTestSystemSlotOnIO(bool* out_system_slot_constructed_successfully) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>();
+    test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>(
+        /*simulate_token_loader=*/false);
     *out_system_slot_constructed_successfully =
         test_system_slot_->ConstructedSuccessfully();
   }
diff --git a/chrome/browser/ash/policy/dlp/dlp_clipboard_notifier.cc b/chrome/browser/ash/policy/dlp/dlp_clipboard_notifier.cc
index 786265c..1f05000 100644
--- a/chrome/browser/ash/policy/dlp/dlp_clipboard_notifier.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_clipboard_notifier.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ash/public/cpp/new_window_delegate.h"
 #include "ash/public/cpp/toast_data.h"
 #include "ash/public/cpp/toast_manager.h"
 #include "ash/public/cpp/window_tree_host_lookup.h"
@@ -77,6 +78,11 @@
   return false;
 }
 
+void OnToastClicked() {
+  ash::NewWindowDelegate::GetInstance()->OpenUrl(
+      GURL(kDlpLearnMoreUrl), /*from_user_interaction=*/true);
+}
+
 }  // namespace
 
 DlpClipboardNotifier::DlpClipboardNotifier() {
@@ -244,9 +250,11 @@
 
 void DlpClipboardNotifier::ShowToast(const std::string& id,
                                      const std::u16string& text) const {
-  ash::ToastData toast(id, text, kClipboardDlpBlockDurationMs,
-                       /*dismiss_text=*/absl::nullopt);
+  ash::ToastData toast(
+      id, text, kClipboardDlpBlockDurationMs,
+      l10n_util::GetStringUTF16(IDS_POLICY_DLP_CLIPBOARD_BLOCK_TOAST_BUTTON));
   toast.is_managed = true;
+  toast.dismiss_callback = base::BindRepeating(&OnToastClicked);
   ash::ToastManager::Get()->Show(toast);
 }
 
diff --git a/chrome/browser/ash/policy/dlp/dlp_notification_helper.cc b/chrome/browser/ash/policy/dlp/dlp_notification_helper.cc
index b24269ee..d438f2c0 100644
--- a/chrome/browser/ash/policy/dlp/dlp_notification_helper.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_notification_helper.cc
@@ -135,4 +135,10 @@
                     DlpWarnDialog::Restriction::kScreenCapture);
 }
 
+void ShowDlpVideoCaptureWarningDialog(base::OnceClosure continue_cb,
+                                      base::OnceClosure cancel_cb) {
+  ShowDlpWarnDialog(std::move(continue_cb), std::move(cancel_cb),
+                    DlpWarnDialog::Restriction::kVideoCapture);
+}
+
 }  // namespace policy
diff --git a/chrome/browser/ash/policy/dlp/dlp_notification_helper.h b/chrome/browser/ash/policy/dlp/dlp_notification_helper.h
index 26f6a487..f59b121 100644
--- a/chrome/browser/ash/policy/dlp/dlp_notification_helper.h
+++ b/chrome/browser/ash/policy/dlp/dlp_notification_helper.h
@@ -38,6 +38,12 @@
 void ShowDlpScreenCaptureWarningDialog(base::OnceClosure continue_cb,
                                        base::OnceClosure cancel_cb);
 
+// Shows a warning dialog that video capture is not recommended and allows the
+// user to choose whether to save it or not. Based on the response, only one of
+// |continue_cb| and |cancel_cb| will run.
+void ShowDlpVideoCaptureWarningDialog(base::OnceClosure continue_cb,
+                                      base::OnceClosure cancel_cb);
+
 }  // namespace policy
 
 #endif  // CHROME_BROWSER_ASH_POLICY_DLP_DLP_NOTIFICATION_HELPER_H_
diff --git a/chrome/browser/ash/policy/dlp/dlp_warn_dialog.cc b/chrome/browser/ash/policy/dlp/dlp_warn_dialog.cc
index 27b89b5e..050da4a 100644
--- a/chrome/browser/ash/policy/dlp/dlp_warn_dialog.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_warn_dialog.cc
@@ -70,6 +70,9 @@
     case DlpWarnDialog::Restriction::kScreenCapture:
       return l10n_util::GetStringUTF16(
           IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_CONTINUE_BUTTON);
+    case DlpWarnDialog::Restriction::kVideoCapture:
+      return l10n_util::GetStringUTF16(
+          IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CONTINUE_BUTTON);
     case DlpWarnDialog::Restriction::kPrinting:
       return l10n_util::GetStringUTF16(
           IDS_POLICY_DLP_PRINTING_WARN_CONTINUE_BUTTON);
@@ -82,6 +85,9 @@
     case DlpWarnDialog::Restriction::kScreenCapture:
       return l10n_util::GetStringUTF16(
           IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_CANCEL_BUTTON);
+    case DlpWarnDialog::Restriction::kVideoCapture:
+      return l10n_util::GetStringUTF16(
+          IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CANCEL_BUTTON);
     case DlpWarnDialog::Restriction::kPrinting:
       return l10n_util::GetStringUTF16(
           IDS_POLICY_DLP_PRINTING_WARN_CANCEL_BUTTON);
@@ -93,6 +99,8 @@
     case DlpWarnDialog::Restriction::kScreenCapture:
       return l10n_util::GetStringUTF16(
           IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_TITLE);
+    case DlpWarnDialog::Restriction::kVideoCapture:
+      return l10n_util::GetStringUTF16(IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_TITLE);
     case DlpWarnDialog::Restriction::kPrinting:
       return l10n_util::GetStringUTF16(IDS_POLICY_DLP_PRINTING_WARN_TITLE);
   }
@@ -103,6 +111,9 @@
     case DlpWarnDialog::Restriction::kScreenCapture:
       return l10n_util::GetStringUTF16(
           IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_MESSAGE);
+    case DlpWarnDialog::Restriction::kVideoCapture:
+      return l10n_util::GetStringUTF16(
+          IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_MESSAGE);
     case DlpWarnDialog::Restriction::kPrinting:
       return l10n_util::GetStringUTF16(IDS_POLICY_DLP_PRINTING_WARN_MESSAGE);
   }
diff --git a/chrome/browser/ash/policy/dlp/dlp_warn_dialog.h b/chrome/browser/ash/policy/dlp/dlp_warn_dialog.h
index e23bb011..1dcc326 100644
--- a/chrome/browser/ash/policy/dlp/dlp_warn_dialog.h
+++ b/chrome/browser/ash/policy/dlp/dlp_warn_dialog.h
@@ -16,7 +16,7 @@
  public:
   METADATA_HEADER(DlpWarnDialog);
 
-  enum Restriction { kScreenCapture, kPrinting };
+  enum class Restriction { kScreenCapture, kVideoCapture, kPrinting };
 
   DlpWarnDialog(base::OnceClosure accept_callback,
                 base::OnceClosure cancel_callback,
diff --git a/chrome/browser/ash/printing/DIR_METADATA b/chrome/browser/ash/printing/DIR_METADATA
index 939d296..bcaf2b74 100644
--- a/chrome/browser/ash/printing/DIR_METADATA
+++ b/chrome/browser/ash/printing/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>Printing>CUPS"
-}
-team_email: "cros-printing-dev@chromium.org"
+mixins: "//chromeos/printing/COMMON_METADATA"
diff --git a/chrome/browser/ash/quick_pair/DIR_METADATA b/chrome/browser/ash/quick_pair/DIR_METADATA
index 4891ec87..8ce78732 100644
--- a/chrome/browser/ash/quick_pair/DIR_METADATA
+++ b/chrome/browser/ash/quick_pair/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "OS>Systems>Multidevice>FastPair"
-}
+mixins: "//ash/quick_pair/COMMON_METADATA"
diff --git a/chrome/browser/ash/remote_apps/remote_apps_manager.cc b/chrome/browser/ash/remote_apps/remote_apps_manager.cc
index 4171cebe..196d8b4 100644
--- a/chrome/browser/ash/remote_apps/remote_apps_manager.cc
+++ b/chrome/browser/ash/remote_apps/remote_apps_manager.cc
@@ -328,11 +328,11 @@
       item->SetName(folder_info.name);
       item->SetIsPersistent(true);
 
-      if (folder_info.add_to_front) {
-        item->SetPosition(model_updater_->GetPositionBeforeFirstItem());
-      } else {
-        item->SetPosition(model_updater_->GetFirstAvailablePosition());
-      }
+      syncer::StringOrdinal item_position =
+          folder_info.add_to_front
+              ? model_updater_->GetPositionBeforeFirstItem()
+              : model_updater_->GetFirstAvailablePosition();
+      model_updater_->SetItemPosition(item->id(), item_position);
     }
   }
 
diff --git a/chrome/browser/ash/settings/DIR_METADATA b/chrome/browser/ash/settings/DIR_METADATA
index 543dab0e..f88e446 100644
--- a/chrome/browser/ash/settings/DIR_METADATA
+++ b/chrome/browser/ash/settings/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "OS>Software>Enterprise"
-}
+mixins: "//chromeos/settings/COMMON_METADATA"
diff --git a/chrome/browser/ash/settings/cros_settings_unittest.cc b/chrome/browser/ash/settings/cros_settings_unittest.cc
index 8a8cfc1..9346bbb 100644
--- a/chrome/browser/ash/settings/cros_settings_unittest.cc
+++ b/chrome/browser/ash/settings/cros_settings_unittest.cc
@@ -93,7 +93,7 @@
         OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
     DCHECK(service);
 
-    service->OnTPMTokenReady(true);
+    service->OnTPMTokenReady();
     task_environment_.RunUntilIdle();
     DCHECK(service->IsOwner());
     return service;
diff --git a/chrome/browser/ash/settings/device_settings_service_unittest.cc b/chrome/browser/ash/settings/device_settings_service_unittest.cc
index f549077..f14e9d0 100644
--- a/chrome/browser/ash/settings/device_settings_service_unittest.cc
+++ b/chrome/browser/ash/settings/device_settings_service_unittest.cc
@@ -288,7 +288,7 @@
             device_settings_service_->GetOwnershipStatus());
   EXPECT_FALSE(is_owner_set_);
 
-  service->OnTPMTokenReady(true /* is ready */);
+  service->OnTPMTokenReady();
   FlushDeviceSettings();
 
   EXPECT_FALSE(device_settings_service_->HasPrivateOwnerKey());
@@ -328,7 +328,7 @@
             device_settings_service_->GetOwnershipStatus());
 
   owner_key_util_->SetPrivateKey(device_policy_->GetSigningKey());
-  service->OnTPMTokenReady(true /* is ready */);
+  service->OnTPMTokenReady();
   FlushDeviceSettings();
 
   EXPECT_TRUE(device_settings_service_->HasPrivateOwnerKey());
@@ -366,7 +366,7 @@
   EXPECT_FALSE(is_owner_set_);
 
   owner_key_util_->SetPrivateKey(device_policy_->GetSigningKey());
-  service->OnTPMTokenReady(true /* is ready */);
+  service->OnTPMTokenReady();
   FlushDeviceSettings();
 
   EXPECT_TRUE(device_settings_service_->HasPrivateOwnerKey());
@@ -493,7 +493,7 @@
 
   // Load the private key and trigger a reload. Load operations should finish.
   owner_key_util_->SetPrivateKey(device_policy_->GetSigningKey());
-  service->OnTPMTokenReady(true /* is ready */);
+  service->OnTPMTokenReady();
   FlushDeviceSettings();
 
   // Verify owner key is loaded and ownership status is updated.
diff --git a/chrome/browser/ash/settings/device_settings_test_helper.cc b/chrome/browser/ash/settings/device_settings_test_helper.cc
index 2194550..3f8de88 100644
--- a/chrome/browser/ash/settings/device_settings_test_helper.cc
+++ b/chrome/browser/ash/settings/device_settings_test_helper.cc
@@ -125,7 +125,7 @@
       OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
   CHECK(service);
   if (tpm_is_ready)
-    service->OnTPMTokenReady(true /* token is enabled */);
+    service->OnTPMTokenReady();
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc b/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc
index fee60f0..22e66f93 100644
--- a/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc
+++ b/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc
@@ -61,7 +61,7 @@
         keys);
     std::unique_ptr<TestingProfile> user = std::make_unique<TestingProfile>();
     OwnerSettingsServiceAshFactory::GetForBrowserContext(user.get())
-        ->OnTPMTokenReady(true);
+        ->OnTPMTokenReady();
     content::RunAllTasksUntilIdle();
     return user;
   }
diff --git a/chrome/browser/ash/tether/DIR_METADATA b/chrome/browser/ash/tether/DIR_METADATA
new file mode 100644
index 0000000..c34c17f
--- /dev/null
+++ b/chrome/browser/ash/tether/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chromeos/components/tether/COMMON_METADATA"
diff --git a/chrome/browser/ash/web_applications/file_manager_web_app_info.cc b/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
index 8c48f4a..adbdd63 100644
--- a/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
+++ b/chrome/browser/ash/web_applications/file_manager_web_app_info.cc
@@ -13,14 +13,15 @@
 #include "chrome/browser/ash/web_applications/system_web_app_install_utils.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_application_info.h"
+#include "chrome/grit/generated_resources.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
+#include "ui/base/l10n/l10n_util.h"
 
 std::unique_ptr<WebApplicationInfo> CreateWebAppInfoForFileManager() {
   auto info = std::make_unique<WebApplicationInfo>();
   info->start_url = GURL(ash::file_manager::kChromeUIFileManagerURL);
   info->scope = GURL(ash::file_manager::kChromeUIFileManagerURL);
-  // TODO(majewski): Fetch from a resource.
-  info->title = u"File Manager";
+  info->title = l10n_util::GetStringUTF16(IDS_FILEMANAGER_APP_NAME);
   web_app::CreateIconInfoForSystemWebApp(
       info->start_url,
       {{"icon192.png", 192, IDR_FILE_MANAGER_SWA_IMAGES_ICON192_PNG}}, *info);
diff --git a/chrome/browser/attribution_reporting/DIR_METADATA b/chrome/browser/attribution_reporting/DIR_METADATA
new file mode 100644
index 0000000..0598e0e
--- /dev/null
+++ b/chrome/browser/attribution_reporting/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/attribution_reporting/COMMON_METADATA"
diff --git a/chrome/browser/attribution_reporting/android/DIR_METADATA b/chrome/browser/attribution_reporting/android/DIR_METADATA
index d263372e..8fc9919 100644
--- a/chrome/browser/attribution_reporting/android/DIR_METADATA
+++ b/chrome/browser/attribution_reporting/android/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>ConversionMeasurement"
-}
 os: ANDROID
diff --git a/chrome/browser/autofill/DIR_METADATA b/chrome/browser/autofill/DIR_METADATA
new file mode 100644
index 0000000..bc280336
--- /dev/null
+++ b/chrome/browser/autofill/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/autofill/COMMON_METADATA"
diff --git a/chrome/browser/background_fetch/DIR_METADATA b/chrome/browser/background_fetch/DIR_METADATA
index 774edd1..7a535e15 100644
--- a/chrome/browser/background_fetch/DIR_METADATA
+++ b/chrome/browser/background_fetch/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>BackgroundFetch"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//content/browser/background_fetch/COMMON_METADATA"
diff --git a/chrome/browser/background_sync/DIR_METADATA b/chrome/browser/background_sync/DIR_METADATA
new file mode 100644
index 0000000..8a6d80f
--- /dev/null
+++ b/chrome/browser/background_sync/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/background_sync/COMMON_METADATA"
diff --git a/chrome/browser/badging/COMMON_METADATA b/chrome/browser/badging/COMMON_METADATA
new file mode 100644
index 0000000..c8b762a
--- /dev/null
+++ b/chrome/browser/badging/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org"
diff --git a/chrome/browser/badging/DIR_METADATA b/chrome/browser/badging/DIR_METADATA
index c8b762a..b7768f9 100644
--- a/chrome/browser/badging/DIR_METADATA
+++ b/chrome/browser/badging/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
+mixins: "//chrome/browser/badging/COMMON_METADATA"
diff --git a/chrome/browser/banners/COMMON_METADATA b/chrome/browser/banners/COMMON_METADATA
new file mode 100644
index 0000000..c8b762a
--- /dev/null
+++ b/chrome/browser/banners/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org"
diff --git a/chrome/browser/banners/DIR_METADATA b/chrome/browser/banners/DIR_METADATA
index c8b762a..3d423c7 100644
--- a/chrome/browser/banners/DIR_METADATA
+++ b/chrome/browser/banners/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
+mixins: "//chrome/browser/banners/COMMON_METADATA"
diff --git a/chrome/browser/bluetooth/DIR_METADATA b/chrome/browser/bluetooth/DIR_METADATA
index d8105565..cd51015 100644
--- a/chrome/browser/bluetooth/DIR_METADATA
+++ b/chrome/browser/bluetooth/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>Bluetooth"
-}
-team_email: "web-bluetooth@chromium.org"
+mixins: "//content/browser/bluetooth/COMMON_METADATA"
diff --git a/chrome/browser/browser_controls/android/DIR_METADATA b/chrome/browser/browser_controls/android/DIR_METADATA
index c51c729..c69388e 100644
--- a/chrome/browser/browser_controls/android/DIR_METADATA
+++ b/chrome/browser/browser_controls/android/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Mobile"
-}
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/chrome/browser/browsing_data/DIR_METADATA b/chrome/browser/browsing_data/DIR_METADATA
index ff46333..ce654ba 100644
--- a/chrome/browser/browsing_data/DIR_METADATA
+++ b/chrome/browser/browsing_data/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Privacy"
-}
+mixins: "//content/browser/browsing_data/COMMON_METADATA"
diff --git a/chrome/browser/cart/COMMON_METADATA b/chrome/browser/cart/COMMON_METADATA
new file mode 100644
index 0000000..2cb1250
--- /dev/null
+++ b/chrome/browser/cart/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Shopping"
+}
diff --git a/chrome/browser/cart/DIR_METADATA b/chrome/browser/cart/DIR_METADATA
index 2cb1250..fc2f072d 100644
--- a/chrome/browser/cart/DIR_METADATA
+++ b/chrome/browser/cart/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Shopping"
-}
+mixins: "//chrome/browser/cart/COMMON_METADATA"
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index 915c4a9..100e18b 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -58,8 +58,6 @@
 //                                               NssCertDatabaseGetter
 //                                                         |
 //                               CertificateManagerModel::DidGetCertDBOnIOThread
-//                                                         |
-//                                       crypto::IsTPMTokenEnabledForNSS
 //                  v--------------------------------------/
 // CertificateManagerModel::DidGetCertDBOnUIThread
 //                  |
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index f0dad8a..5f0fb87 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1678,8 +1678,8 @@
     "../ash/login/easy_unlock/easy_unlock_service_factory.h",
     "../ash/login/easy_unlock/easy_unlock_service_regular.cc",
     "../ash/login/easy_unlock/easy_unlock_service_regular.h",
-    "../ash/login/easy_unlock/easy_unlock_service_signin_chromeos.cc",
-    "../ash/login/easy_unlock/easy_unlock_service_signin_chromeos.h",
+    "../ash/login/easy_unlock/easy_unlock_service_signin.cc",
+    "../ash/login/easy_unlock/easy_unlock_service_signin.h",
     "../ash/login/easy_unlock/easy_unlock_tpm_key_manager.cc",
     "../ash/login/easy_unlock/easy_unlock_tpm_key_manager.h",
     "../ash/login/easy_unlock/easy_unlock_tpm_key_manager_factory.cc",
@@ -3063,10 +3063,10 @@
     "locale_change_guard.h",
     "logging.cc",
     "logging.h",
-    "net/client_cert_filter_chromeos.cc",
-    "net/client_cert_filter_chromeos.h",
-    "net/client_cert_store_chromeos.cc",
-    "net/client_cert_store_chromeos.h",
+    "net/client_cert_filter.cc",
+    "net/client_cert_filter.h",
+    "net/client_cert_store_ash.cc",
+    "net/client_cert_store_ash.h",
     "net/delay_network_call.cc",
     "net/delay_network_call.h",
     "net/dhcp_wpad_url_client.cc",
@@ -4379,7 +4379,7 @@
     "fileapi/recent_model_unittest.cc",
     "fileapi/test/fake_recent_source.cc",
     "locale_change_guard_unittest.cc",
-    "net/client_cert_store_chromeos_unittest.cc",
+    "net/client_cert_store_ash_unittest.cc",
     "net/network_diagnostics/arc_dns_resolution_routine_unittest.cc",
     "net/network_diagnostics/arc_http_routine_unittest.cc",
     "net/network_diagnostics/arc_ping_routine_unittest.cc",
diff --git a/chrome/browser/chromeos/app_mode/DIR_METADATA b/chrome/browser/chromeos/app_mode/DIR_METADATA
new file mode 100644
index 0000000..d4effef
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ash/app_mode/COMMON_METADATA"
diff --git a/chrome/browser/chromeos/extensions/DIR_METADATA b/chrome/browser/chromeos/extensions/DIR_METADATA
index 9a42572..e1d704c 100644
--- a/chrome/browser/chromeos/extensions/DIR_METADATA
+++ b/chrome/browser/chromeos/extensions/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Platform>Extensions"
-}
+mixins: "//extensions/COMMON_METADATA"
diff --git a/chrome/browser/chromeos/extensions/file_manager/DIR_METADATA b/chrome/browser/chromeos/extensions/file_manager/DIR_METADATA
new file mode 100644
index 0000000..e9400b87
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//ui/file_manager/COMMON_METADATA"
diff --git a/chrome/browser/chromeos/net/client_cert_filter.cc b/chrome/browser/chromeos/net/client_cert_filter.cc
new file mode 100644
index 0000000..a11ddb8f
--- /dev/null
+++ b/chrome/browser/chromeos/net/client_cert_filter.cc
@@ -0,0 +1,148 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/net/client_cert_filter.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "crypto/nss_util_internal.h"
+#include "crypto/scoped_nss_types.h"
+#include "net/cert/nss_profile_filter_chromeos.h"
+
+namespace chromeos {
+
+class ClientCertFilter::CertFilterIO {
+ public:
+  CertFilterIO(bool use_system_slot, const std::string& username_hash)
+      : use_system_slot_(use_system_slot), username_hash_(username_hash) {}
+
+  // Must be called on the IO thread. Calls |callback| on the UI thread.
+  void Init(base::OnceClosure callback) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    DCHECK(!init_called_);
+    init_called_ = true;
+
+    waiting_for_private_slot_ = true;
+
+    private_slot_ = crypto::GetPrivateSlotForChromeOSUser(
+        username_hash_, base::BindOnce(&CertFilterIO::GotPrivateSlot,
+                                       weak_ptr_factory_.GetWeakPtr()));
+
+    // If the returned slot is null, GotPrivateSlot will be called back
+    // eventually. If it is not null, the private slot was available
+    // synchronously and the callback will not be called.
+    if (private_slot_)
+      waiting_for_private_slot_ = false;
+
+    init_callback_ = std::move(callback);
+
+    if (use_system_slot_) {
+      crypto::GetSystemNSSKeySlot(base::BindOnce(
+          &CertFilterIO::GotSystemSlot, weak_ptr_factory_.GetWeakPtr()));
+      return;
+    }
+
+    InitIfSlotsAvailable();
+  }
+
+  // May be called on any thread, after Init()'s callback has run.
+  bool IsCertAllowed(CERTCertificate* cert) {
+    return nss_profile_filter_.IsCertAllowed(cert);
+  }
+
+ private:
+  // Called back if the system slot was retrieved asynchronously. Continues the
+  // initialization.
+  void GotSystemSlot(crypto::ScopedPK11Slot system_slot) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    system_slot_ = std::move(system_slot);
+    InitIfSlotsAvailable();
+  }
+
+  // Called back if the private slot was retrieved asynchronously. Continues the
+  // initialization.
+  void GotPrivateSlot(crypto::ScopedPK11Slot private_slot) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    waiting_for_private_slot_ = false;
+    private_slot_ = std::move(private_slot);
+    InitIfSlotsAvailable();
+  }
+
+  // If the required slots (|private_slot_| and conditionally |system_slot_|)
+  // are available, initializes |nss_profile_filter_| and posts |init_callback_|
+  // to the UI thread.
+  void InitIfSlotsAvailable() {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    if ((use_system_slot_ && !system_slot_) || waiting_for_private_slot_)
+      return;
+    nss_profile_filter_.Init(
+        crypto::GetPublicSlotForChromeOSUser(username_hash_),
+        std::move(private_slot_), std::move(system_slot_));
+    if (!init_callback_.is_null()) {
+      content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
+                                                   std::move(init_callback_));
+    }
+  }
+
+  // True once Init() was called.
+  bool init_called_ = false;
+
+  // The callback provided to Init(). Called on the UI thread.
+  base::OnceClosure init_callback_;
+
+  bool use_system_slot_;
+  std::string username_hash_;
+
+  // Used to store the system slot, if required, for initialization. Will be
+  // null after the filter is initialized.
+  crypto::ScopedPK11Slot system_slot_;
+
+  // Used to store the private slot for initialization. Will be null after the
+  // filter is initialized.
+  crypto::ScopedPK11Slot private_slot_;
+
+  // If a private slot is requested but the slot, maybe null, is not obtained
+  // yet, this is equal true. As long as this is true, the NSSProfileFilter will
+  // not be initialized.
+  bool waiting_for_private_slot_ = false;
+
+  net::NSSProfileFilterChromeOS nss_profile_filter_;
+  base::WeakPtrFactory<CertFilterIO> weak_ptr_factory_{this};
+};
+
+ClientCertFilter::ClientCertFilter(bool use_system_slot,
+                                   const std::string& username_hash)
+    : cert_filter_io_(new CertFilterIO(use_system_slot, username_hash)) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
+
+ClientCertFilter::~ClientCertFilter() {}
+
+bool ClientCertFilter::Init(base::OnceClosure callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // base::Unretained() is safe here because |cert_filter_io_| is destroyed on
+  // a post to the IO thread.
+  content::GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &CertFilterIO::Init, base::Unretained(cert_filter_io_.get()),
+          // Wrap |callback| in OnInitComplete so it is cancelled if the
+          // ClientCertFilter is destroyed earlier.
+          base::BindOnce(&ClientCertFilter::OnInitComplete,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
+  return false;
+}
+
+bool ClientCertFilter::IsCertAllowed(CERTCertificate* cert) const {
+  return cert_filter_io_->IsCertAllowed(cert);
+}
+
+void ClientCertFilter::OnInitComplete(base::OnceClosure callback) {
+  std::move(callback).Run();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/client_cert_filter.h b/chrome/browser/chromeos/net/client_cert_filter.h
new file mode 100644
index 0000000..ff70520
--- /dev/null
+++ b/chrome/browser/chromeos/net/client_cert_filter.h
@@ -0,0 +1,57 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_FILTER_H_
+#define CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_FILTER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/browser_thread.h"
+
+typedef struct CERTCertificateStr CERTCertificate;
+
+namespace chromeos {
+
+// A client certificate filter that filters by applying a
+// NSSProfileFilterChromeOS.
+//
+// TODO(davidben): Fold this class back into ClientCertStoreAsh.
+class ClientCertFilter {
+ public:
+  // The internal NSSProfileFilterChromeOS will be initialized with the public
+  // and private slot of the user with |username_hash| and with the system slot
+  // if |use_system_slot| is true.
+  // If |username_hash| is empty, no public and no private slot will be used.
+  ClientCertFilter(bool use_system_slot, const std::string& username_hash);
+  ~ClientCertFilter();
+
+  // Initializes this filter. Returns true if it finished initialization,
+  // otherwise returns false and calls |callback| once the initialization is
+  // completed.
+  // Must be called at most once.
+  bool Init(base::OnceClosure callback);
+
+  // Returns true if |cert| is allowed to be used as a client certificate (e.g.
+  // for a certain browser context or user). This is only called once
+  // initialization is finished, see Init().
+  bool IsCertAllowed(CERTCertificate* cert) const;
+
+ private:
+  class CertFilterIO;
+
+  void OnInitComplete(base::OnceClosure callback);
+
+  // This class lives on the UI thread but the NSS ChromeOS user integration
+  // must be called from the IO thread.
+  std::unique_ptr<CertFilterIO, content::BrowserThread::DeleteOnIOThread>
+      cert_filter_io_;
+  base::WeakPtrFactory<ClientCertFilter> weak_ptr_factory_{this};
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_FILTER_H_
diff --git a/chrome/browser/chromeos/net/client_cert_filter_chromeos.cc b/chrome/browser/chromeos/net/client_cert_filter_chromeos.cc
deleted file mode 100644
index a3039c3..0000000
--- a/chrome/browser/chromeos/net/client_cert_filter_chromeos.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/net/client_cert_filter_chromeos.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "crypto/nss_util_internal.h"
-#include "crypto/scoped_nss_types.h"
-#include "net/cert/nss_profile_filter_chromeos.h"
-
-namespace chromeos {
-
-class ClientCertFilterChromeOS::CertFilterIO {
- public:
-  CertFilterIO(bool use_system_slot, const std::string& username_hash)
-      : use_system_slot_(use_system_slot), username_hash_(username_hash) {}
-
-  // Must be called on the IO thread. Calls |callback| on the UI thread.
-  void Init(base::OnceClosure callback) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    DCHECK(!init_called_);
-    init_called_ = true;
-
-    waiting_for_private_slot_ = true;
-
-    if (use_system_slot_) {
-      system_slot_ = crypto::GetSystemNSSKeySlot(base::BindOnce(
-          &CertFilterIO::GotSystemSlot, weak_ptr_factory_.GetWeakPtr()));
-    }
-
-    private_slot_ = crypto::GetPrivateSlotForChromeOSUser(
-        username_hash_, base::BindOnce(&CertFilterIO::GotPrivateSlot,
-                                       weak_ptr_factory_.GetWeakPtr()));
-
-    // If the returned slot is null, GotPrivateSlot will be called back
-    // eventually. If it is not null, the private slot was available
-    // synchronously and the callback will not be called.
-    if (private_slot_)
-      waiting_for_private_slot_ = false;
-
-    init_callback_ = std::move(callback);
-    InitIfSlotsAvailable();
-  }
-
-  // May be called on any thread, after Init()'s callback has run.
-  bool IsCertAllowed(CERTCertificate* cert) {
-    return nss_profile_filter_.IsCertAllowed(cert);
-  }
-
- private:
-  // Called back if the system slot was retrieved asynchronously. Continues the
-  // initialization.
-  void GotSystemSlot(crypto::ScopedPK11Slot system_slot) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    system_slot_ = std::move(system_slot);
-    InitIfSlotsAvailable();
-  }
-
-  // Called back if the private slot was retrieved asynchronously. Continues the
-  // initialization.
-  void GotPrivateSlot(crypto::ScopedPK11Slot private_slot) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    waiting_for_private_slot_ = false;
-    private_slot_ = std::move(private_slot);
-    InitIfSlotsAvailable();
-  }
-
-  // If the required slots (|private_slot_| and conditionally |system_slot_|)
-  // are available, initializes |nss_profile_filter_| and posts |init_callback_|
-  // to the UI thread.
-  void InitIfSlotsAvailable() {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    if ((use_system_slot_ && !system_slot_) || waiting_for_private_slot_)
-      return;
-    nss_profile_filter_.Init(
-        crypto::GetPublicSlotForChromeOSUser(username_hash_),
-        std::move(private_slot_), std::move(system_slot_));
-    if (!init_callback_.is_null()) {
-      content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
-                                                   std::move(init_callback_));
-    }
-  }
-
-  // True once Init() was called.
-  bool init_called_ = false;
-
-  // The callback provided to Init(). Called on the UI thread.
-  base::OnceClosure init_callback_;
-
-  bool use_system_slot_;
-  std::string username_hash_;
-
-  // Used to store the system slot, if required, for initialization. Will be
-  // null after the filter is initialized.
-  crypto::ScopedPK11Slot system_slot_;
-
-  // Used to store the private slot for initialization. Will be null after the
-  // filter is initialized.
-  crypto::ScopedPK11Slot private_slot_;
-
-  // If a private slot is requested but the slot, maybe null, is not obtained
-  // yet, this is equal true. As long as this is true, the NSSProfileFilter will
-  // not be initialized.
-  bool waiting_for_private_slot_ = false;
-
-  net::NSSProfileFilterChromeOS nss_profile_filter_;
-  base::WeakPtrFactory<CertFilterIO> weak_ptr_factory_{this};
-};
-
-ClientCertFilterChromeOS::ClientCertFilterChromeOS(
-    bool use_system_slot,
-    const std::string& username_hash)
-    : cert_filter_io_(new CertFilterIO(use_system_slot, username_hash)) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-}
-
-ClientCertFilterChromeOS::~ClientCertFilterChromeOS() {}
-
-bool ClientCertFilterChromeOS::Init(base::OnceClosure callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  // base::Unretained() is safe here because |cert_filter_io_| is destroyed on
-  // a post to the IO thread.
-  content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &CertFilterIO::Init, base::Unretained(cert_filter_io_.get()),
-          // Wrap |callback| in OnInitComplete so it is cancelled if the
-          // ClientCertFilterChromeOS is destroyed earlier.
-          base::BindOnce(&ClientCertFilterChromeOS::OnInitComplete,
-                         weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
-  return false;
-}
-
-bool ClientCertFilterChromeOS::IsCertAllowed(CERTCertificate* cert) const {
-  return cert_filter_io_->IsCertAllowed(cert);
-}
-
-void ClientCertFilterChromeOS::OnInitComplete(base::OnceClosure callback) {
-  std::move(callback).Run();
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/client_cert_filter_chromeos.h b/chrome/browser/chromeos/net/client_cert_filter_chromeos.h
deleted file mode 100644
index 1ec989b0..0000000
--- a/chrome/browser/chromeos/net/client_cert_filter_chromeos.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_FILTER_CHROMEOS_H_
-#define CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_FILTER_CHROMEOS_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "content/public/browser/browser_thread.h"
-
-typedef struct CERTCertificateStr CERTCertificate;
-
-namespace chromeos {
-
-// A client certificate filter that filters by applying a
-// NSSProfileFilterChromeOS.
-//
-// TODO(davidben): Fold this class back into ClientCertStoreChromeOS.
-class ClientCertFilterChromeOS {
- public:
-  // The internal NSSProfileFilterChromeOS will be initialized with the public
-  // and private slot of the user with |username_hash| and with the system slot
-  // if |use_system_slot| is true.
-  // If |username_hash| is empty, no public and no private slot will be used.
-  ClientCertFilterChromeOS(bool use_system_slot,
-                           const std::string& username_hash);
-  ~ClientCertFilterChromeOS();
-
-  // Initializes this filter. Returns true if it finished initialization,
-  // otherwise returns false and calls |callback| once the initialization is
-  // completed.
-  // Must be called at most once.
-  bool Init(base::OnceClosure callback);
-
-  // Returns true if |cert| is allowed to be used as a client certificate (e.g.
-  // for a certain browser context or user). This is only called once
-  // initialization is finished, see Init().
-  bool IsCertAllowed(CERTCertificate* cert) const;
-
- private:
-  class CertFilterIO;
-
-  void OnInitComplete(base::OnceClosure callback);
-
-  // This class lives on the UI thread but the NSS ChromeOS user integration
-  // must be called from the IO thread.
-  std::unique_ptr<CertFilterIO, content::BrowserThread::DeleteOnIOThread>
-      cert_filter_io_;
-  base::WeakPtrFactory<ClientCertFilterChromeOS> weak_ptr_factory_{this};
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_FILTER_CHROMEOS_H_
diff --git a/chrome/browser/chromeos/net/client_cert_store_ash.cc b/chrome/browser/chromeos/net/client_cert_store_ash.cc
new file mode 100644
index 0000000..8859da5
--- /dev/null
+++ b/chrome/browser/chromeos/net/client_cert_store_ash.cc
@@ -0,0 +1,108 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/net/client_cert_store_ash.h"
+
+#include <cert.h>
+#include <algorithm>
+#include <iterator>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "chrome/browser/ash/certificate_provider/certificate_provider.h"
+#include "chrome/browser/chromeos/net/client_cert_filter.h"
+#include "crypto/nss_crypto_module_delegate.h"
+#include "net/ssl/ssl_cert_request_info.h"
+#include "net/ssl/ssl_private_key.h"
+
+namespace chromeos {
+
+ClientCertStoreAsh::ClientCertStoreAsh(
+    std::unique_ptr<CertificateProvider> cert_provider,
+    bool use_system_slot,
+    const std::string& username_hash,
+    const PasswordDelegateFactory& password_delegate_factory)
+    : cert_provider_(std::move(cert_provider)),
+      cert_filter_(use_system_slot, username_hash) {}
+
+ClientCertStoreAsh::~ClientCertStoreAsh() {}
+
+void ClientCertStoreAsh::GetClientCerts(
+    const net::SSLCertRequestInfo& cert_request_info,
+    ClientCertListCallback callback) {
+  // Caller is responsible for keeping the ClientCertStore alive until the
+  // callback is run.
+  base::OnceCallback<void(net::ClientCertIdentityList)>
+      get_platform_certs_and_filter = base::BindOnce(
+          &ClientCertStoreAsh::GotAdditionalCerts, base::Unretained(this),
+          base::Unretained(&cert_request_info), std::move(callback));
+
+  base::OnceClosure get_additional_certs_and_continue;
+  if (cert_provider_) {
+    get_additional_certs_and_continue =
+        base::BindOnce(&CertificateProvider::GetCertificates,
+                       base::Unretained(cert_provider_.get()),
+                       std::move(get_platform_certs_and_filter));
+  } else {
+    get_additional_certs_and_continue =
+        base::BindOnce(std::move(get_platform_certs_and_filter),
+                       net::ClientCertIdentityList());
+  }
+
+  auto split_callback =
+      base::SplitOnceCallback(std::move(get_additional_certs_and_continue));
+  if (cert_filter_.Init(std::move(split_callback.first))) {
+    std::move(split_callback.second).Run();
+  }
+}
+
+void ClientCertStoreAsh::GotAdditionalCerts(
+    const net::SSLCertRequestInfo* request,
+    ClientCertListCallback callback,
+    net::ClientCertIdentityList additional_certs) {
+  scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate;
+  if (!password_delegate_factory_.is_null())
+    password_delegate = password_delegate_factory_.Run(request->host_and_port);
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&ClientCertStoreAsh::GetAndFilterCertsOnWorkerThread,
+                     base::Unretained(this), password_delegate,
+                     base::Unretained(request), std::move(additional_certs)),
+      std::move(callback));
+}
+
+net::ClientCertIdentityList ClientCertStoreAsh::GetAndFilterCertsOnWorkerThread(
+    scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate>
+        password_delegate,
+    const net::SSLCertRequestInfo* request,
+    net::ClientCertIdentityList additional_certs) {
+  // This method may acquire the NSS lock or reenter this code via extension
+  // hooks (such as smart card UI). To ensure threads are not starved or
+  // deadlocked, the base::ScopedBlockingCall below increments the thread pool
+  // capacity if this method takes too much time to run.
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
+
+  net::ClientCertIdentityList client_certs;
+  net::ClientCertStoreNSS::GetPlatformCertsOnWorkerThread(
+      std::move(password_delegate),
+      base::BindRepeating(&ClientCertFilter::IsCertAllowed,
+                          base::Unretained(&cert_filter_)),
+      &client_certs);
+
+  client_certs.reserve(client_certs.size() + additional_certs.size());
+  for (std::unique_ptr<net::ClientCertIdentity>& cert : additional_certs)
+    client_certs.push_back(std::move(cert));
+  net::ClientCertStoreNSS::FilterCertsOnWorkerThread(&client_certs, *request);
+  return client_certs;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/client_cert_store_ash.h b/chrome/browser/chromeos/net/client_cert_store_ash.h
new file mode 100644
index 0000000..ced51026
--- /dev/null
+++ b/chrome/browser/chromeos/net/client_cert_store_ash.h
@@ -0,0 +1,66 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_STORE_ASH_H_
+#define CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_STORE_ASH_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+// TODO(https://crbug.com/1164001): forward declare when moved to ash.
+#include "chrome/browser/ash/certificate_provider/certificate_provider.h"
+#include "chrome/browser/chromeos/net/client_cert_filter.h"
+#include "net/ssl/client_cert_store_nss.h"
+
+namespace chromeos {
+
+class ClientCertStoreAsh : public net::ClientCertStore {
+ public:
+  using PasswordDelegateFactory =
+      net::ClientCertStoreNSS::PasswordDelegateFactory;
+
+  // This ClientCertStore will return client certs from the public
+  // and private slot of the user with |username_hash| and with the system slot
+  // if |use_system_slot| is true. If |username_hash| is empty, no public and no
+  // private slot will be used. It will additionally return certificates
+  // provided by |cert_provider|.
+  ClientCertStoreAsh(std::unique_ptr<CertificateProvider> cert_provider,
+                     bool use_system_slot,
+                     const std::string& username_hash,
+                     const PasswordDelegateFactory& password_delegate_factory);
+
+  ClientCertStoreAsh(const ClientCertStoreAsh&) = delete;
+  ClientCertStoreAsh& operator=(const ClientCertStoreAsh&) = delete;
+
+  ~ClientCertStoreAsh() override;
+
+  // net::ClientCertStore:
+  void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
+                      ClientCertListCallback callback) override;
+
+ private:
+  void GotAdditionalCerts(const net::SSLCertRequestInfo* request,
+                          ClientCertListCallback callback,
+                          net::ClientCertIdentityList additional_certs);
+
+  net::ClientCertIdentityList GetAndFilterCertsOnWorkerThread(
+      scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate>
+          password_delegate,
+      const net::SSLCertRequestInfo* request,
+      net::ClientCertIdentityList additional_certs);
+
+  std::unique_ptr<CertificateProvider> cert_provider_;
+  ClientCertFilter cert_filter_;
+
+  // The factory for creating the delegate for requesting a password to a
+  // PKCS#11 token. May be null.
+  PasswordDelegateFactory password_delegate_factory_;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_STORE_ASH_H_
diff --git a/chrome/browser/chromeos/net/client_cert_store_ash_unittest.cc b/chrome/browser/chromeos/net/client_cert_store_ash_unittest.cc
new file mode 100644
index 0000000..bcd502a1
--- /dev/null
+++ b/chrome/browser/chromeos/net/client_cert_store_ash_unittest.cc
@@ -0,0 +1,261 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/net/client_cert_store_ash.h"
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/files/file_path.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "chrome/browser/ash/certificate_provider/certificate_provider.h"
+#include "content/public/test/browser_task_environment.h"
+#include "crypto/nss_util.h"
+#include "crypto/nss_util_internal.h"
+#include "crypto/scoped_nss_types.h"
+#include "crypto/scoped_test_nss_chromeos_user.h"
+#include "crypto/scoped_test_nss_db.h"
+#include "crypto/scoped_test_system_nss_key_slot.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util_nss.h"
+#include "net/ssl/client_cert_identity_test_util.h"
+#include "net/ssl/ssl_cert_request_info.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace {
+
+// "CN=B CA" - DER encoded DN of the issuer of client_1.pem
+const unsigned char kAuthority1DN[] = {0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b,
+                                       0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+                                       0x04, 0x42, 0x20, 0x43, 0x41};
+
+void SaveIdentitiesAndQuitCallback(net::ClientCertIdentityList* out_identities,
+                                   base::OnceClosure quit_closure,
+                                   net::ClientCertIdentityList in_identities) {
+  *out_identities = std::move(in_identities);
+  std::move(quit_closure).Run();
+}
+
+}  // namespace
+
+class ClientCertStoreAshTest : public ::testing::Test {
+ public:
+  ClientCertStoreAshTest() {}
+
+  void SetUp() override {
+    ASSERT_TRUE(user1_.constructed_successfully());
+    ASSERT_TRUE(user2_.constructed_successfully());
+    ASSERT_TRUE(system_slot_.ConstructedSuccessfully());
+  }
+
+  scoped_refptr<net::X509Certificate> ImportCertToSlot(
+      const std::string& cert_filename,
+      const std::string& key_filename,
+      PK11SlotInfo* slot) {
+    return net::ImportClientCertAndKeyFromFile(
+        net::GetTestCertsDirectory(), cert_filename, key_filename, slot);
+  }
+
+ protected:
+  crypto::ScopedTestNSSChromeOSUser user1_{"user1"};
+  crypto::ScopedTestNSSChromeOSUser user2_{"user2"};
+  crypto::ScopedTestSystemNSSKeySlot system_slot_{
+      /*simulate_token_loader=*/true};
+  content::BrowserTaskEnvironment task_environment_;
+};
+
+// Ensure that cert requests, that are started before the filter is initialized,
+// will wait for the initialization and succeed afterwards.
+TEST_F(ClientCertStoreAshTest, RequestWaitsForNSSInitAndSucceeds) {
+  ClientCertStoreAsh store(nullptr /* no additional provider */,
+                           /*use_system_slot=*/false, user1_.username_hash(),
+                           ClientCertStoreAsh::PasswordDelegateFactory());
+
+  scoped_refptr<net::X509Certificate> cert_1(ImportCertToSlot(
+      "client_1.pem", "client_1.pk8",
+      crypto::GetPublicSlotForChromeOSUser(user1_.username_hash()).get()));
+  ASSERT_TRUE(cert_1);
+
+  // Request any client certificate, which is expected to match client_1.
+  auto request_all = base::MakeRefCounted<net::SSLCertRequestInfo>();
+
+  net::ClientCertIdentityList selected_identities;
+  base::RunLoop run_loop;
+  store.GetClientCerts(
+      *request_all,
+      base::BindOnce(SaveIdentitiesAndQuitCallback, &selected_identities,
+                     run_loop.QuitClosure()));
+
+  {
+    base::RunLoop run_loop_inner;
+    run_loop_inner.RunUntilIdle();
+    // GetClientCerts should wait for the initialization of the filter to
+    // finish.
+    ASSERT_EQ(0u, selected_identities.size());
+  }
+
+  user1_.FinishInit();
+  run_loop.Run();
+
+  ASSERT_EQ(1u, selected_identities.size());
+}
+
+// Ensure that cert requests, that are started after the filter was initialized,
+// will succeed.
+TEST_F(ClientCertStoreAshTest, RequestsAfterNSSInitSucceed) {
+  user1_.FinishInit();
+
+  ClientCertStoreAsh store(nullptr /* no additional provider */,
+                           /*use_system_slot=*/false, user1_.username_hash(),
+                           ClientCertStoreAsh::PasswordDelegateFactory());
+
+  scoped_refptr<net::X509Certificate> cert_1(ImportCertToSlot(
+      "client_1.pem", "client_1.pk8",
+      crypto::GetPublicSlotForChromeOSUser(user1_.username_hash()).get()));
+  ASSERT_TRUE(cert_1);
+
+  auto request_all = base::MakeRefCounted<net::SSLCertRequestInfo>();
+
+  base::RunLoop run_loop;
+  net::ClientCertIdentityList selected_identities;
+  store.GetClientCerts(
+      *request_all,
+      base::BindOnce(SaveIdentitiesAndQuitCallback, &selected_identities,
+                     run_loop.QuitClosure()));
+  run_loop.Run();
+
+  ASSERT_EQ(1u, selected_identities.size());
+}
+
+TEST_F(ClientCertStoreAshTest, Filter) {
+  user1_.FinishInit();
+  user2_.FinishInit();
+
+  crypto::ScopedPK11Slot slot_public1 =
+      crypto::GetPublicSlotForChromeOSUser(user1_.username_hash());
+  crypto::ScopedPK11Slot slot_public2 =
+      crypto::GetPublicSlotForChromeOSUser(user2_.username_hash());
+  crypto::ScopedPK11Slot slot_private1 = crypto::GetPrivateSlotForChromeOSUser(
+      user1_.username_hash(), base::DoNothing());
+  crypto::ScopedPK11Slot slot_private2 = crypto::GetPrivateSlotForChromeOSUser(
+      user2_.username_hash(), base::DoNothing());
+  // crypto::GetPrivateSlotForChromeOSUser() may return nullptr if the slot is
+  // not initialized yet, but this should not happen.
+  ASSERT_TRUE(slot_private1);
+  ASSERT_TRUE(slot_private2);
+
+  // Import a certificate into each slot.
+  scoped_refptr<net::X509Certificate> cert_public1(
+      ImportCertToSlot("client_1.pem", "client_1.pk8", slot_public1.get()));
+  ASSERT_TRUE(cert_public1);
+  scoped_refptr<net::X509Certificate> cert_private1(
+      ImportCertToSlot("client_2.pem", "client_2.pk8", slot_private1.get()));
+  ASSERT_TRUE(cert_private1);
+  scoped_refptr<net::X509Certificate> cert_public2(
+      ImportCertToSlot("client_3.pem", "client_3.pk8", slot_public2.get()));
+  ASSERT_TRUE(cert_public2);
+  scoped_refptr<net::X509Certificate> cert_private2(
+      ImportCertToSlot("client_4.pem", "client_4.pk8", slot_private2.get()));
+  ASSERT_TRUE(cert_private2);
+  scoped_refptr<net::X509Certificate> cert_system(
+      ImportCertToSlot("client_5.pem", "client_5.pk8", system_slot_.slot()));
+  ASSERT_TRUE(cert_system);
+
+  const struct FilterTest {
+    bool use_system_slot;
+    std::string username_hash;
+    std::vector<net::X509Certificate*> results;
+  } kTests[] = {
+      {false,
+       user1_.username_hash(),
+       {cert_public1.get(), cert_private1.get()}},
+      {true,
+       user1_.username_hash(),
+       {cert_public1.get(), cert_private1.get(), cert_system.get()}},
+      {false,
+       user2_.username_hash(),
+       {cert_public2.get(), cert_private2.get()}},
+      {true,
+       user2_.username_hash(),
+       {cert_public2.get(), cert_private2.get(), cert_system.get()}},
+  };
+
+  for (const auto& test : kTests) {
+    SCOPED_TRACE(test.use_system_slot);
+    SCOPED_TRACE(test.username_hash);
+
+    ClientCertStoreAsh store(nullptr /* no additional provider */,
+                             test.use_system_slot, test.username_hash,
+                             ClientCertStoreAsh::PasswordDelegateFactory());
+
+    auto request_all = base::MakeRefCounted<net::SSLCertRequestInfo>();
+
+    base::RunLoop run_loop;
+    net::ClientCertIdentityList selected_identities;
+    store.GetClientCerts(
+        *request_all,
+        base::BindOnce(SaveIdentitiesAndQuitCallback, &selected_identities,
+                       run_loop.QuitClosure()));
+    run_loop.Run();
+
+    ASSERT_EQ(test.results.size(), selected_identities.size());
+    for (size_t i = 0; i < test.results.size(); i++) {
+      bool found_cert = false;
+      for (const auto& identity : selected_identities) {
+        if (test.results[i]->EqualsExcludingChain(identity->certificate())) {
+          found_cert = true;
+          break;
+        }
+      }
+      EXPECT_TRUE(found_cert) << "Could not find certificate " << i;
+    }
+  }
+}
+
+// Ensure that the delegation of the request matching to the base class is
+// functional.
+TEST_F(ClientCertStoreAshTest, CertRequestMatching) {
+  user1_.FinishInit();
+
+  ClientCertStoreAsh store(nullptr,  // no additional provider
+                           /*use_system_slot=*/false, user1_.username_hash(),
+                           ClientCertStoreAsh::PasswordDelegateFactory());
+
+  crypto::ScopedPK11Slot slot =
+      crypto::GetPublicSlotForChromeOSUser(user1_.username_hash());
+  scoped_refptr<net::X509Certificate> cert_1(
+      ImportCertToSlot("client_1.pem", "client_1.pk8", slot.get()));
+  ASSERT_TRUE(cert_1);
+  scoped_refptr<net::X509Certificate> cert_2(
+      ImportCertToSlot("client_2.pem", "client_2.pk8", slot.get()));
+  ASSERT_TRUE(cert_2.get());
+
+  std::vector<std::string> authority_1 = {
+      std::string(std::begin(kAuthority1DN), std::end(kAuthority1DN))};
+  auto request = base::MakeRefCounted<net::SSLCertRequestInfo>();
+  request->cert_authorities = authority_1;
+
+  base::RunLoop run_loop;
+  net::ClientCertIdentityList selected_identities;
+  store.GetClientCerts(
+      *request, base::BindOnce(SaveIdentitiesAndQuitCallback,
+                               &selected_identities, run_loop.QuitClosure()));
+  run_loop.Run();
+
+  ASSERT_EQ(1u, selected_identities.size());
+  EXPECT_TRUE(
+      cert_1->EqualsExcludingChain(selected_identities[0]->certificate()));
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/client_cert_store_chromeos.cc b/chrome/browser/chromeos/net/client_cert_store_chromeos.cc
deleted file mode 100644
index 0dce9db..0000000
--- a/chrome/browser/chromeos/net/client_cert_store_chromeos.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/net/client_cert_store_chromeos.h"
-
-#include <cert.h>
-#include <algorithm>
-#include <iterator>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/callback_helpers.h"
-#include "base/location.h"
-#include "base/task/post_task.h"
-#include "base/task/thread_pool.h"
-#include "base/threading/scoped_blocking_call.h"
-#include "chrome/browser/ash/certificate_provider/certificate_provider.h"
-#include "chrome/browser/chromeos/net/client_cert_filter_chromeos.h"
-#include "crypto/nss_crypto_module_delegate.h"
-#include "net/ssl/ssl_cert_request_info.h"
-#include "net/ssl/ssl_private_key.h"
-
-namespace chromeos {
-
-ClientCertStoreChromeOS::ClientCertStoreChromeOS(
-    std::unique_ptr<CertificateProvider> cert_provider,
-    bool use_system_slot,
-    const std::string& username_hash,
-    const PasswordDelegateFactory& password_delegate_factory)
-    : cert_provider_(std::move(cert_provider)),
-      cert_filter_(use_system_slot, username_hash) {}
-
-ClientCertStoreChromeOS::~ClientCertStoreChromeOS() {}
-
-void ClientCertStoreChromeOS::GetClientCerts(
-    const net::SSLCertRequestInfo& cert_request_info,
-    ClientCertListCallback callback) {
-  // Caller is responsible for keeping the ClientCertStore alive until the
-  // callback is run.
-  base::OnceCallback<void(net::ClientCertIdentityList)>
-      get_platform_certs_and_filter = base::BindOnce(
-          &ClientCertStoreChromeOS::GotAdditionalCerts, base::Unretained(this),
-          base::Unretained(&cert_request_info), std::move(callback));
-
-  base::OnceClosure get_additional_certs_and_continue;
-  if (cert_provider_) {
-    get_additional_certs_and_continue =
-        base::BindOnce(&CertificateProvider::GetCertificates,
-                       base::Unretained(cert_provider_.get()),
-                       std::move(get_platform_certs_and_filter));
-  } else {
-    get_additional_certs_and_continue =
-        base::BindOnce(std::move(get_platform_certs_and_filter),
-                       net::ClientCertIdentityList());
-  }
-
-  auto split_callback =
-      base::SplitOnceCallback(std::move(get_additional_certs_and_continue));
-  if (cert_filter_.Init(std::move(split_callback.first))) {
-    std::move(split_callback.second).Run();
-  }
-}
-
-void ClientCertStoreChromeOS::GotAdditionalCerts(
-    const net::SSLCertRequestInfo* request,
-    ClientCertListCallback callback,
-    net::ClientCertIdentityList additional_certs) {
-  scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate;
-  if (!password_delegate_factory_.is_null())
-    password_delegate = password_delegate_factory_.Run(request->host_and_port);
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE,
-      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::BindOnce(&ClientCertStoreChromeOS::GetAndFilterCertsOnWorkerThread,
-                     base::Unretained(this), password_delegate,
-                     base::Unretained(request), std::move(additional_certs)),
-      std::move(callback));
-}
-
-net::ClientCertIdentityList
-ClientCertStoreChromeOS::GetAndFilterCertsOnWorkerThread(
-    scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate>
-        password_delegate,
-    const net::SSLCertRequestInfo* request,
-    net::ClientCertIdentityList additional_certs) {
-  // This method may acquire the NSS lock or reenter this code via extension
-  // hooks (such as smart card UI). To ensure threads are not starved or
-  // deadlocked, the base::ScopedBlockingCall below increments the thread pool
-  // capacity if this method takes too much time to run.
-  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
-                                                base::BlockingType::MAY_BLOCK);
-
-  net::ClientCertIdentityList client_certs;
-  net::ClientCertStoreNSS::GetPlatformCertsOnWorkerThread(
-      std::move(password_delegate),
-      base::BindRepeating(&ClientCertFilterChromeOS::IsCertAllowed,
-                          base::Unretained(&cert_filter_)),
-      &client_certs);
-
-  client_certs.reserve(client_certs.size() + additional_certs.size());
-  for (std::unique_ptr<net::ClientCertIdentity>& cert : additional_certs)
-    client_certs.push_back(std::move(cert));
-  net::ClientCertStoreNSS::FilterCertsOnWorkerThread(&client_certs, *request);
-  return client_certs;
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/client_cert_store_chromeos.h b/chrome/browser/chromeos/net/client_cert_store_chromeos.h
deleted file mode 100644
index 9b7753e..0000000
--- a/chrome/browser/chromeos/net/client_cert_store_chromeos.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_STORE_CHROMEOS_H_
-#define CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_STORE_CHROMEOS_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-// TODO(https://crbug.com/1164001): forward declare when moved to ash.
-#include "chrome/browser/ash/certificate_provider/certificate_provider.h"
-#include "chrome/browser/chromeos/net/client_cert_filter_chromeos.h"
-#include "net/ssl/client_cert_store_nss.h"
-
-namespace chromeos {
-
-class ClientCertStoreChromeOS : public net::ClientCertStore {
- public:
-  using PasswordDelegateFactory =
-      net::ClientCertStoreNSS::PasswordDelegateFactory;
-
-  // This ClientCertStore will return client certs from the public
-  // and private slot of the user with |username_hash| and with the system slot
-  // if |use_system_slot| is true. If |username_hash| is empty, no public and no
-  // private slot will be used. It will additionally return certificates
-  // provided by |cert_provider|.
-  ClientCertStoreChromeOS(
-      std::unique_ptr<CertificateProvider> cert_provider,
-      bool use_system_slot,
-      const std::string& username_hash,
-      const PasswordDelegateFactory& password_delegate_factory);
-
-  ClientCertStoreChromeOS(const ClientCertStoreChromeOS&) = delete;
-  ClientCertStoreChromeOS& operator=(const ClientCertStoreChromeOS&) = delete;
-
-  ~ClientCertStoreChromeOS() override;
-
-  // net::ClientCertStore:
-  void GetClientCerts(const net::SSLCertRequestInfo& cert_request_info,
-                      ClientCertListCallback callback) override;
-
- private:
-  void GotAdditionalCerts(const net::SSLCertRequestInfo* request,
-                          ClientCertListCallback callback,
-                          net::ClientCertIdentityList additional_certs);
-
-  net::ClientCertIdentityList GetAndFilterCertsOnWorkerThread(
-      scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate>
-          password_delegate,
-      const net::SSLCertRequestInfo* request,
-      net::ClientCertIdentityList additional_certs);
-
-  std::unique_ptr<CertificateProvider> cert_provider_;
-  ClientCertFilterChromeOS cert_filter_;
-
-  // The factory for creating the delegate for requesting a password to a
-  // PKCS#11 token. May be null.
-  PasswordDelegateFactory password_delegate_factory_;
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_NET_CLIENT_CERT_STORE_CHROMEOS_H_
diff --git a/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc b/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc
deleted file mode 100644
index 6814c249..0000000
--- a/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/net/client_cert_store_chromeos.h"
-
-#include <memory>
-#include <string>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/callback_helpers.h"
-#include "base/files/file_path.h"
-#include "base/location.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/run_loop.h"
-#include "chrome/browser/ash/certificate_provider/certificate_provider.h"
-#include "content/public/test/browser_task_environment.h"
-#include "crypto/nss_util_internal.h"
-#include "crypto/scoped_nss_types.h"
-#include "crypto/scoped_test_nss_chromeos_user.h"
-#include "crypto/scoped_test_nss_db.h"
-#include "crypto/scoped_test_system_nss_key_slot.h"
-#include "net/cert/x509_certificate.h"
-#include "net/cert/x509_util_nss.h"
-#include "net/ssl/client_cert_identity_test_util.h"
-#include "net/ssl/ssl_cert_request_info.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromeos {
-
-namespace {
-
-// "CN=B CA" - DER encoded DN of the issuer of client_1.pem
-const unsigned char kAuthority1DN[] = {0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b,
-                                       0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-                                       0x04, 0x42, 0x20, 0x43, 0x41};
-
-void SaveIdentitiesAndQuitCallback(net::ClientCertIdentityList* out_identities,
-                                   base::OnceClosure quit_closure,
-                                   net::ClientCertIdentityList in_identities) {
-  *out_identities = std::move(in_identities);
-  std::move(quit_closure).Run();
-}
-
-}  // namespace
-
-class ClientCertStoreChromeOSTest : public ::testing::Test {
- public:
-  ClientCertStoreChromeOSTest() {}
-
-  void SetUp() override {
-    ASSERT_TRUE(user1_.constructed_successfully());
-    ASSERT_TRUE(user2_.constructed_successfully());
-    ASSERT_TRUE(system_slot_.ConstructedSuccessfully());
-  }
-
-  scoped_refptr<net::X509Certificate> ImportCertToSlot(
-      const std::string& cert_filename,
-      const std::string& key_filename,
-      PK11SlotInfo* slot) {
-    return net::ImportClientCertAndKeyFromFile(
-        net::GetTestCertsDirectory(), cert_filename, key_filename, slot);
-  }
-
- protected:
-  crypto::ScopedTestNSSChromeOSUser user1_{"user1"};
-  crypto::ScopedTestNSSChromeOSUser user2_{"user2"};
-  crypto::ScopedTestSystemNSSKeySlot system_slot_;
-  content::BrowserTaskEnvironment task_environment_;
-};
-
-// Ensure that cert requests, that are started before the filter is initialized,
-// will wait for the initialization and succeed afterwards.
-TEST_F(ClientCertStoreChromeOSTest, RequestWaitsForNSSInitAndSucceeds) {
-  ClientCertStoreChromeOS store(
-      nullptr /* no additional provider */,
-      /*use_system_slot=*/false, user1_.username_hash(),
-      ClientCertStoreChromeOS::PasswordDelegateFactory());
-
-  scoped_refptr<net::X509Certificate> cert_1(ImportCertToSlot(
-      "client_1.pem", "client_1.pk8",
-      crypto::GetPublicSlotForChromeOSUser(user1_.username_hash()).get()));
-  ASSERT_TRUE(cert_1);
-
-  // Request any client certificate, which is expected to match client_1.
-  auto request_all = base::MakeRefCounted<net::SSLCertRequestInfo>();
-
-  net::ClientCertIdentityList selected_identities;
-  base::RunLoop run_loop;
-  store.GetClientCerts(
-      *request_all,
-      base::BindOnce(SaveIdentitiesAndQuitCallback, &selected_identities,
-                     run_loop.QuitClosure()));
-
-  {
-    base::RunLoop run_loop_inner;
-    run_loop_inner.RunUntilIdle();
-    // GetClientCerts should wait for the initialization of the filter to
-    // finish.
-    ASSERT_EQ(0u, selected_identities.size());
-  }
-
-  user1_.FinishInit();
-  run_loop.Run();
-
-  ASSERT_EQ(1u, selected_identities.size());
-}
-
-// Ensure that cert requests, that are started after the filter was initialized,
-// will succeed.
-TEST_F(ClientCertStoreChromeOSTest, RequestsAfterNSSInitSucceed) {
-  user1_.FinishInit();
-
-  ClientCertStoreChromeOS store(
-      nullptr /* no additional provider */,
-      /*use_system_slot=*/false, user1_.username_hash(),
-      ClientCertStoreChromeOS::PasswordDelegateFactory());
-
-  scoped_refptr<net::X509Certificate> cert_1(ImportCertToSlot(
-      "client_1.pem", "client_1.pk8",
-      crypto::GetPublicSlotForChromeOSUser(user1_.username_hash()).get()));
-  ASSERT_TRUE(cert_1);
-
-  auto request_all = base::MakeRefCounted<net::SSLCertRequestInfo>();
-
-  base::RunLoop run_loop;
-  net::ClientCertIdentityList selected_identities;
-  store.GetClientCerts(
-      *request_all,
-      base::BindOnce(SaveIdentitiesAndQuitCallback, &selected_identities,
-                     run_loop.QuitClosure()));
-  run_loop.Run();
-
-  ASSERT_EQ(1u, selected_identities.size());
-}
-
-TEST_F(ClientCertStoreChromeOSTest, Filter) {
-  user1_.FinishInit();
-  user2_.FinishInit();
-
-  crypto::ScopedPK11Slot slot_public1 =
-      crypto::GetPublicSlotForChromeOSUser(user1_.username_hash());
-  crypto::ScopedPK11Slot slot_public2 =
-      crypto::GetPublicSlotForChromeOSUser(user2_.username_hash());
-  crypto::ScopedPK11Slot slot_private1 = crypto::GetPrivateSlotForChromeOSUser(
-      user1_.username_hash(), base::DoNothing());
-  crypto::ScopedPK11Slot slot_private2 = crypto::GetPrivateSlotForChromeOSUser(
-      user2_.username_hash(), base::DoNothing());
-  // crypto::GetPrivateSlotForChromeOSUser() may return nullptr if the slot is
-  // not initialized yet, but this should not happen.
-  ASSERT_TRUE(slot_private1);
-  ASSERT_TRUE(slot_private2);
-
-  // Import a certificate into each slot.
-  scoped_refptr<net::X509Certificate> cert_public1(
-      ImportCertToSlot("client_1.pem", "client_1.pk8", slot_public1.get()));
-  ASSERT_TRUE(cert_public1);
-  scoped_refptr<net::X509Certificate> cert_private1(
-      ImportCertToSlot("client_2.pem", "client_2.pk8", slot_private1.get()));
-  ASSERT_TRUE(cert_private1);
-  scoped_refptr<net::X509Certificate> cert_public2(
-      ImportCertToSlot("client_3.pem", "client_3.pk8", slot_public2.get()));
-  ASSERT_TRUE(cert_public2);
-  scoped_refptr<net::X509Certificate> cert_private2(
-      ImportCertToSlot("client_4.pem", "client_4.pk8", slot_private2.get()));
-  ASSERT_TRUE(cert_private2);
-  scoped_refptr<net::X509Certificate> cert_system(
-      ImportCertToSlot("client_5.pem", "client_5.pk8", system_slot_.slot()));
-  ASSERT_TRUE(cert_system);
-
-  const struct FilterTest {
-    bool use_system_slot;
-    std::string username_hash;
-    std::vector<net::X509Certificate*> results;
-  } kTests[] = {
-      {false,
-       user1_.username_hash(),
-       {cert_public1.get(), cert_private1.get()}},
-      {true,
-       user1_.username_hash(),
-       {cert_public1.get(), cert_private1.get(), cert_system.get()}},
-      {false,
-       user2_.username_hash(),
-       {cert_public2.get(), cert_private2.get()}},
-      {true,
-       user2_.username_hash(),
-       {cert_public2.get(), cert_private2.get(), cert_system.get()}},
-  };
-
-  for (const auto& test : kTests) {
-    SCOPED_TRACE(test.use_system_slot);
-    SCOPED_TRACE(test.username_hash);
-
-    ClientCertStoreChromeOS store(
-        nullptr /* no additional provider */, test.use_system_slot,
-        test.username_hash, ClientCertStoreChromeOS::PasswordDelegateFactory());
-
-    auto request_all = base::MakeRefCounted<net::SSLCertRequestInfo>();
-
-    base::RunLoop run_loop;
-    net::ClientCertIdentityList selected_identities;
-    store.GetClientCerts(
-        *request_all,
-        base::BindOnce(SaveIdentitiesAndQuitCallback, &selected_identities,
-                       run_loop.QuitClosure()));
-    run_loop.Run();
-
-    ASSERT_EQ(test.results.size(), selected_identities.size());
-    for (size_t i = 0; i < test.results.size(); i++) {
-      bool found_cert = false;
-      for (const auto& identity : selected_identities) {
-        if (test.results[i]->EqualsExcludingChain(identity->certificate())) {
-          found_cert = true;
-          break;
-        }
-      }
-      EXPECT_TRUE(found_cert) << "Could not find certificate " << i;
-    }
-  }
-}
-
-// Ensure that the delegation of the request matching to the base class is
-// functional.
-TEST_F(ClientCertStoreChromeOSTest, CertRequestMatching) {
-  user1_.FinishInit();
-
-  ClientCertStoreChromeOS store(
-      nullptr,  // no additional provider
-      /*use_system_slot=*/false, user1_.username_hash(),
-      ClientCertStoreChromeOS::PasswordDelegateFactory());
-
-  crypto::ScopedPK11Slot slot =
-      crypto::GetPublicSlotForChromeOSUser(user1_.username_hash());
-  scoped_refptr<net::X509Certificate> cert_1(
-      ImportCertToSlot("client_1.pem", "client_1.pk8", slot.get()));
-  ASSERT_TRUE(cert_1);
-  scoped_refptr<net::X509Certificate> cert_2(
-      ImportCertToSlot("client_2.pem", "client_2.pk8", slot.get()));
-  ASSERT_TRUE(cert_2.get());
-
-  std::vector<std::string> authority_1 = {
-      std::string(std::begin(kAuthority1DN), std::end(kAuthority1DN))};
-  auto request = base::MakeRefCounted<net::SSLCertRequestInfo>();
-  request->cert_authorities = authority_1;
-
-  base::RunLoop run_loop;
-  net::ClientCertIdentityList selected_identities;
-  store.GetClientCerts(
-      *request, base::BindOnce(SaveIdentitiesAndQuitCallback,
-                               &selected_identities, run_loop.QuitClosure()));
-  run_loop.Run();
-
-  ASSERT_EQ(1u, selected_identities.size());
-  EXPECT_TRUE(
-      cert_1->EqualsExcludingChain(selected_identities[0]->certificate()));
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.cc
index 488bd5f..49e37ad 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service_factory.cc
@@ -12,7 +12,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/ash/certificate_provider/certificate_provider.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/net/client_cert_store_chromeos.h"
+#include "chrome/browser/chromeos/net/client_cert_store_ash.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
 #include "chrome/browser/net/nss_context.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
@@ -83,10 +83,10 @@
     // Use the device-wide system key slot only if the user is affiliated on the
     // device.
     const bool use_system_key_slot = user->IsAffiliated();
-    return std::make_unique<ClientCertStoreChromeOS>(
+    return std::make_unique<ClientCertStoreAsh>(
         nullptr,  // no additional provider
         use_system_key_slot, user->username_hash(),
-        ClientCertStoreChromeOS::PasswordDelegateFactory());
+        ClientCertStoreAsh::PasswordDelegateFactory());
   }
 
  private:
@@ -107,10 +107,10 @@
   }
 
   std::unique_ptr<net::ClientCertStore> CreateClientCertStore() override {
-    return std::make_unique<ClientCertStoreChromeOS>(
+    return std::make_unique<ClientCertStoreAsh>(
         nullptr,  // no additional provider
         /*use_system_key_slot=*/true, /*username_hash=*/std::string(),
-        ClientCertStoreChromeOS::PasswordDelegateFactory());
+        ClientCertStoreAsh::PasswordDelegateFactory());
   }
 
  private:
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service_nss.cc
index 48466331..2a57ca7 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service_nss.cc
@@ -32,7 +32,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
-#include "chrome/browser/chromeos/net/client_cert_store_chromeos.h"
+#include "chrome/browser/chromeos/net/client_cert_store_ash.h"
 #include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.h"
 #include "chrome/browser/platform_keys/platform_keys.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
@@ -1004,8 +1004,8 @@
       base::BindOnce(&SignOnWorkerThread, std::move(state)));
 }
 
-// Called when ClientCertStoreChromeOS::GetClientCerts is done. Builds the list
-// of net::CertificateList and calls back. Used by SelectCertificates().
+// Called when `ClientCertStoreAsh::GetClientCerts` is done. Builds the list of
+// `net::CertificateList` and calls back. Used by `SelectCertificates()`.
 void DidSelectCertificates(std::unique_ptr<SelectCertificatesState> state,
                            net::ClientCertIdentityList identities) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/chrome/browser/chromeos/printing/DIR_METADATA b/chrome/browser/chromeos/printing/DIR_METADATA
index 939d296..bcaf2b74 100644
--- a/chrome/browser/chromeos/printing/DIR_METADATA
+++ b/chrome/browser/chromeos/printing/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>Printing>CUPS"
-}
-team_email: "cros-printing-dev@chromium.org"
+mixins: "//chromeos/printing/COMMON_METADATA"
diff --git a/chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.cc b/chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.cc
index 103d76b..2d4188a 100644
--- a/chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.cc
+++ b/chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.cc
@@ -25,11 +25,12 @@
 
 namespace {
 
-// Returns a subdirectory under the user data directory (which is not cleared
-// after pre-tests).
+// Returns a subdirectory under the user data directory (which is cleared in
+// between tests, but not after pre-tests).
 base::FilePath GetNssDbTestDir() {
   base::FilePath nss_db_subdir;
   base::PathService::Get(chrome::DIR_USER_DATA, &nss_db_subdir);
+  CHECK(!nss_db_subdir.empty()) << "DIR_USER_DATA is not initialized yet.";
   nss_db_subdir = nss_db_subdir.AppendASCII("nss_db_subdir");
   return nss_db_subdir;
 }
@@ -42,17 +43,25 @@
 
 ScopedTestSystemNSSKeySlotMixin::~ScopedTestSystemNSSKeySlotMixin() = default;
 
-void ScopedTestSystemNSSKeySlotMixin::SetUpOnMainThread() {
-  bool system_slot_initialized_successfully = false;
-  base::RunLoop loop;
-  content::GetIOThreadTaskRunner({})->PostTaskAndReply(
-      FROM_HERE,
-      base::BindOnce(&ScopedTestSystemNSSKeySlotMixin::InitializeOnIo,
-                     base::Unretained(this),
-                     &system_slot_initialized_successfully),
-      loop.QuitClosure());
-  loop.Run();
-  ASSERT_TRUE(system_slot_initialized_successfully);
+void ScopedTestSystemNSSKeySlotMixin::SetUpInProcessBrowserTestFixture() {
+  // NSS is allowed to do IO on the current thread since dispatching
+  // to a dedicated thread would still have the affect of blocking
+  // the current thread, due to NSS's internal locking requirements
+  base::ScopedAllowBlockingForTesting allow_blocking;
+
+  crypto::EnsureNSSInit();
+
+  base::FilePath nss_db_subdir = GetNssDbTestDir();
+  ASSERT_TRUE(base::CreateDirectory(nss_db_subdir));
+
+  const char kTestDescription[] = "Test DB";
+  slot_ = crypto::OpenSoftwareNSSDB(nss_db_subdir, kTestDescription);
+  ASSERT_TRUE(!!slot_);
+
+  if (slot_) {
+    crypto::PrepareSystemSlotForTesting(
+        crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get())));
+  }
 }
 
 void ScopedTestSystemNSSKeySlotMixin::TearDownOnMainThread() {
@@ -65,32 +74,10 @@
   loop.Run();
 }
 
-void ScopedTestSystemNSSKeySlotMixin::InitializeOnIo(bool* out_success) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
-  crypto::EnsureNSSInit();
-  // NSS is allowed to do IO on the current thread since dispatching
-  // to a dedicated thread would still have the affect of blocking
-  // the current thread, due to NSS's internal locking requirements
-  base::ScopedAllowBlockingForTesting allow_blocking;
-
-  base::FilePath nss_db_subdir = GetNssDbTestDir();
-  ASSERT_TRUE(base::CreateDirectory(nss_db_subdir));
-
-  const char kTestDescription[] = "Test DB";
-  slot_ = crypto::OpenSoftwareNSSDB(nss_db_subdir, kTestDescription);
-  *out_success = !!slot_;
-
-  if (slot_) {
-    crypto::SetSystemKeySlotForTesting(
-        crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot_.get())));
-  }
-}
-
 void ScopedTestSystemNSSKeySlotMixin::DestroyOnIo() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
-  crypto::SetSystemKeySlotForTesting(nullptr);
+  crypto::ResetSystemSlotForTesting();
 
   if (slot_) {
     SECStatus status = SECMOD_CloseUserDB(slot_.get());
diff --git a/chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.h b/chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.h
index 1399198..89e2084 100644
--- a/chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.h
+++ b/chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.h
@@ -20,7 +20,7 @@
 // database without losing its state.
 //
 // This mixin performs the blocking initialization/destruction in the
-// {SetUp|TearDown}OnMainThread methods.
+// SetUp*|TearDown* methods.
 class ScopedTestSystemNSSKeySlotMixin final : public InProcessBrowserTestMixin {
  public:
   explicit ScopedTestSystemNSSKeySlotMixin(InProcessBrowserTestMixinHost* host);
@@ -32,11 +32,14 @@
 
   PK11SlotInfo* slot() { return slot_.get(); }
 
-  void SetUpOnMainThread() override;
+  // SetUp and TearDown are not symmetrical. SetUp has to happen very early in a
+  // test life cycle (before ChromeOSTokenManager is created). And TearDown
+  // should happen while the IO thread still exists to properly close the
+  // database.
+  void SetUpInProcessBrowserTestFixture() override;
   void TearDownOnMainThread() override;
 
  private:
-  void InitializeOnIo(bool* out_success);
   void DestroyOnIo();
 
   crypto::ScopedPK11Slot slot_;
diff --git a/chrome/browser/chromeos/system_token_cert_db_initializer.cc b/chrome/browser/chromeos/system_token_cert_db_initializer.cc
index cdc8e6e..14af8887 100644
--- a/chrome/browser/chromeos/system_token_cert_db_initializer.cc
+++ b/chrome/browser/chromeos/system_token_cert_db_initializer.cc
@@ -48,34 +48,21 @@
 constexpr bool kIsSystemSlotSoftwareFallbackAllowed = false;
 #endif
 
-// Called on UI Thread when the system slot has been retrieved.
-void GotSystemSlotOnUIThread(
-    base::OnceCallback<void(crypto::ScopedPK11Slot)> callback_ui_thread,
-    crypto::ScopedPK11Slot system_slot) {
-  std::move(callback_ui_thread).Run(std::move(system_slot));
-}
-
 // Called on IO Thread when the system slot has been retrieved.
 void GotSystemSlotOnIOThread(
-    base::OnceCallback<void(crypto::ScopedPK11Slot)> callback_ui_thread,
+    base::OnceCallback<void(crypto::ScopedPK11Slot)> ui_callback,
     crypto::ScopedPK11Slot system_slot) {
   content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE,
-      base::BindOnce(&GotSystemSlotOnUIThread, std::move(callback_ui_thread),
-                     std::move(system_slot)));
+      base::BindOnce(std::move(ui_callback), std::move(system_slot)));
 }
 
-// Called on IO Thread, initiates retrieval of system slot. |callback_ui_thread|
+// Called on IO Thread, initiates retrieval of system slot. |ui_callback|
 // will be executed on the UI thread when the system slot has been retrieved.
 void GetSystemSlotOnIOThread(
-    base::RepeatingCallback<void(crypto::ScopedPK11Slot)> callback_ui_thread) {
-  auto callback =
-      base::BindRepeating(&GotSystemSlotOnIOThread, callback_ui_thread);
-  crypto::ScopedPK11Slot system_nss_slot =
-      crypto::GetSystemNSSKeySlot(callback);
-  if (system_nss_slot) {
-    callback.Run(std::move(system_nss_slot));
-  }
+    base::OnceCallback<void(crypto::ScopedPK11Slot)> ui_callback) {
+  crypto::GetSystemNSSKeySlot(
+      base::BindOnce(&GotSystemSlotOnIOThread, std::move(ui_callback)));
 }
 
 // Decides if on start we shall signal to the platform that it can attempt
@@ -223,16 +210,21 @@
       << "SystemTokenCertDBInitializer: TPM is ready, loading system token.";
   NetworkCertLoader::Get()->MarkSystemNSSDBWillBeInitialized();
   TPMTokenLoader::Get()->EnsureStarted();
-  base::RepeatingCallback<void(crypto::ScopedPK11Slot)> callback =
-      base::BindRepeating(&SystemTokenCertDBInitializer::InitializeDatabase,
-                          weak_ptr_factory_.GetWeakPtr());
+  auto ui_callback =
+      base::BindOnce(&SystemTokenCertDBInitializer::InitializeDatabase,
+                     weak_ptr_factory_.GetWeakPtr());
   content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&GetSystemSlotOnIOThread, callback));
+      FROM_HERE,
+      base::BindOnce(&GetSystemSlotOnIOThread, std::move(ui_callback)));
 }
 
 void SystemTokenCertDBInitializer::InitializeDatabase(
     crypto::ScopedPK11Slot system_slot) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!system_slot) {
+    // System slot will never be loaded.
+    return;
+  }
 
   // Currently, NSSCertDatabase requires a public slot to be set, so we use
   // the system slot there. We also want GetSystemSlot() to return the system
diff --git a/chrome/browser/chromeos/system_token_cert_db_initializer_unittest.cc b/chrome/browser/chromeos/system_token_cert_db_initializer_unittest.cc
index 5f3d35e..fc1a6078 100644
--- a/chrome/browser/chromeos/system_token_cert_db_initializer_unittest.cc
+++ b/chrome/browser/chromeos/system_token_cert_db_initializer_unittest.cc
@@ -17,6 +17,7 @@
 #include "chromeos/network/system_token_cert_db_storage_test_util.h"
 #include "chromeos/tpm/tpm_token_loader.h"
 #include "content/public/test/browser_task_environment.h"
+#include "crypto/nss_util.h"
 #include "crypto/scoped_test_system_nss_key_slot.h"
 #include "net/cert/nss_cert_database.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -53,7 +54,8 @@
 
  protected:
   bool InitializeTestSystemSlot() {
-    test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>();
+    test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>(
+        /*simulate_token_loader=*/true);
     return test_system_slot_->ConstructedSuccessfully();
   }
 
diff --git a/chrome/browser/commerce/coupons/coupon_service.cc b/chrome/browser/commerce/coupons/coupon_service.cc
new file mode 100644
index 0000000..dba3671
--- /dev/null
+++ b/chrome/browser/commerce/coupons/coupon_service.cc
@@ -0,0 +1,8 @@
+// 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/commerce/coupons/coupon_service.h"
+
+CouponService::CouponService() {}
+CouponService::~CouponService() = default;
diff --git a/chrome/browser/commerce/coupons/coupon_service.h b/chrome/browser/commerce/coupons/coupon_service.h
new file mode 100644
index 0000000..7f72d2d
--- /dev/null
+++ b/chrome/browser/commerce/coupons/coupon_service.h
@@ -0,0 +1,29 @@
+// 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_COMMERCE_COUPONS_COUPON_SERVICE_H_
+#define CHROME_BROWSER_COMMERCE_COUPONS_COUPON_SERVICE_H_
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/commerce/coupons/coupon_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+// Service to host coupon-related logics.
+class CouponService : public KeyedService {
+ public:
+  CouponService(const CouponService&) = delete;
+  CouponService& operator=(const CouponService&) = delete;
+  ~CouponService() override;
+
+ private:
+  friend class CouponServiceFactory;
+
+  // Use |CouponServiceFactory::GetForProfile(...)| to get an instance of this
+  // service.
+  CouponService();
+  base::WeakPtrFactory<CouponService> weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_COMMERCE_COUPONS_COUPON_SERVICE_H_
diff --git a/chrome/browser/commerce/coupons/coupon_service_factory.cc b/chrome/browser/commerce/coupons/coupon_service_factory.cc
new file mode 100644
index 0000000..165b716
--- /dev/null
+++ b/chrome/browser/commerce/coupons/coupon_service_factory.cc
@@ -0,0 +1,35 @@
+// 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/commerce/coupons/coupon_service_factory.h"
+
+#include "chrome/browser/commerce/coupons/coupon_service.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/storage_partition.h"
+
+// static
+CouponServiceFactory* CouponServiceFactory::GetInstance() {
+  static base::NoDestructor<CouponServiceFactory> factory;
+  return factory.get();
+}
+
+// static
+CouponService* CouponServiceFactory::GetForProfile(Profile* profile) {
+  return static_cast<CouponService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+CouponServiceFactory::CouponServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "CouponService",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+CouponServiceFactory::~CouponServiceFactory() = default;
+
+KeyedService* CouponServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  DCHECK(!context->IsOffTheRecord());
+
+  return new CouponService();
+}
diff --git a/chrome/browser/commerce/coupons/coupon_service_factory.h b/chrome/browser/commerce/coupons/coupon_service_factory.h
new file mode 100644
index 0000000..57b4993
--- /dev/null
+++ b/chrome/browser/commerce/coupons/coupon_service_factory.h
@@ -0,0 +1,34 @@
+// 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_COMMERCE_COUPONS_COUPON_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_COMMERCE_COUPONS_COUPON_SERVICE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class Profile;
+class CouponService;
+
+// Factory to create CouponService per profile. CouponService is not supported
+// on incognito, and the factory will return nullptr for an incognito profile.
+class CouponServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  // Acquire instance of CouponServiceFactory.
+  static CouponServiceFactory* GetInstance();
+
+  // Acquire CouponService - there is one per profile.
+  static CouponService* GetForProfile(Profile* profile);
+
+ private:
+  friend base::NoDestructor<CouponServiceFactory>;
+
+  CouponServiceFactory();
+  ~CouponServiceFactory() override;
+
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+};
+
+#endif  // CHROME_BROWSER_COMMERCE_COUPONS_COUPON_SERVICE_FACTORY_H_
diff --git a/chrome/browser/component_updater/COMMON_METADATA b/chrome/browser/component_updater/COMMON_METADATA
new file mode 100644
index 0000000..564340d8
--- /dev/null
+++ b/chrome/browser/component_updater/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "Internals>Installer>Components"
+}
+team_email: "chrome-updates-dev@chromium.org"
diff --git a/chrome/browser/component_updater/DIR_METADATA b/chrome/browser/component_updater/DIR_METADATA
index 564340d8..4d69679 100644
--- a/chrome/browser/component_updater/DIR_METADATA
+++ b/chrome/browser/component_updater/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>Installer>Components"
-}
-team_email: "chrome-updates-dev@chromium.org"
+mixins: "//chrome/browser/component_updater/COMMON_METADATA"
diff --git a/chrome/browser/consent_auditor/DIR_METADATA b/chrome/browser/consent_auditor/DIR_METADATA
index ff46333..c75f2f8 100644
--- a/chrome/browser/consent_auditor/DIR_METADATA
+++ b/chrome/browser/consent_auditor/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Privacy"
-}
+mixins: "//components/consent_auditor/COMMON_METADATA"
diff --git a/chrome/browser/content_creation/DIR_METADATA b/chrome/browser/content_creation/DIR_METADATA
index 22be329..302b1262 100644
--- a/chrome/browser/content_creation/DIR_METADATA
+++ b/chrome/browser/content_creation/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>Creation"
-}
+mixins: "//components/content_creation/COMMON_METADATA"
 
-team_email: "chrome-creation@google.com"
\ No newline at end of file
diff --git a/chrome/browser/content_index/DIR_METADATA b/chrome/browser/content_index/DIR_METADATA
new file mode 100644
index 0000000..14ec9603
--- /dev/null
+++ b/chrome/browser/content_index/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/content_index/COMMON_METADATA"
diff --git a/chrome/browser/content_settings/DIR_METADATA b/chrome/browser/content_settings/DIR_METADATA
index e783e5b..7884b06a 100644
--- a/chrome/browser/content_settings/DIR_METADATA
+++ b/chrome/browser/content_settings/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Permissions>Model"
-}
+mixins: "//components/content_settings/COMMON_METADATA"
diff --git a/chrome/browser/continuous_search/DIR_METADATA b/chrome/browser/continuous_search/DIR_METADATA
index c28e7cd..78deea4 100644
--- a/chrome/browser/continuous_search/DIR_METADATA
+++ b/chrome/browser/continuous_search/DIR_METADATA
@@ -1,5 +1 @@
-monorail: {
-  component:  "UI>Browser>ContinuousSearch"
-}
-team_email: "csn-dev@google.com"
-os: ANDROID
+mixins: "//components/continuous_search/COMMON_METADATA"
diff --git a/chrome/browser/custom_handlers/COMMON_METADATA b/chrome/browser/custom_handlers/COMMON_METADATA
new file mode 100644
index 0000000..c8b762a
--- /dev/null
+++ b/chrome/browser/custom_handlers/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org"
diff --git a/chrome/browser/custom_handlers/DIR_METADATA b/chrome/browser/custom_handlers/DIR_METADATA
index c8b762a..a9ebe08 100644
--- a/chrome/browser/custom_handlers/DIR_METADATA
+++ b/chrome/browser/custom_handlers/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
+mixins: "//chrome/browser/custom_handlers/COMMON_METADATA"
diff --git a/chrome/browser/data_reduction_proxy/DIR_METADATA b/chrome/browser/data_reduction_proxy/DIR_METADATA
index ce14958..eb96fa3 100644
--- a/chrome/browser/data_reduction_proxy/DIR_METADATA
+++ b/chrome/browser/data_reduction_proxy/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Network>DataProxy"
-}
+mixins: "//components/data_reduction_proxy/COMMON_METADATA"
diff --git a/chrome/browser/dom_distiller/DIR_METADATA b/chrome/browser/dom_distiller/DIR_METADATA
index e1577fe..ca7bc37 100644
--- a/chrome/browser/dom_distiller/DIR_METADATA
+++ b/chrome/browser/dom_distiller/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>ReaderMode"
-}
+mixins: "//components/dom_distiller/COMMON_METADATA"
diff --git a/chrome/browser/domain_reliability/DIR_METADATA b/chrome/browser/domain_reliability/DIR_METADATA
index f1b0913..bbbf3bf6 100644
--- a/chrome/browser/domain_reliability/DIR_METADATA
+++ b/chrome/browser/domain_reliability/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>Network>ReportingAndNEL"
-}
-team_email: "net-dev@chromium.org"
+mixins: "//components/domain_reliability/COMMON_METADATA"
diff --git a/chrome/browser/download/DIR_METADATA b/chrome/browser/download/DIR_METADATA
index fc36dcd..8b1c141 100644
--- a/chrome/browser/download/DIR_METADATA
+++ b/chrome/browser/download/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Downloads"
-}
+mixins: "//components/download/COMMON_METADATA"
diff --git a/chrome/browser/extensions/DIR_METADATA b/chrome/browser/extensions/DIR_METADATA
index 81a57a13..e1d704c 100644
--- a/chrome/browser/extensions/DIR_METADATA
+++ b/chrome/browser/extensions/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Platform>Extensions"
-}
-team_email: "extensions-dev@chromium.org"
+mixins: "//extensions/COMMON_METADATA"
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
index d0ce4d4..2d853685 100644
--- a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
+++ b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
@@ -73,6 +73,10 @@
   chromeos::platform_keys::PlatformKeysServiceFactory::GetInstance()
       ->SetTestingMode(true);
 
+  if (system_token_status() == SystemTokenStatus::EXISTS) {
+    CreateTestSystemSlot();
+  }
+
   extensions::MixinBasedExtensionApiTest::SetUp();
 }
 
@@ -160,10 +164,14 @@
 
   if (system_token_status() == SystemTokenStatus::EXISTS) {
     base::RunLoop loop;
-    content::GetIOThreadTaskRunner({})->PostTask(
+    // Call specializations of the virtual method that configures the created
+    // system slot.
+    content::GetIOThreadTaskRunner({})->PostTaskAndReply(
         FROM_HERE,
-        base::BindOnce(&PlatformKeysTestBase::SetUpTestSystemSlotOnIO,
-                       base::Unretained(this), loop.QuitClosure()));
+        base::BindOnce(&PlatformKeysTestBase::PrepareTestSystemSlotOnIO,
+                       base::Unretained(this),
+                       base::Unretained(test_system_slot_.get())),
+        loop.QuitClosure());
     loop.Run();
   }
 
@@ -178,10 +186,11 @@
 
   if (system_token_status() == SystemTokenStatus::EXISTS) {
     base::RunLoop loop;
-    content::GetIOThreadTaskRunner({})->PostTask(
+    content::GetIOThreadTaskRunner({})->PostTaskAndReply(
         FROM_HERE,
         base::BindOnce(&PlatformKeysTestBase::TearDownTestSystemSlotOnIO,
-                       base::Unretained(this), loop.QuitClosure()));
+                       base::Unretained(this)),
+        loop.QuitClosure());
     loop.Run();
   }
   EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
@@ -212,21 +221,12 @@
   return content::IsPreTest();
 }
 
-void PlatformKeysTestBase::SetUpTestSystemSlotOnIO(
-    base::OnceClosure done_callback) {
-  test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>();
+void PlatformKeysTestBase::CreateTestSystemSlot() {
+  test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>(
+      /*simulate_token_loader=*/false);
   ASSERT_TRUE(test_system_slot_->ConstructedSuccessfully());
-
-  PrepareTestSystemSlotOnIO(test_system_slot_.get());
-
-  content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
-                                               std::move(done_callback));
 }
 
-void PlatformKeysTestBase::TearDownTestSystemSlotOnIO(
-    base::OnceClosure done_callback) {
+void PlatformKeysTestBase::TearDownTestSystemSlotOnIO() {
   test_system_slot_.reset();
-
-  content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
-                                               std::move(done_callback));
 }
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h
index cf6882b2..e68437f 100644
--- a/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h
+++ b/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h
@@ -90,8 +90,11 @@
   bool IsPreTest();
 
  private:
-  void SetUpTestSystemSlotOnIO(base::OnceClosure done_callback);
-  void TearDownTestSystemSlotOnIO(base::OnceClosure done_callback);
+  // Create test system slot and prepare crypto:: methods to use it when the
+  // initialization starts.
+  void CreateTestSystemSlot();
+  // Destroy test system slot.
+  void TearDownTestSystemSlotOnIO();
 
   const SystemTokenStatus system_token_status_;
   const EnrollmentStatus enrollment_status_;
diff --git a/chrome/browser/extensions/api/web_request/DIR_METADATA b/chrome/browser/extensions/api/web_request/DIR_METADATA
index 637eb4dc..ab13556 100644
--- a/chrome/browser/extensions/api/web_request/DIR_METADATA
+++ b/chrome/browser/extensions/api/web_request/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Extensions>API"
-}
+mixins: "//extensions/browser/api/web_request/COMMON_METADATA"
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/OWNERS b/chrome/browser/extensions/api/webrtc_logging_private/OWNERS
index c954e42..e5e4f93 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/OWNERS
+++ b/chrome/browser/extensions/api/webrtc_logging_private/OWNERS
@@ -1,3 +1,2 @@
 eladalon@chromium.org
-grunell@chromium.org
 guidou@chromium.org
diff --git a/chrome/browser/extensions/wasm_mv3_browsertest.cc b/chrome/browser/extensions/wasm_mv3_browsertest.cc
index 95c69755..1cdf26f 100644
--- a/chrome/browser/extensions/wasm_mv3_browsertest.cc
+++ b/chrome/browser/extensions/wasm_mv3_browsertest.cc
@@ -52,10 +52,6 @@
 
 // Test web assembly usage in a service worker.
 IN_PROC_BROWSER_TEST_P(WasmMV3BrowserTest, ServiceWorker) {
-  // TODO(crbug.com/1248289): Remove this custom arg override. Currently service
-  // workers can always use web assembly regardless of their CSP.
-  SetCustomArg("expect-wasm-allowed");
-
   ResultCatcher catcher;
 
   ExtensionTestMessageListener listener("ready", true);
diff --git a/chrome/browser/feature_engagement/DIR_METADATA b/chrome/browser/feature_engagement/DIR_METADATA
index feab3f8..02a82b3 100644
--- a/chrome/browser/feature_engagement/DIR_METADATA
+++ b/chrome/browser/feature_engagement/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>FeatureEngagement"
-}
+mixins: "//components/feature_engagement/COMMON_METADATA"
diff --git a/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/DIR_METADATA b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/DIR_METADATA
new file mode 100644
index 0000000..02a82b3
--- /dev/null
+++ b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/feature_engagement/COMMON_METADATA"
diff --git a/chrome/browser/federated_learning/COMMON_METADATA b/chrome/browser/federated_learning/COMMON_METADATA
new file mode 100644
index 0000000..0e6c0305
--- /dev/null
+++ b/chrome/browser/federated_learning/COMMON_METADATA
@@ -0,0 +1 @@
+team_email: "privacy-sandbox-dev@chromium.org"
diff --git a/chrome/browser/federated_learning/DIR_METADATA b/chrome/browser/federated_learning/DIR_METADATA
index 0e6c0305..94c4325 100644
--- a/chrome/browser/federated_learning/DIR_METADATA
+++ b/chrome/browser/federated_learning/DIR_METADATA
@@ -1 +1 @@
-team_email: "privacy-sandbox-dev@chromium.org"
+mixins: "//chrome/browser/federated_learning/COMMON_METADATA"
diff --git a/chrome/browser/feed/DIR_METADATA b/chrome/browser/feed/DIR_METADATA
index 45526208..a042a7015 100644
--- a/chrome/browser/feed/DIR_METADATA
+++ b/chrome/browser/feed/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>ContentSuggestions>Feed"
-}
-team_email: "feed@chromium.org"
+mixins: "//components/feed/COMMON_METADATA"
 os: ANDROID
diff --git a/chrome/browser/feedback/DIR_METADATA b/chrome/browser/feedback/DIR_METADATA
index b5697710..25e9f5bf 100644
--- a/chrome/browser/feedback/DIR_METADATA
+++ b/chrome/browser/feedback/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Platform>Apps>Feedback"
-}
+mixins: "//components/feedback/COMMON_METADATA"
diff --git a/chrome/browser/file_system_access/DIR_METADATA b/chrome/browser/file_system_access/DIR_METADATA
index b2811d9..29ed859f 100644
--- a/chrome/browser/file_system_access/DIR_METADATA
+++ b/chrome/browser/file_system_access/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>Storage>FileSystem"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/file_system_access/COMMON_METADATA"
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index f5f80ea..3c6c44ae 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3170,7 +3170,7 @@
   {
     "name": "force-startup-signin-promo",
     "owners": [ "jlebel", "chrome-signin-team" ],
-    // This is required by test teams and dev teams to verify the startup
+    // This is required by test teams and dev teams to verify the startup
     // sign-in promo functionality.
     "expiry_milestone": -1
   },
diff --git a/chrome/browser/flags/COMMON_METADATA b/chrome/browser/flags/COMMON_METADATA
new file mode 100644
index 0000000..1bfac8b
--- /dev/null
+++ b/chrome/browser/flags/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail: {
+  component: "Internals>Flags"
+}
+team_email: "clank-modularization@chromium.org"
+os: ANDROID
diff --git a/chrome/browser/flags/DIR_METADATA b/chrome/browser/flags/DIR_METADATA
index 1bfac8b..4931f239 100644
--- a/chrome/browser/flags/DIR_METADATA
+++ b/chrome/browser/flags/DIR_METADATA
@@ -1,5 +1 @@
-monorail: {
-  component: "Internals>Flags"
-}
-team_email: "clank-modularization@chromium.org"
-os: ANDROID
+mixins: "//chrome/browser/flags/COMMON_METADATA"
diff --git a/chrome/browser/font_access/DIR_METADATA b/chrome/browser/font_access/DIR_METADATA
index 77e8c1c9..be579e99 100644
--- a/chrome/browser/font_access/DIR_METADATA
+++ b/chrome/browser/font_access/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>Storage>FontAccess"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/font_access/COMMON_METADATA"
diff --git a/chrome/browser/fullscreen/android/DIR_METADATA b/chrome/browser/fullscreen/android/DIR_METADATA
index c51c729..c69388e 100644
--- a/chrome/browser/fullscreen/android/DIR_METADATA
+++ b/chrome/browser/fullscreen/android/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Mobile"
-}
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/chrome/browser/gcm/COMMON_METADATA b/chrome/browser/gcm/COMMON_METADATA
new file mode 100644
index 0000000..777cdb6
--- /dev/null
+++ b/chrome/browser/gcm/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "Services>CloudMessaging"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/chrome/browser/gcm/DIR_METADATA b/chrome/browser/gcm/DIR_METADATA
index 777cdb6..66fe868 100644
--- a/chrome/browser/gcm/DIR_METADATA
+++ b/chrome/browser/gcm/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Services>CloudMessaging"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//chrome/browser/gcm/COMMON_METADATA"
diff --git a/chrome/browser/guest_view/DIR_METADATA b/chrome/browser/guest_view/DIR_METADATA
index df25159e..38cda2d 100644
--- a/chrome/browser/guest_view/DIR_METADATA
+++ b/chrome/browser/guest_view/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Platform>Apps>BrowserTag"
-}
+mixins: "//components/guest_view/COMMON_METADATA"
diff --git a/chrome/browser/headless/DIR_METADATA b/chrome/browser/headless/DIR_METADATA
new file mode 100644
index 0000000..38e3db2
--- /dev/null
+++ b/chrome/browser/headless/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//headless/COMMON_METADATA"
diff --git a/chrome/browser/heavy_ad_intervention/DIR_METADATA b/chrome/browser/heavy_ad_intervention/DIR_METADATA
index 04cdbc4..cc2c627ce 100644
--- a/chrome/browser/heavy_ad_intervention/DIR_METADATA
+++ b/chrome/browser/heavy_ad_intervention/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>AdFilter"
-}
+mixins: "//components/heavy_ad_intervention/COMMON_METADATA"
diff --git a/chrome/browser/hid/DIR_METADATA b/chrome/browser/hid/DIR_METADATA
index 549ba169e..9260825 100644
--- a/chrome/browser/hid/DIR_METADATA
+++ b/chrome/browser/hid/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>HID"
-}
-team_email: "device-dev@chromium.org"
+mixins: "//third_party/blink/renderer/modules/hid/COMMON_METADATA"
diff --git a/chrome/browser/history_clusters/DIR_METADATA b/chrome/browser/history_clusters/DIR_METADATA
index 88f25f6..694e2bf 100644
--- a/chrome/browser/history_clusters/DIR_METADATA
+++ b/chrome/browser/history_clusters/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Memories"
-}
+mixins: "//components/history_clusters/COMMON_METADATA"
diff --git a/chrome/browser/idle/DIR_METADATA b/chrome/browser/idle/DIR_METADATA
index 4245efd..7b9dd684 100644
--- a/chrome/browser/idle/DIR_METADATA
+++ b/chrome/browser/idle/DIR_METADATA
@@ -1 +1 @@
-team_email: "fugu-dev@chromium.org"
+mixins: "//content/browser/idle/COMMON_METADATA"
diff --git a/chrome/browser/image_fetcher/DIR_METADATA b/chrome/browser/image_fetcher/DIR_METADATA
new file mode 100644
index 0000000..eacf064
--- /dev/null
+++ b/chrome/browser/image_fetcher/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/image_fetcher/COMMON_METADATA"
diff --git a/chrome/browser/interest_group/DIR_METADATA b/chrome/browser/interest_group/DIR_METADATA
index dfbd7f35..245f2ac 100644
--- a/chrome/browser/interest_group/DIR_METADATA
+++ b/chrome/browser/interest_group/DIR_METADATA
@@ -1 +1,2 @@
+mixins: "//content/browser/interest_group/COMMON_METADATA"
 team_email: "privacy-sandbox-dev@chromium.org"
\ No newline at end of file
diff --git a/chrome/browser/interstitials/COMMON_METADATA b/chrome/browser/interstitials/COMMON_METADATA
new file mode 100644
index 0000000..8c7ba12d
--- /dev/null
+++ b/chrome/browser/interstitials/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "UI>Browser>Interstitials"
+}
+team_email: "security-enamel@chromium.org"
diff --git a/chrome/browser/interstitials/DIR_METADATA b/chrome/browser/interstitials/DIR_METADATA
index 8c7ba12d..f2acd85 100644
--- a/chrome/browser/interstitials/DIR_METADATA
+++ b/chrome/browser/interstitials/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>Interstitials"
-}
-team_email: "security-enamel@chromium.org"
+mixins: "//chrome/browser/interstitials/COMMON_METADATA"
diff --git a/chrome/browser/invalidation/DIR_METADATA b/chrome/browser/invalidation/DIR_METADATA
index 9b9d0ac..d572883 100644
--- a/chrome/browser/invalidation/DIR_METADATA
+++ b/chrome/browser/invalidation/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Services>Invalidation"
-}
+mixins: "//components/invalidation/COMMON_METADATA"
diff --git a/chrome/browser/language/DIR_METADATA b/chrome/browser/language/DIR_METADATA
index 8d13695..83bdb5a 100644
--- a/chrome/browser/language/DIR_METADATA
+++ b/chrome/browser/language/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Language"
-}
+mixins: "//components/language/COMMON_METADATA"
diff --git a/chrome/browser/loader/DIR_METADATA b/chrome/browser/loader/DIR_METADATA
index a830984f5..df01806 100644
--- a/chrome/browser/loader/DIR_METADATA
+++ b/chrome/browser/loader/DIR_METADATA
@@ -1,3 +1,4 @@
+mixins: "//content/browser/loader/COMMON_METADATA"
 monorail: {
   component: "Internals>Services>Network"
 }
diff --git a/chrome/browser/locale/java/src/org/chromium/chrome/browser/locale/COMMON_METADATA b/chrome/browser/locale/java/src/org/chromium/chrome/browser/locale/COMMON_METADATA
new file mode 100644
index 0000000..0adba788
--- /dev/null
+++ b/chrome/browser/locale/java/src/org/chromium/chrome/browser/locale/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Mobile>SearchWidget"
+}
diff --git a/chrome/browser/locale/java/src/org/chromium/chrome/browser/locale/DIR_METADATA b/chrome/browser/locale/java/src/org/chromium/chrome/browser/locale/DIR_METADATA
index 0adba788..8dd9fb2f 100644
--- a/chrome/browser/locale/java/src/org/chromium/chrome/browser/locale/DIR_METADATA
+++ b/chrome/browser/locale/java/src/org/chromium/chrome/browser/locale/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>SearchWidget"
-}
+mixins: "//chrome/browser/locale/java/src/org/chromium/chrome/browser/locale/COMMON_METADATA"
diff --git a/chrome/browser/media_galleries/COMMON_METADATA b/chrome/browser/media_galleries/COMMON_METADATA
new file mode 100644
index 0000000..bf48267
--- /dev/null
+++ b/chrome/browser/media_galleries/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "Platform>Apps>MediaGalleries"
+}
diff --git a/chrome/browser/media_galleries/DIR_METADATA b/chrome/browser/media_galleries/DIR_METADATA
index bf48267..a9173fc 100644
--- a/chrome/browser/media_galleries/DIR_METADATA
+++ b/chrome/browser/media_galleries/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Platform>Apps>MediaGalleries"
-}
+mixins: "//chrome/browser/media_galleries/COMMON_METADATA"
diff --git a/chrome/browser/metrics/DIR_METADATA b/chrome/browser/metrics/DIR_METADATA
index 876e1056..1c83dc52 100644
--- a/chrome/browser/metrics/DIR_METADATA
+++ b/chrome/browser/metrics/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail: {
-  component: "Internals>Metrics"
-}
+mixins: "//base/metrics/COMMON_METADATA"
 team_email: "chromium-dev@chromium.org"
diff --git a/chrome/browser/net/DIR_METADATA b/chrome/browser/net/DIR_METADATA
index 2ba70d2..09f5b5e 100644
--- a/chrome/browser/net/DIR_METADATA
+++ b/chrome/browser/net/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>Network"
-}
-team_email: "net-dev@chromium.org"
+mixins: "//net/COMMON_METADATA"
diff --git a/chrome/browser/net/nss_service_chromeos.cc b/chrome/browser/net/nss_service_chromeos.cc
index 7baed7f..673de2d 100644
--- a/chrome/browser/net/nss_service_chromeos.cc
+++ b/chrome/browser/net/nss_service_chromeos.cc
@@ -59,7 +59,7 @@
 //                                                           |
 //                                          crypto::InitializeNSSForChromeOSUser
 //                                                           |
-//                                                crypto::IsTPMTokenReady
+//                                                crypto::IsTPMTokenEnabled
 //                                                           |
 //                                          StartTPMSlotInitializationOnIOThread
 //                   v---------------------------------------/
@@ -107,9 +107,15 @@
 }
 
 void StartTPMSlotInitializationOnIOThread(const AccountId& account_id,
-                                          const std::string& username_hash) {
+                                          const std::string& username_hash,
+                                          bool is_tpm_token_enabled) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
+  if (!is_tpm_token_enabled) {
+    crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash);
+    return;
+  }
+
   content::GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE,
       base::BindOnce(&GetTPMInfoForUserOnUIThread, account_id, username_hash));
@@ -132,18 +138,8 @@
     return;
 
   crypto::WillInitializeTPMForChromeOSUser(username_hash);
-
-  if (crypto::IsTPMTokenEnabledForNSS()) {
-    if (crypto::IsTPMTokenReady(
-            base::BindOnce(&StartTPMSlotInitializationOnIOThread, account_id,
-                           username_hash))) {
-      StartTPMSlotInitializationOnIOThread(account_id, username_hash);
-    } else {
-      DVLOG(1) << "Waiting for tpm ready ...";
-    }
-  } else {
-    crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash);
-  }
+  crypto::IsTPMTokenEnabled(base::BindOnce(
+      &StartTPMSlotInitializationOnIOThread, account_id, username_hash));
 }
 
 // Used to convert a callback that takes a net::NSSCertDatabase to one that
@@ -226,16 +222,20 @@
     // This should only be called once.
     DCHECK(!pending_system_slot_);
 
-    crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(
+    crypto::GetSystemNSSKeySlot(
         base::BindOnce(&NSSCertDatabaseChromeOSManager::SetSystemSlotOfDB,
                        weak_ptr_factory_.GetWeakPtr()));
-    if (system_slot)
-      SetSystemSlotOfDB(std::move(system_slot));
   }
 
   void SetSystemSlotOfDB(crypto::ScopedPK11Slot system_slot) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    DCHECK(system_slot);
+    if (!system_slot) {
+      // It's valid for `system_slot` to be nullptr, such as when there is no
+      // TPM, and it's not been overridden for testing. In this scenario,
+      // initialization is complete, because there's nothing to pass to the
+      // NSSCertDatabaseChromeOS.
+      return;
+    }
 
     pending_system_slot_ = std::move(system_slot);
 
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index d3f6dbcf..b1e4150 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -71,7 +71,7 @@
 #include "chrome/browser/ash/policy/networking/policy_cert_service.h"
 #include "chrome/browser/ash/policy/networking/policy_cert_service_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/net/client_cert_store_chromeos.h"
+#include "chrome/browser/chromeos/net/client_cert_store_ash.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
@@ -557,12 +557,12 @@
     certificate_provider = cert_provider_service->CreateCertificateProvider();
   }
 
-  // ClientCertStoreChromeOS internally depends on NSS initialization that
-  // happens when the ResourceContext is created. Call GetResourceContext() so
-  // the dependency is explicit. See https://crbug.com/1018972.
+  // `ClientCertStoreAsh` internally depends on NSS initialization that happens
+  // when the `ResourceContext` is created. Call `GetResourceContext()` so the
+  // dependency is explicit. See https://crbug.com/1018972.
   profile_->GetResourceContext();
 
-  return std::make_unique<chromeos::ClientCertStoreChromeOS>(
+  return std::make_unique<chromeos::ClientCertStoreAsh>(
       std::move(certificate_provider), use_system_key_slot, username_hash,
       base::BindRepeating(&CreateCryptoModuleBlockingPasswordDelegate,
                           kCryptoModulePasswordClientAuth));
diff --git a/chrome/browser/nfc/DIR_METADATA b/chrome/browser/nfc/DIR_METADATA
index 0271108..f38ac080 100644
--- a/chrome/browser/nfc/DIR_METADATA
+++ b/chrome/browser/nfc/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>NFC"
-}
-team_email: "device-dev@chromium.org"
+mixins: "//third_party/blink/renderer/modules/nfc/COMMON_METADATA"
diff --git a/chrome/browser/notifications/COMMON_METADATA b/chrome/browser/notifications/COMMON_METADATA
new file mode 100644
index 0000000..b3b636b3
--- /dev/null
+++ b/chrome/browser/notifications/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "UI>Notifications"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/chrome/browser/notifications/DIR_METADATA b/chrome/browser/notifications/DIR_METADATA
index b3b636b3..2e4e834 100644
--- a/chrome/browser/notifications/DIR_METADATA
+++ b/chrome/browser/notifications/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Notifications"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//chrome/browser/notifications/COMMON_METADATA"
diff --git a/chrome/browser/ntp_tiles/DIR_METADATA b/chrome/browser/ntp_tiles/DIR_METADATA
index 03ca2d5..390105a 100644
--- a/chrome/browser/ntp_tiles/DIR_METADATA
+++ b/chrome/browser/ntp_tiles/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>ContentSuggestions>History"
-}
+mixins: "//components/ntp_tiles/COMMON_METADATA"
diff --git a/chrome/browser/offline_items_collection/DIR_METADATA b/chrome/browser/offline_items_collection/DIR_METADATA
index b3bd965..e91f52f3 100644
--- a/chrome/browser/offline_items_collection/DIR_METADATA
+++ b/chrome/browser/offline_items_collection/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>Downloads"
-}
-team_email: "chrome-downloads@chromium.org"
+mixins: "//components/offline_items_collection/COMMON_METADATA"
diff --git a/chrome/browser/offline_pages/DIR_METADATA b/chrome/browser/offline_pages/DIR_METADATA
index b8fd807..f3d5613e 100644
--- a/chrome/browser/offline_pages/DIR_METADATA
+++ b/chrome/browser/offline_pages/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>Offline"
-}
-team_email: "offline-dev@chromium.org"
+mixins: "//components/offline_pages/COMMON_METADATA"
diff --git a/chrome/browser/optimization_guide/DIR_METADATA b/chrome/browser/optimization_guide/DIR_METADATA
index fb4428a..0a043d53 100644
--- a/chrome/browser/optimization_guide/DIR_METADATA
+++ b/chrome/browser/optimization_guide/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>OptimizationGuide"
-}
+mixins: "//components/optimization_guide/COMMON_METADATA"
diff --git a/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc b/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc
index c685ed61..86890b6 100644
--- a/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc
+++ b/chrome/browser/optimization_guide/hints_fetcher_browsertest.cc
@@ -67,6 +67,13 @@
 
 namespace {
 
+enum class HintsFetcherRemoteResponseType {
+  kSuccessful = 0,
+  kUnsuccessful = 1,
+  kMalformed = 2,
+  kHung = 3,
+};
+
 constexpr char kGoogleHost[] = "www.google.com";
 
 constexpr char kGoogleSearchUrlPath[] = "/search?q=search_results_page.html";
@@ -228,8 +235,7 @@
         network::mojom::ConnectionType::CONNECTION_2G);
   }
 
-  void SetResponseType(
-      optimization_guide::HintsFetcherRemoteResponseType response_type) {
+  void SetResponseType(HintsFetcherRemoteResponseType response_type) {
     response_type_ = response_type;
   }
 
@@ -301,8 +307,8 @@
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<net::EmbeddedTestServer> origin_server_;
   std::unique_ptr<net::EmbeddedTestServer> hints_server_;
-  optimization_guide::HintsFetcherRemoteResponseType response_type_ =
-      optimization_guide::HintsFetcherRemoteResponseType::kSuccessful;
+  HintsFetcherRemoteResponseType response_type_ =
+      HintsFetcherRemoteResponseType::kSuccessful;
 
  private:
   std::unique_ptr<net::test_server::HttpResponse> HandleOriginRequest(
@@ -334,8 +340,7 @@
     if (!hints_request.hosts().empty())
       VerifyHintsMatchExpectedHostsAndUrls(hints_request);
 
-    if (response_type_ ==
-        optimization_guide::HintsFetcherRemoteResponseType::kSuccessful) {
+    if (response_type_ == HintsFetcherRemoteResponseType::kSuccessful) {
       response->set_code(net::HTTP_OK);
 
       optimization_guide::proto::GetHintsResponse get_hints_response;
@@ -350,18 +355,15 @@
       get_hints_response.SerializeToString(&serialized_request);
       response->set_content(serialized_request);
     } else if (response_type_ ==
-               optimization_guide::HintsFetcherRemoteResponseType::
-                   kUnsuccessful) {
+               HintsFetcherRemoteResponseType::kUnsuccessful) {
       response->set_code(net::HTTP_NOT_FOUND);
 
-    } else if (response_type_ ==
-               optimization_guide::HintsFetcherRemoteResponseType::kMalformed) {
+    } else if (response_type_ == HintsFetcherRemoteResponseType::kMalformed) {
       response->set_code(net::HTTP_OK);
 
       std::string serialized_request = "Not a proto";
       response->set_content(serialized_request);
-    } else if (response_type_ ==
-               optimization_guide::HintsFetcherRemoteResponseType::kHung) {
+    } else if (response_type_ == HintsFetcherRemoteResponseType::kHung) {
       return std::make_unique<net::test_server::HungResponse>();
     } else {
       NOTREACHED();
@@ -563,8 +565,7 @@
 
 IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
                        HintsFetcherWithResponsesSuccessful) {
-  SetResponseType(
-      optimization_guide::HintsFetcherRemoteResponseType::kSuccessful);
+  SetResponseType(HintsFetcherRemoteResponseType::kSuccessful);
 
   const base::HistogramTester* histogram_tester = GetHistogramTester();
 
@@ -595,8 +596,7 @@
 
 IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
                        HintsFetcherWithResponsesUnsuccessful) {
-  SetResponseType(
-      optimization_guide::HintsFetcherRemoteResponseType::kUnsuccessful);
+  SetResponseType(HintsFetcherRemoteResponseType::kUnsuccessful);
 
   const base::HistogramTester* histogram_tester = GetHistogramTester();
 
@@ -626,8 +626,7 @@
 
 IN_PROC_BROWSER_TEST_F(HintsFetcherBrowserTest,
                        HintsFetcherWithResponsesMalformed) {
-  SetResponseType(
-      optimization_guide::HintsFetcherRemoteResponseType::kMalformed);
+  SetResponseType(HintsFetcherRemoteResponseType::kMalformed);
 
   const base::HistogramTester* histogram_tester = GetHistogramTester();
 
@@ -661,8 +660,7 @@
                        HintsFetcherWithResponsesUnsuccessfulAtNavigationTime) {
   const base::HistogramTester* histogram_tester = GetHistogramTester();
 
-  SetResponseType(
-      optimization_guide::HintsFetcherRemoteResponseType::kUnsuccessful);
+  SetResponseType(HintsFetcherRemoteResponseType::kUnsuccessful);
 
   // Set the connection online to force a fetch at navigation time.
   SetNetworkConnectionOnline();
@@ -682,7 +680,7 @@
     HintsFetcherWithResponsesHungShouldRecordWhenActiveRequestCanceled) {
   const base::HistogramTester* histogram_tester = GetHistogramTester();
 
-  SetResponseType(optimization_guide::HintsFetcherRemoteResponseType::kHung);
+  SetResponseType(HintsFetcherRemoteResponseType::kHung);
 
   // Set the connection online to force a fetch at navigation time.
   SetNetworkConnectionOnline();
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager.cc b/chrome/browser/optimization_guide/prediction/prediction_manager.cc
index 123bf4a0..f5f0e0a 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager.cc
@@ -166,7 +166,7 @@
   absl::optional<
       std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
       model_file_path_and_metadata =
-          optimization_guide::GetModelOverrideForOptimizationTarget(
+          optimization_guide::switches::GetModelOverrideForOptimizationTarget(
               optimization_target);
   if (!model_file_path_and_metadata)
     return nullptr;
diff --git a/chrome/browser/page_info/DIR_METADATA b/chrome/browser/page_info/DIR_METADATA
new file mode 100644
index 0000000..aed523b0
--- /dev/null
+++ b/chrome/browser/page_info/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ui/page_info/COMMON_METADATA"
diff --git a/chrome/browser/paint_preview/DIR_METADATA b/chrome/browser/paint_preview/DIR_METADATA
index 9cca4c1..1148592 100644
--- a/chrome/browser/paint_preview/DIR_METADATA
+++ b/chrome/browser/paint_preview/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>FreezeDriedTabs"
-}
+mixins: "//components/paint_preview/COMMON_METADATA"
diff --git a/chrome/browser/password_manager/DIR_METADATA b/chrome/browser/password_manager/DIR_METADATA
index b420232..5b9fb11 100644
--- a/chrome/browser/password_manager/DIR_METADATA
+++ b/chrome/browser/password_manager/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>Passwords"
-}
-team_email: "chromium-dev@chromium.org"
+mixins: "//components/password_manager/COMMON_METADATA"
diff --git a/chrome/browser/payments/DIR_METADATA b/chrome/browser/payments/DIR_METADATA
new file mode 100644
index 0000000..9dddbb4
--- /dev/null
+++ b/chrome/browser/payments/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/payments/COMMON_METADATA"
diff --git a/chrome/browser/pdf/DIR_METADATA b/chrome/browser/pdf/DIR_METADATA
index 11b8e5a..0563e2c 100644
--- a/chrome/browser/pdf/DIR_METADATA
+++ b/chrome/browser/pdf/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Plugins>PDF"
-}
+mixins: "//pdf/COMMON_METADATA"
diff --git a/chrome/browser/performance_manager/DIR_METADATA b/chrome/browser/performance_manager/DIR_METADATA
new file mode 100644
index 0000000..e9e0173
--- /dev/null
+++ b/chrome/browser/performance_manager/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/performance_manager/COMMON_METADATA"
diff --git a/chrome/browser/performance_monitor/process_metrics_recorder_util.cc b/chrome/browser/performance_monitor/process_metrics_recorder_util.cc
index 19d1178..2598b37 100644
--- a/chrome/browser/performance_monitor/process_metrics_recorder_util.cc
+++ b/chrome/browser/performance_monitor/process_metrics_recorder_util.cc
@@ -11,7 +11,9 @@
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#if defined(OS_MAC)
 #include "chrome/browser/performance_monitor/resource_coalition_mac.h"
+#endif
 
 namespace performance_monitor {
 
diff --git a/chrome/browser/performance_monitor/process_metrics_recorder_util_unittest.cc b/chrome/browser/performance_monitor/process_metrics_recorder_util_unittest.cc
index 997cc66..1d4b3e59 100644
--- a/chrome/browser/performance_monitor/process_metrics_recorder_util_unittest.cc
+++ b/chrome/browser/performance_monitor/process_metrics_recorder_util_unittest.cc
@@ -7,9 +7,12 @@
 #include "base/strings/strcat.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
-#include "chrome/browser/performance_monitor/resource_coalition_mac.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_MAC)
+#include "chrome/browser/performance_monitor/resource_coalition_mac.h"
+#endif
+
 namespace performance_monitor {
 
 #if defined(OS_MAC)
diff --git a/chrome/browser/performance_monitor/resource_coalition_mac.h b/chrome/browser/performance_monitor/resource_coalition_mac.h
index 52d8cdd3..dc199a4 100644
--- a/chrome/browser/performance_monitor/resource_coalition_mac.h
+++ b/chrome/browser/performance_monitor/resource_coalition_mac.h
@@ -147,7 +147,7 @@
   // Note that this only has relevance on Intel architecture, as it looks like
   // on M1 architecture macOS implements more granular, and hopefully more
   // accurate, energy metering on the fly.
-  static double ComputeEnergyImpactForCoalitionUsage(
+  double ComputeEnergyImpactForCoalitionUsage(
       const EnergyImpactCoefficients& coefficients,
       const coalition_resource_usage& data_sample);
 
@@ -158,9 +158,14 @@
   void SetEnergyImpactCoefficientsForTesting(
       const absl::optional<EnergyImpactCoefficients>& coefficients);
 
+  // Override the machine time base for testing.
+  void SetMachTimebaseForTesting(
+      const mach_timebase_info_data_t& mach_timebase);
+
  private:
   void EnsureEnergyImpactCoefficientsIfAvailable();
   void SetCoalitionId(absl::optional<uint64_t> coalition_id);
+  uint64_t MachTimeToNs(uint64_t mach_time);
 
   // Computes the diff between two coalition_resource_usage objects and stores
   // the per-second change rate for each field in a ResourceCoalition::Data
@@ -180,6 +185,10 @@
   // available.
   absl::optional<uint64_t> coalition_id_;
 
+  // Used to convert coalition_resource_usage time fields from
+  // mach_absolute_time units to ns.
+  mach_timebase_info_data_t mach_timebase_;
+
   // The data sample collected during the last call to GetDataDiff or since
   // creating this object.
   std::unique_ptr<coalition_resource_usage> last_data_sample_;
diff --git a/chrome/browser/performance_monitor/resource_coalition_mac.mm b/chrome/browser/performance_monitor/resource_coalition_mac.mm
index c0698ab..cb79e3d8 100644
--- a/chrome/browser/performance_monitor/resource_coalition_mac.mm
+++ b/chrome/browser/performance_monitor/resource_coalition_mac.mm
@@ -136,6 +136,12 @@
   SetCoalitionId(GetCurrentCoalitionId(&availability_details));
   base::UmaHistogramEnumeration(kCoalitionAvailabilityHistogram,
                                 availability_details);
+
+  // Initialize the machine timebase.
+  kern_return_t kr = mach_timebase_info(&mach_timebase_);
+  DCHECK_EQ(kr, KERN_SUCCESS);
+  DCHECK(mach_timebase_.numer);
+  DCHECK(mach_timebase_.denom);
 }
 ResourceCoalition::~ResourceCoalition() = default;
 
@@ -177,7 +183,7 @@
     if (!energy_constants)
       return absl::nullopt;
 
-    EnergyImpactCoefficients coefficients;
+    EnergyImpactCoefficients coefficients{};
     coefficients.kcpu_time =
         GetNamedCoefficientOrZero(energy_constants, @"kcpu_time");
     coefficients.kcpu_wakeups =
@@ -231,7 +237,6 @@
       directory.Append(FILE_PATH_LITERAL("default.plist")));
 }
 
-// static
 double ResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
     const EnergyImpactCoefficients& coefficients,
     const coalition_resource_usage& data_sample) {
@@ -260,22 +265,27 @@
   // of GPU time energy to CPU time energy. There is a fairly wide spread on
   // this constant seen in /usr/share/pmenergy. On macOS 11.5.2 the spread is
   // from 0 through 5.9.
-  cpu_time_equivalent_ns += coefficients.kgpu_time * data_sample.gpu_time;
+  cpu_time_equivalent_ns +=
+      coefficients.kgpu_time * MachTimeToNs(data_sample.gpu_time);
 
-  cpu_time_equivalent_ns += coefficients.kqos_background *
-                            data_sample.cpu_time_eqos[THREAD_QOS_BACKGROUND];
   cpu_time_equivalent_ns +=
-      coefficients.kqos_default * data_sample.cpu_time_eqos[THREAD_QOS_DEFAULT];
+      coefficients.kqos_background *
+      MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_BACKGROUND]);
   cpu_time_equivalent_ns +=
-      coefficients.kqos_legacy * data_sample.cpu_time_eqos[THREAD_QOS_LEGACY];
+      coefficients.kqos_default *
+      MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_DEFAULT]);
+  cpu_time_equivalent_ns +=
+      coefficients.kqos_legacy *
+      MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_LEGACY]);
   cpu_time_equivalent_ns +=
       coefficients.kqos_user_initiated *
-      data_sample.cpu_time_eqos[THREAD_QOS_USER_INITIATED];
+      MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_USER_INITIATED]);
   cpu_time_equivalent_ns +=
       coefficients.kqos_user_interactive *
-      data_sample.cpu_time_eqos[THREAD_QOS_USER_INTERACTIVE];
+      MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_USER_INTERACTIVE]);
   cpu_time_equivalent_ns +=
-      coefficients.kqos_utility * data_sample.cpu_time_eqos[THREAD_QOS_UTILITY];
+      coefficients.kqos_utility *
+      MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_UTILITY]);
 
   // The conversion ratio for CPU time/EnergyImpact is ns/10ms
   constexpr double kNsToEI = 1E-7;
@@ -308,6 +318,11 @@
   energy_impact_coefficients_ = coefficients;
 }
 
+void ResourceCoalition::SetMachTimebaseForTesting(
+    const mach_timebase_info_data_t& mach_timebase) {
+  mach_timebase_ = mach_timebase;
+}
+
 void ResourceCoalition::EnsureEnergyImpactCoefficientsIfAvailable() {
   if (energy_impact_coefficients_initialized_)
     return;
@@ -330,6 +345,15 @@
   }
 }
 
+uint64_t ResourceCoalition::MachTimeToNs(uint64_t mach_time) {
+  if (mach_timebase_.numer == mach_timebase_.denom)
+    return mach_time;
+
+  CHECK(
+      !__builtin_umulll_overflow(mach_time, mach_timebase_.numer, &mach_time));
+  return mach_time / mach_timebase_.denom;
+}
+
 absl::optional<ResourceCoalition::DataRate>
 ResourceCoalition::GetCoalitionDataDiff(
     const coalition_resource_usage& new_sample,
@@ -366,12 +390,16 @@
     return diff / interval_length.InSecondsF();
   };
 
-  auto get_timedelta_rate_per_second =
-      [&interval_length](uint64_t new_sample, uint64_t old_sample) -> double {
+  auto get_timedelta_rate_per_second = [&interval_length, self = this](
+                                           uint64_t new_sample,
+                                           uint64_t old_sample) -> double {
     DCHECK_GE(new_sample, old_sample);
-    base::TimeDelta time_delta =
-        base::TimeDelta::FromNanoseconds(new_sample - old_sample);
-    return time_delta.InSecondsF() / interval_length.InSecondsF();
+    // Compute the delta in s, being careful to avoid truncation due to integral
+    // division.
+    double delta_sample_s =
+        self->MachTimeToNs(new_sample - old_sample) /
+        static_cast<double>(base::Time::kNanosecondsPerSecond);
+    return delta_sample_s / interval_length.InSecondsF();
   };
 
   ret.cpu_time_per_second =
diff --git a/chrome/browser/performance_monitor/resource_coalition_mac_unittest.mm b/chrome/browser/performance_monitor/resource_coalition_mac_unittest.mm
index 9b9a9d9..11aa7673 100644
--- a/chrome/browser/performance_monitor/resource_coalition_mac_unittest.mm
+++ b/chrome/browser/performance_monitor/resource_coalition_mac_unittest.mm
@@ -25,8 +25,18 @@
 
 namespace {
 
+constexpr mach_timebase_info_data_t kIntelTimebase = {1, 1};
+
+// A sample (not definitive) timebase for M1.
+constexpr mach_timebase_info_data_t kM1Timebase = {125, 3};
+
+// Initializes to no EI constants and the Intel timebase.
 class TestResourceCoalition : public ResourceCoalition {
  public:
+  TestResourceCoalition() {
+    SetEnergyImpactCoefficientsForTesting(absl::nullopt);
+    SetMachTimebaseForTesting(kIntelTimebase);
+  }
   // Expose as public for testing.
   using ResourceCoalition::SetCoalitionIDToCurrentProcessIdForTesting;
   using ResourceCoalition::GetDataRateFromFakeDataForTesting;
@@ -36,6 +46,7 @@
   using ResourceCoalition::ReadEnergyImpactOrDefaultForBoardId;
   using ResourceCoalition::MaybeGetBoardIdForThisMachine;
   using ResourceCoalition::SetEnergyImpactCoefficientsForTesting;
+  using ResourceCoalition::SetMachTimebaseForTesting;
 };
 using EnergyImpactCoefficients =
     TestResourceCoalition::EnergyImpactCoefficients;
@@ -55,8 +66,7 @@
   return coefficients;
 }
 
-static constexpr base::TimeDelta kIntervalLength =
-    base::TimeDelta::FromSecondsD(2.5);
+constexpr base::TimeDelta kIntervalLength = base::TimeDelta::FromSecondsD(2.5);
 
 TEST(ResourceCoalitionTests, Basics) {
   base::HistogramTester histogram_tester;
@@ -95,50 +105,63 @@
 constexpr double kExpectedBytesReadPerSecond = 0.8;
 constexpr double kExpectedBytesWrittenPerSecond = 1.6;
 constexpr double kExpectedPowerNW = 10000.0;
+// This number will be multiplied by the int value associated with a QoS level
+// to compute the expected time spent in this QoS level. E.g.
+// |QoSLevels::kUtility == 3| so the time spent in the utility QoS state will
+// be set to 3 * 0.1 = 30%.
 constexpr double kExpectedQoSTimeBucketIdMultiplier = 0.1;
 
-coalition_resource_usage GetCoalitionResourceUsageTestData() {
-  coalition_resource_usage test_data{};
-  test_data.cpu_time =
-      kExpectedCPUUsagePerSecondPercent * kIntervalLength.InNanoseconds();
-  test_data.interrupt_wakeups =
+// Scales a time given in ns to mach_time in |timebase|.
+uint64_t NsScaleToTimebase(const mach_timebase_info_data_t& timebase,
+                           int64_t time_ns) {
+  return time_ns * timebase.denom / timebase.numer;
+}
+
+// Returns test data with all time quantities scaled to the given time base.
+std::unique_ptr<coalition_resource_usage> GetCoalitionResourceUsageTestData(
+    const mach_timebase_info_data_t& timebase) {
+  std::unique_ptr<coalition_resource_usage> test_data =
+      std::make_unique<coalition_resource_usage>();
+
+  // Scales a time given in ns to mach_time in |timebase|.
+  auto scale_to_timebase = [&timebase](double time_ns) -> int64_t {
+    return NsScaleToTimebase(timebase, time_ns);
+  };
+
+  test_data->cpu_time = scale_to_timebase(kExpectedCPUUsagePerSecondPercent *
+                                          kIntervalLength.InNanoseconds());
+  test_data->interrupt_wakeups =
       kExpectedInterruptWakeUpPerSecond * kIntervalLength.InSecondsF();
-  test_data.platform_idle_wakeups =
+  test_data->platform_idle_wakeups =
       kExpectedPlatformIdleWakeUpPerSecond * kIntervalLength.InSecondsF();
-  test_data.bytesread =
+  test_data->bytesread =
       kExpectedBytesReadPerSecond * kIntervalLength.InSecondsF();
-  test_data.byteswritten =
+  test_data->byteswritten =
       kExpectedBytesWrittenPerSecond * kIntervalLength.InSecondsF();
-  test_data.gpu_time =
-      kExpectedGPUUsagePerSecondPercent * kIntervalLength.InNanoseconds();
-  test_data.energy = kExpectedPowerNW * kIntervalLength.InSecondsF();
+  test_data->gpu_time = scale_to_timebase(kExpectedGPUUsagePerSecondPercent *
+                                          kIntervalLength.InNanoseconds());
+  test_data->energy = kExpectedPowerNW * kIntervalLength.InSecondsF();
   for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
-    test_data.cpu_time_eqos[i] = i * kExpectedQoSTimeBucketIdMultiplier *
-                                 kIntervalLength.InNanoseconds();
+    test_data->cpu_time_eqos[i] =
+        scale_to_timebase(i * kExpectedQoSTimeBucketIdMultiplier *
+                          kIntervalLength.InNanoseconds());
   }
-  test_data.cpu_time_eqos_len = COALITION_NUM_THREAD_QOS_TYPES;
+  test_data->cpu_time_eqos_len = COALITION_NUM_THREAD_QOS_TYPES;
 
   return test_data;
 }
 
-TEST(ResourceCoalitionTests, GetDataRate_NoEnergyImpact) {
+TEST(ResourceCoalitionTests, GetDataRate_NoEnergyImpact_Intel) {
   TestResourceCoalition coalition;
   coalition.SetCoalitionIDToCurrentProcessIdForTesting();
-  coalition.SetEnergyImpactCoefficientsForTesting(absl::nullopt);
 
   EXPECT_TRUE(coalition.IsAvailable());
 
-  // This number will be multiplied by the int value associated with a QoS level
-  // to compute the expected time spent in this QoS level. E.g.
-  // |QoSLevels::kUtility == 3| so the time spent in the utility QoS state will
-  // be set to 3 * 0.1 = 30%.
-
   // Keep the initial data zero initialized.
   std::unique_ptr<coalition_resource_usage> t0_data =
       std::make_unique<coalition_resource_usage>();
   std::unique_ptr<coalition_resource_usage> t1_data =
-      std::make_unique<coalition_resource_usage>(
-          GetCoalitionResourceUsageTestData());
+      GetCoalitionResourceUsageTestData(kIntelTimebase);
 
   auto data_rate = coalition.GetDataRateFromFakeDataForTesting(
       std::move(t0_data), std::move(t1_data), kIntervalLength);
@@ -160,8 +183,44 @@
   }
 }
 
-TEST(ResourceCoalitionTests, GetDataRate_WithEnergyImpact) {
-  base::HistogramTester histogram_tester;
+TEST(ResourceCoalitionTests, GetDataRate_NoEnergyImpact_M1) {
+  TestResourceCoalition coalition;
+  coalition.SetCoalitionIDToCurrentProcessIdForTesting();
+  coalition.SetMachTimebaseForTesting(kM1Timebase);
+
+  EXPECT_TRUE(coalition.IsAvailable());
+
+  // Keep the initial data zero initialized.
+  std::unique_ptr<coalition_resource_usage> t0_data =
+      std::make_unique<coalition_resource_usage>();
+  std::unique_ptr<coalition_resource_usage> t1_data =
+      GetCoalitionResourceUsageTestData(kM1Timebase);
+
+  auto data_rate = coalition.GetDataRateFromFakeDataForTesting(
+      std::move(t0_data), std::move(t1_data), kIntervalLength);
+  ASSERT_TRUE(data_rate);
+  EXPECT_DOUBLE_EQ(kExpectedCPUUsagePerSecondPercent,
+                   data_rate->cpu_time_per_second);
+  EXPECT_DOUBLE_EQ(kExpectedInterruptWakeUpPerSecond,
+                   data_rate->interrupt_wakeups_per_second);
+  EXPECT_DOUBLE_EQ(kExpectedPlatformIdleWakeUpPerSecond,
+                   data_rate->platform_idle_wakeups_per_second);
+  EXPECT_DOUBLE_EQ(kExpectedBytesReadPerSecond,
+                   data_rate->bytesread_per_second);
+  EXPECT_DOUBLE_EQ(kExpectedBytesWrittenPerSecond,
+                   data_rate->byteswritten_per_second);
+  EXPECT_DOUBLE_EQ(kExpectedGPUUsagePerSecondPercent,
+                   data_rate->gpu_time_per_second);
+  EXPECT_DOUBLE_EQ(0, data_rate->energy_impact_per_second);
+  EXPECT_DOUBLE_EQ(kExpectedPowerNW, data_rate->power_nw);
+
+  for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+    EXPECT_DOUBLE_EQ(i * kExpectedQoSTimeBucketIdMultiplier,
+                     data_rate->qos_time_per_second[i]);
+  }
+}
+
+TEST(ResourceCoalitionTests, GetDataRate_WithEnergyImpact_Intel) {
   TestResourceCoalition coalition;
   coalition.SetCoalitionIDToCurrentProcessIdForTesting();
   coalition.SetEnergyImpactCoefficientsForTesting(
@@ -170,8 +229,42 @@
   std::unique_ptr<coalition_resource_usage> t0_data =
       std::make_unique<coalition_resource_usage>();
   std::unique_ptr<coalition_resource_usage> t1_data =
-      std::make_unique<coalition_resource_usage>(
-          GetCoalitionResourceUsageTestData());
+      GetCoalitionResourceUsageTestData(kIntelTimebase);
+
+  auto ei_data_rate = coalition.GetDataRateFromFakeDataForTesting(
+      std::move(t0_data), std::move(t1_data), kIntervalLength);
+  ASSERT_TRUE(ei_data_rate);
+  EXPECT_EQ(kExpectedCPUUsagePerSecondPercent,
+            ei_data_rate->cpu_time_per_second);
+  EXPECT_EQ(kExpectedInterruptWakeUpPerSecond,
+            ei_data_rate->interrupt_wakeups_per_second);
+  EXPECT_EQ(kExpectedPlatformIdleWakeUpPerSecond,
+            ei_data_rate->platform_idle_wakeups_per_second);
+  EXPECT_EQ(kExpectedBytesReadPerSecond, ei_data_rate->bytesread_per_second);
+  EXPECT_EQ(kExpectedBytesWrittenPerSecond,
+            ei_data_rate->byteswritten_per_second);
+  EXPECT_EQ(kExpectedGPUUsagePerSecondPercent,
+            ei_data_rate->gpu_time_per_second);
+  EXPECT_EQ(271.2, ei_data_rate->energy_impact_per_second);
+  EXPECT_FLOAT_EQ(kExpectedPowerNW, ei_data_rate->power_nw);
+
+  for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+    EXPECT_DOUBLE_EQ(i * kExpectedQoSTimeBucketIdMultiplier,
+                     ei_data_rate->qos_time_per_second[i]);
+  }
+}
+
+TEST(ResourceCoalitionTests, GetDataRate_WithEnergyImpact_M1) {
+  TestResourceCoalition coalition;
+  coalition.SetCoalitionIDToCurrentProcessIdForTesting();
+  coalition.SetEnergyImpactCoefficientsForTesting(
+      GetEnergyImpactTestCoefficients());
+  coalition.SetMachTimebaseForTesting(kM1Timebase);
+
+  std::unique_ptr<coalition_resource_usage> t0_data =
+      std::make_unique<coalition_resource_usage>();
+  std::unique_ptr<coalition_resource_usage> t1_data =
+      GetCoalitionResourceUsageTestData(kM1Timebase);
 
   auto ei_data_rate = coalition.GetDataRateFromFakeDataForTesting(
       std::move(t0_data), std::move(t1_data), kIntervalLength);
@@ -242,7 +335,6 @@
 TEST(ResourceCoalitionTests, Overflows) {
   TestResourceCoalition coalition;
   coalition.SetCoalitionIDToCurrentProcessIdForTesting();
-  coalition.SetEnergyImpactCoefficientsForTesting(absl::nullopt);
 
   EXPECT_TRUE(coalition.IsAvailable());
 
@@ -375,12 +467,13 @@
 }
 
 TEST(ResourceCoalitionTests, ComputeEnergyImpactForCoalitionUsage_Individual) {
-  EXPECT_EQ(0.0, TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
+  TestResourceCoalition coalition;
+  EXPECT_EQ(0.0, coalition.ComputeEnergyImpactForCoalitionUsage(
                      EnergyImpactCoefficients(), coalition_resource_usage()));
 
   // Test the coefficients and sample factors individually.
   EXPECT_DOUBLE_EQ(
-      2.66, TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
+      2.66, coalition.ComputeEnergyImpactForCoalitionUsage(
                 EnergyImpactCoefficients{
                     .kcpu_wakeups =
                         base::TimeDelta::FromMicroseconds(200).InSecondsF()},
@@ -388,43 +481,41 @@
 
   // Test 100 ms of CPU, which should come out to 8% of a CPU second with a
   // background QOS discount of rate of 0.8.
+  EXPECT_DOUBLE_EQ(8.0, coalition.ComputeEnergyImpactForCoalitionUsage(
+                            EnergyImpactCoefficients{.kqos_background = 0.8},
+                            MakeResourceUsageWithQOS(
+                                THREAD_QOS_BACKGROUND,
+                                base::TimeDelta::FromMilliseconds(100))));
   EXPECT_DOUBLE_EQ(
-      8.0,
-      TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
-          EnergyImpactCoefficients{.kqos_background = 0.8},
-          MakeResourceUsageWithQOS(THREAD_QOS_BACKGROUND,
-                                   base::TimeDelta::FromMilliseconds(100))));
-  EXPECT_DOUBLE_EQ(
-      5.0, TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
+      5.0, coalition.ComputeEnergyImpactForCoalitionUsage(
                EnergyImpactCoefficients{.kqos_default = 1.0},
                MakeResourceUsageWithQOS(
                    THREAD_QOS_DEFAULT, base::TimeDelta::FromMilliseconds(50))));
+  EXPECT_DOUBLE_EQ(10.0, coalition.ComputeEnergyImpactForCoalitionUsage(
+                             EnergyImpactCoefficients{.kqos_utility = 1.0},
+                             MakeResourceUsageWithQOS(
+                                 THREAD_QOS_UTILITY,
+                                 base::TimeDelta::FromMilliseconds(100))));
   EXPECT_DOUBLE_EQ(
-      10.0,
-      TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
-          EnergyImpactCoefficients{.kqos_utility = 1.0},
-          MakeResourceUsageWithQOS(THREAD_QOS_UTILITY,
-                                   base::TimeDelta::FromMilliseconds(100))));
-  EXPECT_DOUBLE_EQ(
-      1.0, TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
+      1.0, coalition.ComputeEnergyImpactForCoalitionUsage(
                EnergyImpactCoefficients{.kqos_legacy = 1.0},
                MakeResourceUsageWithQOS(
                    THREAD_QOS_LEGACY, base::TimeDelta::FromMilliseconds(10))));
   EXPECT_DOUBLE_EQ(
       1.0,
-      TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
+      coalition.ComputeEnergyImpactForCoalitionUsage(
           EnergyImpactCoefficients{.kqos_user_initiated = 1.0},
           MakeResourceUsageWithQOS(THREAD_QOS_USER_INITIATED,
                                    base::TimeDelta::FromMilliseconds(10))));
   EXPECT_DOUBLE_EQ(
       1.0,
-      TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
+      coalition.ComputeEnergyImpactForCoalitionUsage(
           EnergyImpactCoefficients{.kqos_user_interactive = 1.0},
           MakeResourceUsageWithQOS(THREAD_QOS_USER_INTERACTIVE,
                                    base::TimeDelta::FromMilliseconds(10))));
 
   EXPECT_DOUBLE_EQ(
-      1.0, TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
+      1.0, coalition.ComputeEnergyImpactForCoalitionUsage(
                EnergyImpactCoefficients{.kgpu_time = 2.5},
                coalition_resource_usage{
                    .gpu_time =
@@ -445,25 +536,27 @@
   };
   coalition_resource_usage sample{
       .platform_idle_wakeups = 133,
-      .gpu_time = base::TimeDelta::FromMilliseconds(4).InNanoseconds(),
+      .gpu_time = NsScaleToTimebase(
+          kM1Timebase, base::TimeDelta::FromMilliseconds(4).InNanoseconds()),
       .cpu_time_eqos_len = COALITION_NUM_THREAD_QOS_TYPES,
   };
-  sample.cpu_time_eqos[THREAD_QOS_BACKGROUND] =
-      base::TimeDelta::FromMilliseconds(100).InNanoseconds();
-  sample.cpu_time_eqos[THREAD_QOS_DEFAULT] =
-      base::TimeDelta::FromMilliseconds(50).InNanoseconds();
-  sample.cpu_time_eqos[THREAD_QOS_UTILITY] =
-      base::TimeDelta::FromMilliseconds(100).InNanoseconds();
-  sample.cpu_time_eqos[THREAD_QOS_LEGACY] =
-      base::TimeDelta::FromMilliseconds(10).InNanoseconds();
-  sample.cpu_time_eqos[THREAD_QOS_USER_INITIATED] =
-      base::TimeDelta::FromMilliseconds(10).InNanoseconds();
-  sample.cpu_time_eqos[THREAD_QOS_USER_INTERACTIVE] =
-      base::TimeDelta::FromMilliseconds(10).InNanoseconds();
+  sample.cpu_time_eqos[THREAD_QOS_BACKGROUND] = NsScaleToTimebase(
+      kM1Timebase, base::TimeDelta::FromMilliseconds(100).InNanoseconds());
+  sample.cpu_time_eqos[THREAD_QOS_DEFAULT] = NsScaleToTimebase(
+      kM1Timebase, base::TimeDelta::FromMilliseconds(50).InNanoseconds());
+  sample.cpu_time_eqos[THREAD_QOS_UTILITY] = NsScaleToTimebase(
+      kM1Timebase, base::TimeDelta::FromMilliseconds(100).InNanoseconds());
+  sample.cpu_time_eqos[THREAD_QOS_LEGACY] = NsScaleToTimebase(
+      kM1Timebase, base::TimeDelta::FromMilliseconds(10).InNanoseconds());
+  sample.cpu_time_eqos[THREAD_QOS_USER_INITIATED] = NsScaleToTimebase(
+      kM1Timebase, base::TimeDelta::FromMilliseconds(10).InNanoseconds());
+  sample.cpu_time_eqos[THREAD_QOS_USER_INTERACTIVE] = NsScaleToTimebase(
+      kM1Timebase, base::TimeDelta::FromMilliseconds(10).InNanoseconds());
 
-  EXPECT_DOUBLE_EQ(29.66,
-                   TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
-                       coefficients, sample));
+  TestResourceCoalition coalition;
+  coalition.SetMachTimebaseForTesting(kM1Timebase);
+  EXPECT_DOUBLE_EQ(29.66, coalition.ComputeEnergyImpactForCoalitionUsage(
+                              coefficients, sample));
 }
 
 TEST(ResourceCoalitionTests, ComputeEnergyImpactForCoalitionUsage_Unused) {
@@ -504,8 +597,9 @@
       .pm_writes = 1000,
   };
 
-  EXPECT_EQ(0, TestResourceCoalition::ComputeEnergyImpactForCoalitionUsage(
-                   coefficients, sample));
+  TestResourceCoalition coalition;
+  EXPECT_EQ(
+      0, coalition.ComputeEnergyImpactForCoalitionUsage(coefficients, sample));
 }
 
 TEST(ResourceCoalitionTests, ReadEnergyImpactOrDefaultForBoardId_Exists) {
diff --git a/chrome/browser/picture_in_picture/DIR_METADATA b/chrome/browser/picture_in_picture/DIR_METADATA
index 9f78557..26f3796 100644
--- a/chrome/browser/picture_in_picture/DIR_METADATA
+++ b/chrome/browser/picture_in_picture/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>Media>PictureInPicture"
-}
-team_email: "media-dev@chromium.org"
+mixins: "//third_party/blink/renderer/modules/picture_in_picture/COMMON_METADATA"
diff --git a/chrome/browser/policy/DIR_METADATA b/chrome/browser/policy/DIR_METADATA
index f37723a..aa6b82f 100644
--- a/chrome/browser/policy/DIR_METADATA
+++ b/chrome/browser/policy/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Enterprise"
-}
+mixins: "//components/policy/COMMON_METADATA"
diff --git a/chrome/browser/portal/DIR_METADATA b/chrome/browser/portal/DIR_METADATA
index b437bcf..842d7f2 100644
--- a/chrome/browser/portal/DIR_METADATA
+++ b/chrome/browser/portal/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Blink>Portals"
-}
+mixins: "//third_party/blink/renderer/core/html/portal/COMMON_METADATA"
diff --git a/chrome/browser/predictors/COMMON_METADATA b/chrome/browser/predictors/COMMON_METADATA
new file mode 100644
index 0000000..eaf73c7
--- /dev/null
+++ b/chrome/browser/predictors/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "Internals>Preload"
+}
diff --git a/chrome/browser/predictors/DIR_METADATA b/chrome/browser/predictors/DIR_METADATA
index eaf73c7..79bed43 100644
--- a/chrome/browser/predictors/DIR_METADATA
+++ b/chrome/browser/predictors/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Preload"
-}
+mixins: "//chrome/browser/predictors/COMMON_METADATA"
diff --git a/chrome/browser/preferences/COMMON_METADATA b/chrome/browser/preferences/COMMON_METADATA
new file mode 100644
index 0000000..45d75af
--- /dev/null
+++ b/chrome/browser/preferences/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "Internals>Preferences"
+}
diff --git a/chrome/browser/preferences/DIR_METADATA b/chrome/browser/preferences/DIR_METADATA
index 45d75af..0f0f251 100644
--- a/chrome/browser/preferences/DIR_METADATA
+++ b/chrome/browser/preferences/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Preferences"
-}
+mixins: "//chrome/browser/preferences/COMMON_METADATA"
diff --git a/chrome/browser/prerender/DIR_METADATA b/chrome/browser/prerender/DIR_METADATA
new file mode 100644
index 0000000..1881f70
--- /dev/null
+++ b/chrome/browser/prerender/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/prerender/COMMON_METADATA"
diff --git a/chrome/browser/printing/DIR_METADATA b/chrome/browser/printing/DIR_METADATA
index ee7161a6..2413ed4 100644
--- a/chrome/browser/printing/DIR_METADATA
+++ b/chrome/browser/printing/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Printing"
-}
+mixins: "//printing/COMMON_METADATA"
diff --git a/chrome/browser/printing/cloud_print/DIR_METADATA b/chrome/browser/printing/cloud_print/DIR_METADATA
index 67273c4..66c1511 100644
--- a/chrome/browser/printing/cloud_print/DIR_METADATA
+++ b/chrome/browser/printing/cloud_print/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Services>CloudPrint"
-}
+mixins: "//cloud_print/COMMON_METADATA"
diff --git a/chrome/browser/privacy_budget/DIR_METADATA b/chrome/browser/privacy_budget/DIR_METADATA
index fe6ef77..6d362b2 100644
--- a/chrome/browser/privacy_budget/DIR_METADATA
+++ b/chrome/browser/privacy_budget/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Privacy>Fingerprinting"
-}
-team_email: "privacy-sandbox-dev@chromium.org"
+mixins: "//third_party/blink/public/common/privacy_budget/COMMON_METADATA"
diff --git a/chrome/browser/profiles/COMMON_METADATA b/chrome/browser/profiles/COMMON_METADATA
new file mode 100644
index 0000000..3c63e1a4
--- /dev/null
+++ b/chrome/browser/profiles/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "UI>Browser>Profiles"
+}
+team_email: "chrome-signin@chromium.org"
diff --git a/chrome/browser/profiles/DIR_METADATA b/chrome/browser/profiles/DIR_METADATA
index 3c63e1a4..3a626e1 100644
--- a/chrome/browser/profiles/DIR_METADATA
+++ b/chrome/browser/profiles/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>Profiles"
-}
-team_email: "chrome-signin@chromium.org"
+mixins: "//chrome/browser/profiles/COMMON_METADATA"
diff --git a/chrome/browser/profiles/android/DIR_METADATA b/chrome/browser/profiles/android/DIR_METADATA
index 04ba9fd..c69388e 100644
--- a/chrome/browser/profiles/android/DIR_METADATA
+++ b/chrome/browser/profiles/android/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/cookies/DIR_METADATA b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/cookies/DIR_METADATA
new file mode 100644
index 0000000..99fcdc2
--- /dev/null
+++ b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/cookies/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//net/cookies/COMMON_METADATA"
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 4e8d54ea..15515417 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -139,6 +139,7 @@
 #include "chrome/browser/browsing_data/chrome_browsing_data_lifetime_manager_factory.h"
 #include "chrome/browser/cart/cart_db_content.pb.h"
 #include "chrome/browser/cart/cart_service_factory.h"
+#include "chrome/browser/commerce/coupons/coupon_service_factory.h"
 #include "chrome/browser/feedback/feedback_uploader_factory_chrome.h"
 #include "chrome/browser/metrics/desktop_session_duration/desktop_profile_session_durations_service_factory.h"
 #include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_facade_factory.h"
@@ -310,6 +311,9 @@
 #endif
   ConsentAuditorFactory::GetInstance();
   CookieSettingsFactory::GetInstance();
+#if !defined(OS_ANDROID)
+  CouponServiceFactory::GetInstance();
+#endif
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
   DiceWebSigninInterceptorFactory::GetInstance();
 #endif
diff --git a/chrome/browser/push_messaging/DIR_METADATA b/chrome/browser/push_messaging/DIR_METADATA
index eb61d5d..a684b81 100644
--- a/chrome/browser/push_messaging/DIR_METADATA
+++ b/chrome/browser/push_messaging/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>PushAPI"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//content/browser/push_messaging/COMMON_METADATA"
diff --git a/chrome/browser/query_tiles/DIR_METADATA b/chrome/browser/query_tiles/DIR_METADATA
new file mode 100644
index 0000000..98d4b501
--- /dev/null
+++ b/chrome/browser/query_tiles/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/query_tiles/COMMON_METADATA"
diff --git a/chrome/browser/resource_coordinator/DIR_METADATA b/chrome/browser/resource_coordinator/DIR_METADATA
index 8b7461d..f87b987 100644
--- a/chrome/browser/resource_coordinator/DIR_METADATA
+++ b/chrome/browser/resource_coordinator/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>PerformanceManager"
-}
-team_email: "catan-team@chromium.org"
+mixins: "//services/resource_coordinator/COMMON_METADATA"
diff --git a/chrome/browser/resources/accessibility/DIR_METADATA b/chrome/browser/resources/accessibility/DIR_METADATA
index 32e94314..36b12b6 100644
--- a/chrome/browser/resources/accessibility/DIR_METADATA
+++ b/chrome/browser/resources/accessibility/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Accessibility"
-}
-team_email: "chromium-accessibility@chromium.org"
+mixins: "//ui/accessibility/COMMON_METADATA"
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox_manifest.json.jinja2 b/chrome/browser/resources/chromeos/accessibility/chromevox_manifest.json.jinja2
index 8dda133..9df4557d 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox_manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox_manifest.json.jinja2
@@ -66,7 +66,7 @@
     "48": "chromevox/images/chromevox-48.png",
     "128": "chromevox/images/chromevox-128.png"
   },
-  "content_security_policy": "default-src 'none'; script-src 'self' chrome://resources; style-src 'unsafe-inline' chrome://resources;",
+  "content_security_policy": "default-src 'none'; script-src 'self' 'wasm-eval' chrome://resources; style-src 'unsafe-inline' chrome://resources;",
   "externally_connectable": {
     "ids": [
       // Braille IME.
diff --git a/chrome/browser/resources/chromeos/edu_coexistence/DIR_METADATA b/chrome/browser/resources/chromeos/edu_coexistence/DIR_METADATA
index c0ebf85..b636a0e 100644
--- a/chrome/browser/resources/chromeos/edu_coexistence/DIR_METADATA
+++ b/chrome/browser/resources/chromeos/edu_coexistence/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "FamilyExperiences"
-}
\ No newline at end of file
+mixins: "//chrome/browser/ui/webui/chromeos/edu_coexistence/COMMON_METADATA"
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index 234800ea..03703a2 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -151,6 +151,9 @@
     "components/oobe_a11y_option.html",
     "components/oobe_a11y_option.js",
     "components/oobe_icons.html",
+    "components/display_manager_types.html",
+    "screens/common/fingerprint_setup.js",
+    "screens/common/fingerprint_setup.html",
     "screens/common/gesture_navigation.html",
     "screens/common/gesture_navigation.js",
     "screens/common/marketing_opt_in.html",
@@ -214,6 +217,7 @@
     "components/common_styles/oobe_dialog_host_styles.m.js",
     "components/common_styles/oobe_flex_layout_styles.m.js",
     "debug/debug.m.js",
+    "screens/common/fingerprint_setup.m.js",
     "screens/common/gesture_navigation.m.js",
     "screens/common/marketing_opt_in.m.js",
     "screens/login/active_directory_password_change.m.js",
@@ -282,7 +286,6 @@
     ":arc_terms_of_service",
     ":device_disabled",
     ":family_link_notice",
-    ":fingerprint_setup",
     ":gaia_buttons",
     ":gaia_header",
     ":gaia_input_form",
@@ -443,17 +446,6 @@
   ]
 }
 
-js_library("fingerprint_setup") {
-  deps = [
-    "components/behaviors:oobe_dialog_host_behavior",
-    "components/behaviors:oobe_i18n_behavior",
-    "components/buttons:oobe_text_button",
-    "components/dialogs:oobe_adaptive_dialog",
-    "//ui/webui/resources/cr_elements/cr_fingerprint:cr_fingerprint_progress_arc",
-    "//ui/webui/resources/cr_elements/cr_lottie:cr_lottie",
-  ]
-}
-
 js_library("gaia_buttons") {
 }
 
diff --git a/chrome/browser/resources/chromeos/login/app_downloading.html b/chrome/browser/resources/chromeos/login/app_downloading.html
index 1ef21c6..9363230 100644
--- a/chrome/browser/resources/chromeos/login/app_downloading.html
+++ b/chrome/browser/resources/chromeos/login/app_downloading.html
@@ -26,17 +26,11 @@
       }
     </style>
     <oobe-adaptive-dialog id="app-downloading-dialog" role="dialog"
-        aria-label$="[[getDialogTitleA11yString_(numOfApps)]]"
+        aria-label$="[[i18nDynamic(locale, 'appDownloadingScreenTitle')]]"
         no-footer-padding>
       <iron-icon src="chrome://oobe/playstore.svg" slot="icon">
       </iron-icon>
-      <h1 slot="title" id="title-singular" hidden="[[!singularTitleVisible_]]">
-        [[i18nDynamic(locale, 'appDownloadingScreenTitleSingular')]]
-      </h1>
-      <h1 slot="title" id="title-plural" hidden="[[!pluralTitleVisible_]]">
-        [[i18nDynamic(locale, 'appDownloadingScreenTitlePlural', numOfApps)]]
-      </h1>
-      <h1 slot="title" id="title" hidden="[[!newLayoutEnabled_]]">
+      <h1 slot="title" id="title">
         [[i18nDynamic(locale, 'appDownloadingScreenTitle')]]
       </h1>
       <div slot="subtitle">
diff --git a/chrome/browser/resources/chromeos/login/app_downloading.js b/chrome/browser/resources/chromeos/login/app_downloading.js
index 50f9f4e..0cab78e 100644
--- a/chrome/browser/resources/chromeos/login/app_downloading.js
+++ b/chrome/browser/resources/chromeos/login/app_downloading.js
@@ -12,38 +12,7 @@
 
   behaviors: [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior],
 
-  properties: {
-    numOfApps: Number,
-
-    /** Whether the user selected one app. */
-    hasSingleApp: {
-      type: Boolean,
-      computed: 'hasSingleApp_(numOfApps)',
-    },
-
-    /**
-     * Whether new OOBE layout is enabled.
-     *
-     * @type {boolean}
-     */
-    newLayoutEnabled_: {
-      type: Boolean,
-      value() {
-        return loadTimeData.valueExists('newLayoutEnabled') &&
-            loadTimeData.getBoolean('newLayoutEnabled');
-      }
-    },
-
-    pluralTitleVisible_: {
-      type: Boolean,
-      value: false,
-    },
-
-    singularTitleVisible_: {
-      type: Boolean,
-      value: false,
-    },
-  },
+  properties: {},
 
   ready() {
     this.initializeLoginScreen('AppDownloadingScreen', {
@@ -71,20 +40,15 @@
   },
 
   /** Called when dialog is shown */
-  onBeforeShow(data) {
-    this.numOfApps = data.numOfApps;
-    if (!this.newLayoutEnabled_) {
-      this.singularTitleVisible_ = this.hasSingleApp_(this.numOfApps);
-      this.pluralTitleVisible_ = !this.hasSingleApp_(this.numOfApps);
-    }
-    if (this.$.downloadingApps && this.newLayoutEnabled_) {
+  onBeforeShow() {
+    if (this.$.downloadingApps) {
       this.$.downloadingApps.setPlay(true);
     }
   },
 
   /** Called when dialog is hidden */
   onBeforeHide() {
-    if (this.$.downloadingApps && this.newLayoutEnabled_) {
+    if (this.$.downloadingApps) {
       this.$.downloadingApps.setPlay(false);
     }
   },
@@ -93,20 +57,4 @@
   onContinue_() {
     this.userActed('appDownloadingContinueSetup');
   },
-
-  /** @private */
-  hasSingleApp_(numOfApps) {
-    return numOfApps === 1;
-  },
-
-  /** @private */
-  getDialogTitleA11yString_(numOfApps) {
-    if (this.newLayoutEnabled_)
-      return this.i18n('appDownloadingScreenTitle');
-    if (this.hasSingleApp_(numOfApps)) {
-      return this.i18n('appDownloadingScreenTitleSingular');
-    } else {
-      return this.i18n('appDownloadingScreenTitlePlural', numOfApps);
-    }
-  },
 });
diff --git a/chrome/browser/resources/chromeos/login/components/buttons/oobe_next_button.html b/chrome/browser/resources/chromeos/login/components/buttons/oobe_next_button.html
index cb56043..dbbad2b 100644
--- a/chrome/browser/resources/chromeos/login/components/buttons/oobe_next_button.html
+++ b/chrome/browser/resources/chromeos/login/components/buttons/oobe_next_button.html
@@ -61,7 +61,7 @@
       }
       :host-context([dir=ltr]) iron-icon {
         padding-inline-start: var(--oobe-button-icon-margin);
-      }    <script src="oobe_back_button.js"></script>
+      }
       :host ::slotted(*),
       .fallback {
         font-family: var(--oobe-button-font-family);
diff --git a/chrome/browser/resources/chromeos/login/components/dialogs/oobe_loading_dialog.html b/chrome/browser/resources/chromeos/login/components/dialogs/oobe_loading_dialog.html
index 2ed2a2df..af9c6b4 100644
--- a/chrome/browser/resources/chromeos/login/components/dialogs/oobe_loading_dialog.html
+++ b/chrome/browser/resources/chromeos/login/components/dialogs/oobe_loading_dialog.html
@@ -19,32 +19,12 @@
 <dom-module id="oobe-loading-dialog">
   <template>
     <style include="oobe-dialog-host-styles">
-      paper-spinner-lite {
-        height: 38px;
-        margin-bottom: 28px;
-        width: 38px;
-      }
-
-      #comment {
-        color: #747474;
-      }
-
       #spinner {
         max-height: 286px;
         max-width: 286px;
       }
     </style>
-    <oobe-content-dialog id="dialogOld" role="dialog" no-footer-padding
-        no-buttons hidden="[[isNewLayout_]]">
-      <div slot="content" class="flex layout vertical center center-justified">
-        <paper-spinner-lite dir="ltr" active></paper-spinner-lite>
-        <div id="comment" aria-live="polite" class="focus-on-show"
-            aria-label$="[[i18nDynamic(locale, titleKey)]]">
-          [[i18nDynamic(locale, titleKey)]]
-        </div>
-      </div>
-    </oobe-content-dialog>
-    <oobe-adaptive-dialog id="dialog" role="dialog" hidden="[[!isNewLayout_]]">
+    <oobe-adaptive-dialog id="dialog" role="dialog">
       <slot slot="icon" name="icon"></slot>
       <h1 slot="title">[[i18nDynamic(locale, titleKey)]]</h1>
       <div slot="subtitle">[[localizeSubtitle_(locale, subtitleKey)]]</div>
diff --git a/chrome/browser/resources/chromeos/login/components/dialogs/oobe_loading_dialog.js b/chrome/browser/resources/chromeos/login/components/dialogs/oobe_loading_dialog.js
index a38522b..046febd 100644
--- a/chrome/browser/resources/chromeos/login/components/dialogs/oobe_loading_dialog.js
+++ b/chrome/browser/resources/chromeos/login/components/dialogs/oobe_loading_dialog.js
@@ -16,30 +16,14 @@
       type: String,
       value: '',
     },
-
-    isNewLayout_: {
-      type: Boolean,
-      value() {
-        return loadTimeData.valueExists('newLayoutEnabled') &&
-            loadTimeData.getBoolean('newLayoutEnabled');
-      },
-      readOnly: true,
-    }
   },
 
   onBeforeShow() {
-    if (this.isNewLayout_) {
-      this.$.dialog.onBeforeShow();
-      this.$.spinner.setPlay(true);
-    } else {
-      this.$.dialogOld.onBeforeShow();
-    }
+    this.$.spinner.setPlay(true);
   },
 
   onBeforeHide() {
-    if (this.isNewLayout_) {
-      this.$.spinner.setPlay(false);
-    }
+    this.$.spinner.setPlay(false);
   },
 
   /**
diff --git a/chrome/browser/resources/chromeos/login/components/display_manager_types.html b/chrome/browser/resources/chromeos/login/components/display_manager_types.html
new file mode 100644
index 0000000..3d865c31
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/components/display_manager_types.html
@@ -0,0 +1,9 @@
+<!-- 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. -->
+
+<!-- This is just a dummy file to assist with the Polymer3 migration.
+     Adding this file as an import will force the Polymer3 version of
+     the file to add the directive:
+     - `import {OOBE_UI_STATE} from '.../display_manager_types.m.js';`
+-->
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/login/fingerprint_setup.html b/chrome/browser/resources/chromeos/login/fingerprint_setup.html
deleted file mode 100644
index ad67f77..0000000
--- a/chrome/browser/resources/chromeos/login/fingerprint_setup.html
+++ /dev/null
@@ -1,129 +0,0 @@
-<!-- Copyright 2018 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_lottie/cr_lottie.html">
-
-<link rel="import" href="/components/oobe_icons.html">
-<link rel="import" href="/components/behaviors/login_screen_behavior.html">
-<link rel="import" href="/components/behaviors/multi_step_behavior.html">
-<link rel="import" href="/components/behaviors/oobe_dialog_host_behavior.html">
-<link rel="import" href="/components/behaviors/oobe_i18n_behavior.html">
-<link rel="import" href="/components/buttons/oobe_text_button.html">
-<link rel="import" href="/components/common_styles/common_styles.html">
-<link rel="import" href="/components/common_styles/oobe_dialog_host_styles.html">
-<link rel="import" href="/components/dialogs/oobe_adaptive_dialog.html">
-
-
-<dom-module id="fingerprint-setup-element">
-  <template>
-    <style include="oobe-dialog-host-styles">
-      #sensorLocationContainer {
-        height: 242px;
-        width: 352px;
-      }
-
-      #sensorLocation {
-        background-image:
-            url(chrome://oobe/fingerprint_scanner_illustration.svg);
-        background-size: 352px 242px;
-        height: 100%;
-        width: 100%;
-      }
-    </style>
-    <oobe-adaptive-dialog id="setupFingerprint" role="dialog" for-step="start"
-        footer-shrinkable
-        aria-label$="[[i18nDynamic(locale, 'setupFingerprintScreenAriaLabel')]]">
-      <h1 slot="title" hidden="[[isChildAccount_]]">
-        [[i18nDynamic(locale, 'setupFingerprintScreenTitle')]]
-      </h1>
-      <h1 slot="title" hidden="[[!isChildAccount_]]">
-        [[i18nDynamic(locale, 'setupFingerprintScreenTitleForChild')]]
-      </h1>
-      <p slot="subtitle" hidden="[[isChildAccount_]]">
-        [[i18nDynamic(locale, 'setupFingerprintScreenDescription')]]
-      </p>
-      <p slot="subtitle" hidden="[[!isChildAccount_]]">
-        [[i18nDynamic(locale, 'setupFingerprintScreenDescriptionForChild')]]
-      </p>
-      <iron-icon slot="icon" icon="oobe-32:fingerprint"></iron-icon>
-      <div slot="content" class="flex layout vertical center center-justified">
-        <div id="sensorLocationContainer" class="oobe-illustration">
-          <template is="dom-if" if="[[shouldUseLottieAnimation_]]">
-            <cr-lottie id="scannerLocationLottie"
-                animation-url="fingerprint_scanner_animation.json">
-            </cr-lottie>
-          </template>
-          <template is="dom-if" if="[[!shouldUseLottieAnimation_]]">
-            <div id="sensorLocation"></div>
-          </template>
-        </div>
-      </div>
-      <div slot="bottom-buttons">
-        <oobe-text-button id="skipStart"
-            text-key="skipFingerprintSetup"
-            on-click="onSkipOnStart_" class="focus-on-show">
-        </oobe-text-button>
-      </div>
-    </oobe-adaptive-dialog>
-    <oobe-adaptive-dialog id="startFingerprintEnroll" role="dialog" for-step="progress"
-        footer-shrinkable
-        aria-label$="[[i18nDynamic(locale, 'enrollmentProgressScreenTitle')]]">
-      <iron-icon slot="icon" icon="oobe-32:fingerprint"></iron-icon>
-      <h1 slot="title" hidden="[[complete_]]">
-        [[i18nDynamic(locale, 'enrollmentProgressScreenTitle')]]
-      </h1>
-      <h1 slot="title" hidden="[[!complete_]]">
-        [[i18nDynamic(locale, 'setupFingerprintEnrollmentSuccessTitle')]]
-      </h1>
-      <div slot="subtitle" hidden="[[!complete_]]">
-        <div hidden="[[isChildAccount_]]">
-          [[i18nDynamic(locale,
-              'setupFingerprintEnrollmentSuccessDescription')]]
-        </div>
-        <div hidden="[[!isChildAccount_]]">
-          [[i18nDynamic(locale,
-              'setupFingerprintEnrollmentSuccessDescriptionForChild')]]
-        </div>
-      </div>
-      <div slot="subtitle" hidden="[[!isProblemImmobile_(scanResult_)]]">
-        <div hidden="[[isChildAccount_]]">
-          [[i18nDynamic(locale, 'setupFingerprintScanMoveFinger')]]
-        </div>
-        <div hidden="[[!isChildAccount_]]">
-          [[i18nDynamic(locale, 'setupFingerprintScanMoveFingerForChild')]]
-        </div>
-      </div>
-      <div slot="subtitle" hidden="[[!isProblemOther_(scanResult_)]]">
-        [[i18nDynamic(locale, 'setupFingerprintScanTryAgain')]]
-      </div>
-      <div slot="content" class="flex layout vertical center center-justified">
-        <cr-fingerprint-progress-arc id="arc">
-        </cr-fingerprint-progress-arc>
-      </div>
-      <div slot="bottom-buttons">
-        <oobe-text-button id="skipProgress"
-            on-click="onSkipInProgress_" class="focus-on-show"
-            text-key="skipFingerprintSetup"
-            hidden="[[complete_]]">
-        </oobe-text-button>
-        <oobe-text-button id="addAnotherFinger"
-            text-key="fingerprintSetupAddAnother"
-            hidden="[[!isAnotherButtonVisible_(percentComplete_,
-                canAddFinger)]]"
-            on-click="onAddAnother_">
-        </oobe-text-button>
-        <oobe-text-button id="done"
-            hidden="[[!complete_]]"
-            text-key="fingerprintSetupDone"
-            on-click="onDone_" class="focus-on-show" inverse>
-        </oobe-text-button>
-      </div>
-    </oobe-adaptive-dialog>
-  </template>
-</dom-module>
diff --git a/chrome/browser/resources/chromeos/login/fingerprint_setup.js b/chrome/browser/resources/chromeos/login/fingerprint_setup.js
deleted file mode 100644
index 8a036a9..0000000
--- a/chrome/browser/resources/chromeos/login/fingerprint_setup.js
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Polymer element for displaying material design Fingerprint
- * Enrollment screen.
- */
-
-'use strict';
-
-(function() {
-
-/**
- * These values must be kept in sync with the values in
- * third_party/cros_system_api/dbus/service_constants.h.
- * @enum {number}
- */
-var FingerprintResultType = {
-  SUCCESS: 0,
-  PARTIAL: 1,
-  INSUFFICIENT: 2,
-  SENSOR_DIRTY: 3,
-  TOO_SLOW: 4,
-  TOO_FAST: 5,
-  IMMOBILE: 6,
-};
-
-/**
- * UI mode for the dialog.
- * @enum {string}
- */
-const UIState = {
-  START: 'start',
-  PROGRESS: 'progress',
-};
-
-Polymer({
-  is: 'fingerprint-setup-element',
-
-  behaviors: [
-    OobeI18nBehavior,
-    OobeDialogHostBehavior,
-    LoginScreenBehavior,
-    MultiStepBehavior,
-  ],
-
-  EXTERNAL_API: [
-    'onEnrollScanDone',
-    'enableAddAnotherFinger',
-  ],
-
-  UI_STEPS: UIState,
-
-  properties: {
-    /**
-     * The percentage of completion that has been received during setup.
-     * The value within [0, 100] represents the percent of enrollment
-     * completion.
-     * @type {number}
-     */
-    percentComplete_: {
-      type: Number,
-      value: 0,
-      observer: 'onProgressChanged_',
-    },
-
-    /**
-     * Is current finger enrollment complete?
-     * @type {boolean}
-     */
-    complete_: {
-      type: Boolean,
-      value: false,
-      computed: 'enrollIsComplete_(percentComplete_)',
-    },
-
-    /**
-     * Can we add another finger?
-     * @type {boolean}
-     */
-    canAddFinger: {
-      type: Boolean,
-      value: true,
-    },
-
-    /**
-     * The result of fingerprint enrollment scan.
-     * @type {FingerprintResultType}
-     * @private
-     */
-    scanResult_: {
-      type: Number,
-      value: FingerprintResultType.SUCCESS,
-    },
-
-    /**
-     * True if lottie animation file should be used instead of an illustration.
-     * @type {boolean}
-     * @private
-     */
-    shouldUseLottieAnimation_: {
-      type: Boolean,
-      value() {
-        return loadTimeData.getBoolean('useLottieAnimationForFingerprint');
-      },
-      readOnly: true,
-    },
-
-    /**
-     * Indicates whether user is a child account.
-     * @type {boolean}
-     */
-    isChildAccount_: {
-      type: Boolean,
-      value: false,
-    },
-  },
-
-  ready() {
-    this.initializeLoginScreen('FingerprintSetupScreen', {
-      resetAllowed: false,
-    });
-  },
-
-  /** Initial UI State for screen */
-  getOobeUIInitialState() {
-    return OOBE_UI_STATE.ONBOARDING;
-  },
-
-  defaultUIStep() {
-    return UIState.START;
-  },
-
-  onBeforeShow(data) {
-    this.isChildAccount_ = data['isChildAccount'];
-    this.setAnimationState_(true);
-  },
-
-  onBeforeHide() {
-    this.setAnimationState_(false);
-  },
-
-  /**
-   * Called when a fingerprint enroll scan result is received.
-   * @param {FingerprintResultType} scanResult Result of the enroll scan.
-   * @param {boolean} isComplete Whether fingerprint enrollment is complete.
-   * @param {number} percentComplete Percentage of completion of the enrollment.
-   */
-  onEnrollScanDone(scanResult, isComplete, percentComplete) {
-    this.setUIStep(UIState.PROGRESS);
-
-    this.percentComplete_ = percentComplete;
-    this.scanResult_ = scanResult;
-  },
-
-  /**
-   * Enable/disable add another finger.
-   * @param {boolean} enable True if add another fingerprint is enabled.
-   */
-  enableAddAnotherFinger(enable) {
-    this.canAddFinger = enable;
-  },
-
-  /**
-   * Check whether Add Another button should be shown.
-   * @return {boolean}
-   * @private
-   */
-  isAnotherButtonVisible_(percentComplete, canAddFinger) {
-    return percentComplete >= 100 && canAddFinger;
-  },
-
-  /**
-   * This is 'on-tap' event handler for 'Skip' button for 'START' step.
-   * @private
-   */
-  onSkipOnStart_(e) {
-    this.userActed('setup-skipped-on-start');
-  },
-
-  /**
-   * This is 'on-tap' event handler for 'Skip' button for 'PROGRESS' step.
-   * @private
-   */
-  onSkipInProgress_(e) {
-    this.userActed('setup-skipped-in-flow');
-  },
-
-  /**
-   * Enable/disable lottie animation.
-   * @param {boolean} playing True if animation should be playing.
-   */
-  setAnimationState_(playing) {
-    if (this.shouldUseLottieAnimation_) {
-      const lottieElement = /** @type{CrLottieElement} */ (
-          this.$.setupFingerprint.querySelector('#scannerLocationLottie'));
-      lottieElement.setPlay(playing);
-      /** @type {!CrFingerprintProgressArcElement} */ (this.$.arc)
-          .setPlay(playing);
-    }
-  },
-
-  /**
-   * This is 'on-tap' event handler for 'Done' button.
-   * @private
-   */
-  onDone_(e) {
-    this.userActed('setup-done');
-  },
-
-  /**
-   * This is 'on-tap' event handler for 'Add another' button.
-   * @private
-   */
-  onAddAnother_(e) {
-    this.percentComplete_ = 0;
-    this.userActed('add-another-finger');
-  },
-
-  /**
-   * Check whether fingerprint enrollment is in progress.
-   * @return {boolean}
-   * @private
-   */
-  enrollIsComplete_(percent) {
-    return percent >= 100;
-  },
-
-  /**
-   * Check whether fingerprint scan problem is IMMOBILE.
-   * @return {boolean}
-   * @private
-   */
-  isProblemImmobile_(scan_result) {
-    return scan_result === FingerprintResultType.IMMOBILE;
-  },
-
-  /**
-   * Check whether fingerprint scan problem is other than IMMOBILE.
-   * @return {boolean}
-   * @private
-   */
-  isProblemOther_(scan_result) {
-    return scan_result != FingerprintResultType.SUCCESS &&
-        scan_result != FingerprintResultType.IMMOBILE;
-  },
-
-  /**
-   * Observer for percentComplete_.
-   * @private
-   */
-  onProgressChanged_(newValue, oldValue) {
-    // Start a new enrollment, so reset all enrollment related states.
-    if (newValue === 0) {
-      /** @type {!CrFingerprintProgressArcElement} */ (this.$.arc).reset();
-      this.scanResult_ = FingerprintResultType.SUCCESS;
-      return;
-    }
-
-    /** @type {!CrFingerprintProgressArcElement} */ (this.$.arc)
-        .setProgress(oldValue, newValue, newValue === 100);
-  },
-});
-})();
diff --git a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
index b9660ba5..78a7001 100644
--- a/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
+++ b/chrome/browser/resources/chromeos/login/oobe_auto_imports.gni
@@ -33,16 +33,17 @@
 #
 
 oobe_auto_imports = [
-     "chrome/browser/resources/chromeos/login/components/behaviors/oobe_i18n_behavior.html|OobeI18nBehavior,OobeI18nBehaviorInterface",
-     "chrome/browser/resources/chromeos/login/components/behaviors/oobe_dialog_host_behavior.html|OobeDialogHostBehavior",
-     "chrome/browser/resources/chromeos/login/components/behaviors/oobe_focus_behavior.html|OobeFocusBehavior",
-     "chrome/browser/resources/chromeos/login/components/behaviors/oobe_scrollable_behavior.html|OobeScrollableBehavior",
-     "chrome/browser/resources/chromeos/login/components/behaviors/login_screen_behavior.html|LoginScreenBehavior,LoginScreenBehaviorInterface",
-     "chrome/browser/resources/chromeos/login/components/behaviors/multi_step_behavior.html|MultiStepBehavior,MultiStepBehaviorInterface",
-     "ui/webui/resources/html/polymer.html|afterNextRender,Polymer,PolymerElement,html,flush,mixinBehaviors",
+  "chrome/browser/resources/chromeos/login/components/behaviors/oobe_i18n_behavior.html|OobeI18nBehavior,OobeI18nBehaviorInterface",
+  "chrome/browser/resources/chromeos/login/components/behaviors/oobe_dialog_host_behavior.html|OobeDialogHostBehavior",
+  "chrome/browser/resources/chromeos/login/components/behaviors/oobe_focus_behavior.html|OobeFocusBehavior",
+  "chrome/browser/resources/chromeos/login/components/behaviors/oobe_scrollable_behavior.html|OobeScrollableBehavior",
+  "chrome/browser/resources/chromeos/login/components/behaviors/login_screen_behavior.html|LoginScreenBehavior,LoginScreenBehaviorInterface",
+  "chrome/browser/resources/chromeos/login/components/behaviors/multi_step_behavior.html|MultiStepBehavior,MultiStepBehaviorInterface",
+  "chrome/browser/resources/chromeos/login/components/display_manager_types.html|OOBE_UI_STATE",
+  "ui/webui/resources/html/polymer.html|afterNextRender,Polymer,PolymerElement,html,flush,mixinBehaviors",
 ]
 
 oobe_namespace_rewrites = [
-     "Polymer.mixinBehaviors|mixinBehaviors",
-     "Polymer.Element|PolymerElement",
+  "Polymer.mixinBehaviors|mixinBehaviors",
+  "Polymer.Element|PolymerElement",
 ]
diff --git a/chrome/browser/resources/chromeos/login/oobe_polymer3.html b/chrome/browser/resources/chromeos/login/oobe_polymer3.html
index 82c53bb8..49007e5 100644
--- a/chrome/browser/resources/chromeos/login/oobe_polymer3.html
+++ b/chrome/browser/resources/chromeos/login/oobe_polymer3.html
@@ -29,6 +29,8 @@
         <div id="inner-container" class="down">
           <hid-detection-element id="hid-detection" class="step hidden" hidden>
           </hid-detection-element>
+          <fingerprint-setup-element id="fingerprint-setup" class="step hidden" hidden>
+          </fingerprint-setup-element>
           <gesture-navigation-element id="gesture-navigation" class="step hidden" hidden>
           </gesture-navigation-element>
           <marketing-opt-in-element id="marketing-opt-in" class="step hidden" hidden>
diff --git a/chrome/browser/resources/chromeos/login/oobe_polymer3.js b/chrome/browser/resources/chromeos/login/oobe_polymer3.js
index 663f62d4..05f69f4 100644
--- a/chrome/browser/resources/chromeos/login/oobe_polymer3.js
+++ b/chrome/browser/resources/chromeos/login/oobe_polymer3.js
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'chrome://oobe/screens/common/fingerprint_setup.m.js';
 import 'chrome://oobe/screens/common/gesture_navigation.m.js';
 import 'chrome://oobe/screens/common/marketing_opt_in.m.js';
 import 'chrome://oobe/screens/login/active_directory_password_change.m.js';
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
index eeb217c..a708b79 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -1178,26 +1178,5 @@
   clickPrimaryButtonForTesting() {
     this.$['signin-frame-dialog'].clickPrimaryButtonForTesting();
   },
-
-  /**
-   * Whether new OOBE layout is enabled.
-   */
-  newLayoutEnabled_() {
-    return loadTimeData.valueExists('newLayoutEnabled') &&
-        loadTimeData.getBoolean('newLayoutEnabled');
-  },
-
-  /**
-   * Called when focus is returned.
-   * @param {boolean} reverse Is focus returned in reverse order?
-   */
-  onFocusReturned(reverse) {
-    // We need to explicitly adjust focus inside the webview part when focus is
-    // returned from the system tray in regular order. Because the webview is
-    // the first focusable element of the screen and we want to eliminate extra
-    // tab. Reverse tab doesn't need any adjustments here.
-    if (!this.newLayoutEnabled_() && !reverse)
-      this.focusActiveFrame_();
-  },
 });
 })();
diff --git a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
index 7330c5fd..587d3ca 100644
--- a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
@@ -12,6 +12,7 @@
 
 group("polymer3_elements") {
   public_deps = [
+    ":fingerprint_setup_module",
     ":gesture_navigation_module",
     ":marketing_opt_in_module",
   ]
@@ -33,6 +34,7 @@
   is_polymer3 = true
   closure_flags = default_closure_args
   deps = [
+    ":fingerprint_setup.m",
     ":gesture_navigation.m",
     ":marketing_opt_in.m",
   ]
@@ -52,10 +54,26 @@
   ]
 }
 
+js_library("fingerprint_setup.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/common/fingerprint_setup.m.js" ]
+  deps = [
+    "../../components:display_manager_types.m",
+    "../../components/behaviors:login_screen_behavior.m",
+    "../../components/behaviors:multi_step_behavior.m",
+    "../../components/behaviors:oobe_i18n_behavior.m",
+    "../../components/buttons:oobe_text_button.m",
+    "../../components/dialogs:oobe_adaptive_dialog.m",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/cr_elements/cr_fingerprint:cr_fingerprint_progress_arc.m",
+    "//ui/webui/resources/cr_elements/cr_lottie:cr_lottie.m",
+    "//ui/webui/resources/js:load_time_data.m",
+  ]
+  extra_deps = [ ":fingerprint_setup_module" ]
+}
+
 js_library("gesture_navigation.m") {
   sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/common/gesture_navigation.m.js" ]
   deps = [
-    "//ui/webui/resources/js:cr.m",
     "../../components/behaviors:login_screen_behavior.m",
     "../../components/behaviors:multi_step_behavior.m",
     "../../components/behaviors:oobe_i18n_behavior.m",
@@ -63,6 +81,7 @@
     "../../components/buttons:oobe_next_button.m",
     "../../components/buttons:oobe_text_button.m",
     "../../components/dialogs:oobe_adaptive_dialog.m",
+    "//ui/webui/resources/js:cr.m",
   ]
   extra_deps = [ ":gesture_navigation_module" ]
 }
@@ -80,6 +99,14 @@
   extra_deps = [ ":marketing_opt_in_module" ]
 }
 
+polymer_modulizer("fingerprint_setup") {
+  js_file = "fingerprint_setup.js"
+  html_file = "fingerprint_setup.html"
+  html_type = "dom-module"
+  auto_imports = oobe_auto_imports
+  namespace_rewrites = oobe_namespace_rewrites
+}
+
 polymer_modulizer("gesture_navigation") {
   js_file = "gesture_navigation.js"
   html_file = "gesture_navigation.html"
diff --git a/chrome/browser/resources/chromeos/login/screens/common/fingerprint_setup.html b/chrome/browser/resources/chromeos/login/screens/common/fingerprint_setup.html
new file mode 100644
index 0000000..61be8984
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/screens/common/fingerprint_setup.html
@@ -0,0 +1,130 @@
+<!-- Copyright 2018 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/html/load_time_data.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_lottie/cr_lottie.html">
+
+<link rel="import" href="../../components/oobe_icons.html">
+<link rel="import" href="../../components/behaviors/login_screen_behavior.html">
+<link rel="import" href="../../components/behaviors/multi_step_behavior.html">
+<link rel="import" href="../../components/behaviors/oobe_i18n_behavior.html">
+<link rel="import" href="../../components/buttons/oobe_text_button.html">
+<link rel="import" href="../../components/common_styles/common_styles.html">
+<link rel="import" href="../../components/common_styles/oobe_dialog_host_styles.html">
+<link rel="import" href="../../components/dialogs/oobe_adaptive_dialog.html">
+<link rel="import" href="../../components/display_manager_types.html">
+
+<dom-module id="fingerprint-setup-element">
+  <template>
+    <style include="oobe-dialog-host-styles">
+      #sensorLocationContainer {
+        height: 242px;
+        width: 352px;
+      }
+
+      #sensorLocation {
+        background-image:
+            url(chrome://oobe/fingerprint_scanner_illustration.svg);
+        background-size: 352px 242px;
+        height: 100%;
+        width: 100%;
+      }
+    </style>
+    <oobe-adaptive-dialog id="setupFingerprint" role="dialog" for-step="start"
+        footer-shrinkable
+        aria-label$="[[i18nDynamic(locale, 'setupFingerprintScreenAriaLabel')]]">
+      <h1 slot="title" hidden="[[isChildAccount_]]">
+        [[i18nDynamic(locale, 'setupFingerprintScreenTitle')]]
+      </h1>
+      <h1 slot="title" hidden="[[!isChildAccount_]]">
+        [[i18nDynamic(locale, 'setupFingerprintScreenTitleForChild')]]
+      </h1>
+      <p slot="subtitle" hidden="[[isChildAccount_]]">
+        [[i18nDynamic(locale, 'setupFingerprintScreenDescription')]]
+      </p>
+      <p slot="subtitle" hidden="[[!isChildAccount_]]">
+        [[i18nDynamic(locale, 'setupFingerprintScreenDescriptionForChild')]]
+      </p>
+      <iron-icon slot="icon" icon="oobe-32:fingerprint"></iron-icon>
+      <div slot="content" class="flex layout vertical center center-justified">
+        <div id="sensorLocationContainer" class="oobe-illustration">
+          <template is="dom-if" if="[[shouldUseLottieAnimation_]]">
+            <cr-lottie id="scannerLocationLottie"
+                animation-url="fingerprint_scanner_animation.json">
+            </cr-lottie>
+          </template>
+          <template is="dom-if" if="[[!shouldUseLottieAnimation_]]">
+            <div id="sensorLocation"></div>
+          </template>
+        </div>
+      </div>
+      <div slot="bottom-buttons">
+        <oobe-text-button id="skipStart"
+            text-key="skipFingerprintSetup"
+            on-click="onSkipOnStart_" class="focus-on-show">
+        </oobe-text-button>
+      </div>
+    </oobe-adaptive-dialog>
+    <oobe-adaptive-dialog id="startFingerprintEnroll" role="dialog"
+        for-step="progress" footer-shrinkable
+        aria-label$="[[i18nDynamic(locale, 'enrollmentProgressScreenTitle')]]">
+      <iron-icon slot="icon" icon="oobe-32:fingerprint"></iron-icon>
+      <h1 slot="title" hidden="[[complete_]]">
+        [[i18nDynamic(locale, 'enrollmentProgressScreenTitle')]]
+      </h1>
+      <h1 slot="title" hidden="[[!complete_]]">
+        [[i18nDynamic(locale, 'setupFingerprintEnrollmentSuccessTitle')]]
+      </h1>
+      <div slot="subtitle" hidden="[[!complete_]]">
+        <div hidden="[[isChildAccount_]]">
+          [[i18nDynamic(locale,
+              'setupFingerprintEnrollmentSuccessDescription')]]
+        </div>
+        <div hidden="[[!isChildAccount_]]">
+          [[i18nDynamic(locale,
+              'setupFingerprintEnrollmentSuccessDescriptionForChild')]]
+        </div>
+      </div>
+      <div slot="subtitle" hidden="[[!isProblemImmobile_(scanResult_)]]">
+        <div hidden="[[isChildAccount_]]">
+          [[i18nDynamic(locale, 'setupFingerprintScanMoveFinger')]]
+        </div>
+        <div hidden="[[!isChildAccount_]]">
+          [[i18nDynamic(locale, 'setupFingerprintScanMoveFingerForChild')]]
+        </div>
+      </div>
+      <div slot="subtitle" hidden="[[!isProblemOther_(scanResult_)]]">
+        [[i18nDynamic(locale, 'setupFingerprintScanTryAgain')]]
+      </div>
+      <div slot="content" class="flex layout vertical center center-justified">
+        <cr-fingerprint-progress-arc id="arc">
+        </cr-fingerprint-progress-arc>
+      </div>
+      <div slot="bottom-buttons">
+        <oobe-text-button id="skipProgress"
+            on-click="onSkipInProgress_" class="focus-on-show"
+            text-key="skipFingerprintSetup"
+            hidden="[[complete_]]">
+        </oobe-text-button>
+        <oobe-text-button id="addAnotherFinger"
+            text-key="fingerprintSetupAddAnother"
+            hidden="[[!isAnotherButtonVisible_(percentComplete_,
+                canAddFinger)]]"
+            on-click="onAddAnother_">
+        </oobe-text-button>
+        <oobe-text-button id="done"
+            hidden="[[!complete_]]"
+            text-key="fingerprintSetupDone"
+            on-click="onDone_" class="focus-on-show" inverse>
+        </oobe-text-button>
+      </div>
+    </oobe-adaptive-dialog>
+  </template>
+  <script src="fingerprint_setup.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/chromeos/login/screens/common/fingerprint_setup.js b/chrome/browser/resources/chromeos/login/screens/common/fingerprint_setup.js
new file mode 100644
index 0000000..5c19f4d5
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/screens/common/fingerprint_setup.js
@@ -0,0 +1,274 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Polymer element for displaying material design Fingerprint
+ * Enrollment screen.
+ */
+
+/* #js_imports_placeholder */
+
+/**
+ * These values must be kept in sync with the values in
+ * third_party/cros_system_api/dbus/service_constants.h.
+ * @enum {number}
+ */
+var FingerprintResultType = {
+  SUCCESS: 0,
+  PARTIAL: 1,
+  INSUFFICIENT: 2,
+  SENSOR_DIRTY: 3,
+  TOO_SLOW: 4,
+  TOO_FAST: 5,
+  IMMOBILE: 6,
+};
+
+/**
+ * UI mode for the dialog.
+ * @enum {string}
+ */
+const FingerprintUIState = {
+  START: 'start',
+  PROGRESS: 'progress',
+};
+
+/**
+ * @constructor
+ * @extends {PolymerElement}
+ * @implements {LoginScreenBehaviorInterface}
+ * @implements {OobeI18nBehaviorInterface}
+ * @implements {MultiStepBehaviorInterface}
+ */
+const FingerprintSetupBase = Polymer.mixinBehaviors(
+    [OobeI18nBehavior, MultiStepBehavior, LoginScreenBehavior],
+    Polymer.Element);
+
+class FingerprintSetup extends FingerprintSetupBase {
+  static get is() {
+    return 'fingerprint-setup-element';
+  }
+
+  /* #html_template_placeholder */
+
+  static get properties() {
+    return {
+      /**
+       * The percentage of completion that has been received during setup.
+       * The value within [0, 100] represents the percent of enrollment
+       * completion.
+       */
+      percentComplete_: {
+        type: Number,
+        observer: 'onProgressChanged_',
+      },
+
+      /**
+       * Is current finger enrollment complete?
+       */
+      complete_: {
+        type: Boolean,
+        computed: 'enrollIsComplete_(percentComplete_)',
+      },
+
+      /**
+       * Can we add another finger?
+       */
+      canAddFinger: {
+        type: Boolean,
+      },
+
+      /**
+       * The result of fingerprint enrollment scan.
+       * @private
+       */
+      scanResult_: {
+        type: Number,
+      },
+
+      /**
+       * True if lottie animation file should be used instead of an
+       * illustration.
+       * @private
+       */
+      shouldUseLottieAnimation_: {
+        type: Boolean,
+      },
+
+      /**
+       * Indicates whether user is a child account.
+       */
+      isChildAccount_: {
+        type: Boolean,
+      }
+    };
+  }
+
+  constructor() {
+    super();
+    this.UI_STEPS = FingerprintUIState;
+    this.percentComplete_ = 0;
+    this.complete_ = false;
+    this.canAddFinger = true;
+    this.scanResult_ = FingerprintResultType.SUCCESS;
+    this.shouldUseLottieAnimation_ =
+        loadTimeData.getBoolean('useLottieAnimationForFingerprint');
+    this.isChildAccount_ = false;
+  }
+
+  /** @override */
+  get EXTERNAL_API() {
+    return ['onEnrollScanDone', 'enableAddAnotherFinger'];
+  }
+
+  /** @override */
+  ready() {
+    super.ready();
+    this.initializeLoginScreen('FingerprintSetupScreen', {
+      resetAllowed: false,
+    });
+  }
+
+  /** Initial UI State for screen */
+  getOobeUIInitialState() {
+    return OOBE_UI_STATE.ONBOARDING;
+  }
+
+  /** @override */
+  defaultUIStep() {
+    return FingerprintUIState.START;
+  }
+
+  onBeforeShow(data) {
+    this.isChildAccount_ = data['isChildAccount'];
+    this.setAnimationState_(true);
+  }
+
+  onBeforeHide() {
+    this.setAnimationState_(false);
+  }
+
+  /**
+   * Called when a fingerprint enroll scan result is received.
+   * @param {FingerprintResultType} scanResult Result of the enroll scan.
+   * @param {boolean} isComplete Whether fingerprint enrollment is complete.
+   * @param {number} percentComplete Percentage of completion of the enrollment.
+   */
+  onEnrollScanDone(scanResult, isComplete, percentComplete) {
+    this.setUIStep(FingerprintUIState.PROGRESS);
+
+    this.percentComplete_ = percentComplete;
+    this.scanResult_ = scanResult;
+  }
+
+  /**
+   * Enable/disable add another finger.
+   * @param {boolean} enable True if add another fingerprint is enabled.
+   */
+  enableAddAnotherFinger(enable) {
+    this.canAddFinger = enable;
+  }
+
+  /**
+   * Check whether Add Another button should be shown.
+   * @return {boolean}
+   * @private
+   */
+  isAnotherButtonVisible_(percentComplete, canAddFinger) {
+    return percentComplete >= 100 && canAddFinger;
+  }
+
+  /**
+   * This is 'on-tap' event handler for 'Skip' button for 'START' step.
+   * @private
+   */
+  onSkipOnStart_(e) {
+    this.userActed('setup-skipped-on-start');
+  }
+
+  /**
+   * This is 'on-tap' event handler for 'Skip' button for 'PROGRESS' step.
+   * @private
+   */
+  onSkipInProgress_(e) {
+    this.userActed('setup-skipped-in-flow');
+  }
+
+  /**
+   * Enable/disable lottie animation.
+   * @param {boolean} playing True if animation should be playing.
+   * @suppress {missingProperties}
+   */
+  setAnimationState_(playing) {
+    if (this.shouldUseLottieAnimation_) {
+      const lottieElement = /** @type{CrLottieElement} */ (
+          this.$.setupFingerprint.querySelector('#scannerLocationLottie'));
+      lottieElement.setPlay(playing);
+      /** @type {!CrFingerprintProgressArcElement} */ (this.$.arc)
+          .setPlay(playing);
+    }
+  }
+
+  /**
+   * This is 'on-tap' event handler for 'Done' button.
+   * @private
+   */
+  onDone_(e) {
+    this.userActed('setup-done');
+  }
+
+  /**
+   * This is 'on-tap' event handler for 'Add another' button.
+   * @private
+   */
+  onAddAnother_(e) {
+    this.percentComplete_ = 0;
+    this.userActed('add-another-finger');
+  }
+
+  /**
+   * Check whether fingerprint enrollment is in progress.
+   * @return {boolean}
+   * @private
+   */
+  enrollIsComplete_(percent) {
+    return percent >= 100;
+  }
+
+  /**
+   * Check whether fingerprint scan problem is IMMOBILE.
+   * @return {boolean}
+   * @private
+   */
+  isProblemImmobile_(scan_result) {
+    return scan_result === FingerprintResultType.IMMOBILE;
+  }
+
+  /**
+   * Check whether fingerprint scan problem is other than IMMOBILE.
+   * @return {boolean}
+   * @private
+   */
+  isProblemOther_(scan_result) {
+    return scan_result != FingerprintResultType.SUCCESS &&
+        scan_result != FingerprintResultType.IMMOBILE;
+  }
+
+  /**
+   * Observer for percentComplete_.
+   * @private
+   */
+  onProgressChanged_(newValue, oldValue) {
+    // Start a new enrollment, so reset all enrollment related states.
+    if (newValue === 0) {
+      /** @type {!CrFingerprintProgressArcElement} */ (this.$.arc).reset();
+      this.scanResult_ = FingerprintResultType.SUCCESS;
+      return;
+    }
+
+    /** @type {!CrFingerprintProgressArcElement} */ (this.$.arc)
+        .setProgress(oldValue, newValue, newValue === 100);
+  }
+}
+
+customElements.define(FingerprintSetup.is, FingerprintSetup);
diff --git a/chrome/browser/resources/chromeos/login/screens/oobe/oobe_eula.js b/chrome/browser/resources/chromeos/login/screens/oobe/oobe_eula.js
index a93bedf..628acb4 100644
--- a/chrome/browser/resources/chromeos/login/screens/oobe/oobe_eula.js
+++ b/chrome/browser/resources/chromeos/login/screens/oobe/oobe_eula.js
@@ -504,27 +504,5 @@
   setUsageStats(checked) {
     this.usageStatsChecked = checked;
   },
-
-  /**
-   * Whether new OOBE layout is enabled.
-   */
-  newLayoutEnabled_() {
-    return loadTimeData.valueExists('newLayoutEnabled') &&
-        loadTimeData.getBoolean('newLayoutEnabled');
-  },
-
-  /**
-   * Called when focus is returned.
-   * @param {boolean} reverse Is focus returned in reverse order?
-   */
-  onFocusReturned(reverse) {
-    // We need to explicitly adjust focus inside the webview part when focus is
-    // returned from the system tray in regular order. Because the webview is
-    // the first focusable element of the screen and we want to eliminate extra
-    // tab. Reverse tab doesn't need any adjustments here.
-    if (!this.newLayoutEnabled_() && !reverse && this.uiStep == UIState.EULA)
-      Polymer.RenderStatus.afterNextRender(
-          this, () => this.$.crosEulaFrame.focus());
-  },
 });
 })();
diff --git a/chrome/browser/resources/chromeos/login/structure/components_common.html b/chrome/browser/resources/chromeos/login/structure/components_common.html
index 7b120ea0..999a313 100644
--- a/chrome/browser/resources/chromeos/login/structure/components_common.html
+++ b/chrome/browser/resources/chromeos/login/structure/components_common.html
@@ -10,6 +10,7 @@
 <link rel="import" href="/components/oobe_a11y_option.html">
 <link rel="import" href="/screens/common/gesture_navigation.html">
 <link rel="import" href="/screens/common/marketing_opt_in.html">
+<link rel="import" href="/screens/common/fingerprint_setup.html">
 
 <include src="../components/html-echo.html">
 <include src="../notification_card.html">
@@ -35,7 +36,6 @@
 <include src="../oobe_enable_kiosk.html">
 <include src="../oobe_reset.html">
 <include src="../sync_consent.html">
-<include src="../fingerprint_setup.html">
 <include src="../recommend_apps.html">
 <include src="../app_downloading.html">
 <include src="../pin_setup.html">
diff --git a/chrome/browser/resources/chromeos/login/structure/components_common.js b/chrome/browser/resources/chromeos/login/structure/components_common.js
index 8c0e59a..1beac42e 100644
--- a/chrome/browser/resources/chromeos/login/structure/components_common.js
+++ b/chrome/browser/resources/chromeos/login/structure/components_common.js
@@ -29,7 +29,6 @@
 // <include src="../oobe_enable_kiosk.js">
 // <include src="../oobe_reset.js">
 // <include src="../sync_consent.js">
-// <include src="../fingerprint_setup.js">
 // <include src="../recommend_apps.js">
 // <include src="../app_downloading.js">
 // <include src="../pin_setup.js">
diff --git a/chrome/browser/resources/chromeos/login/test_api/test_api.js b/chrome/browser/resources/chromeos/login/test_api/test_api.js
index 6e2951b5..26aedda3 100644
--- a/chrome/browser/resources/chromeos/login/test_api/test_api.js
+++ b/chrome/browser/resources/chromeos/login/test_api/test_api.js
@@ -123,14 +123,7 @@
   clickNext() {
     if (!this.nextButton) {
       let mainStep = new PolymerElementApi(this, '#welcomeScreen');
-      const newLayout = loadTimeData.valueExists('newLayoutEnabled') &&
-          loadTimeData.getBoolean('newLayoutEnabled');
-
-      if (newLayout) {
-        this.nextButton = new PolymerElementApi(mainStep, '#getStarted');
-      } else {
-        this.nextButton = new PolymerElementApi(mainStep, '#welcomeNextButton');
-      }
+      this.nextButton = new PolymerElementApi(mainStep, '#getStarted');
     }
 
     assert(this.nextButton);
diff --git a/chrome/browser/resources/conflicts/DIR_METADATA b/chrome/browser/resources/conflicts/DIR_METADATA
new file mode 100644
index 0000000..71d433d
--- /dev/null
+++ b/chrome/browser/resources/conflicts/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/win/conflicts/COMMON_METADATA"
diff --git a/chrome/browser/resources/download_shelf/DIR_METADATA b/chrome/browser/resources/download_shelf/DIR_METADATA
new file mode 100644
index 0000000..2eac3f4e
--- /dev/null
+++ b/chrome/browser/resources/download_shelf/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ui/webui/download_shelf/COMMON_METADATA"
diff --git a/chrome/browser/resources/feedback/DIR_METADATA b/chrome/browser/resources/feedback/DIR_METADATA
index 1b00e25cb7..25e9f5bf 100644
--- a/chrome/browser/resources/feedback/DIR_METADATA
+++ b/chrome/browser/resources/feedback/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>Feedback"
-}
+mixins: "//components/feedback/COMMON_METADATA"
diff --git a/chrome/browser/resources/hangout_services/OWNERS b/chrome/browser/resources/hangout_services/OWNERS
index f283b346..07e5a3a 100644
--- a/chrome/browser/resources/hangout_services/OWNERS
+++ b/chrome/browser/resources/hangout_services/OWNERS
@@ -1,2 +1 @@
 eladalon@chromium.org
-grunell@chromium.org
diff --git a/chrome/browser/resources/history/COMMON_METADATA b/chrome/browser/resources/history/COMMON_METADATA
new file mode 100644
index 0000000..9b08ae7f
--- /dev/null
+++ b/chrome/browser/resources/history/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>History"
+}
diff --git a/chrome/browser/resources/history/DIR_METADATA b/chrome/browser/resources/history/DIR_METADATA
index 9b08ae7f..e1981b4 100644
--- a/chrome/browser/resources/history/DIR_METADATA
+++ b/chrome/browser/resources/history/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>History"
-}
+mixins: "//chrome/browser/resources/history/COMMON_METADATA"
diff --git a/chrome/browser/resources/history/history_clusters/DIR_METADATA b/chrome/browser/resources/history/history_clusters/DIR_METADATA
index 88f25f6..694e2bf 100644
--- a/chrome/browser/resources/history/history_clusters/DIR_METADATA
+++ b/chrome/browser/resources/history/history_clusters/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Memories"
-}
+mixins: "//components/history_clusters/COMMON_METADATA"
diff --git a/chrome/browser/resources/internals/notifications/DIR_METADATA b/chrome/browser/resources/internals/notifications/DIR_METADATA
index 524f362..2e4e834 100644
--- a/chrome/browser/resources/internals/notifications/DIR_METADATA
+++ b/chrome/browser/resources/internals/notifications/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Notifications"
-}
+mixins: "//chrome/browser/notifications/COMMON_METADATA"
diff --git a/chrome/browser/resources/internals/user_education/DIR_METADATA b/chrome/browser/resources/internals/user_education/DIR_METADATA
new file mode 100644
index 0000000..8a9dcf64
--- /dev/null
+++ b/chrome/browser/resources/internals/user_education/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ui/user_education/COMMON_METADATA"
diff --git a/chrome/browser/resources/offline_pages/DIR_METADATA b/chrome/browser/resources/offline_pages/DIR_METADATA
index b8fd807..f3d5613e 100644
--- a/chrome/browser/resources/offline_pages/DIR_METADATA
+++ b/chrome/browser/resources/offline_pages/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>Offline"
-}
-team_email: "offline-dev@chromium.org"
+mixins: "//components/offline_pages/COMMON_METADATA"
diff --git a/chrome/browser/resources/omnibox/DIR_METADATA b/chrome/browser/resources/omnibox/DIR_METADATA
index 74265378..7a9dec1 100644
--- a/chrome/browser/resources/omnibox/DIR_METADATA
+++ b/chrome/browser/resources/omnibox/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Omnibox"
-}
+mixins: "//components/omnibox/COMMON_METADATA"
diff --git a/chrome/browser/resources/settings/COMMON_METADATA b/chrome/browser/resources/settings/COMMON_METADATA
new file mode 100644
index 0000000..704a8962
--- /dev/null
+++ b/chrome/browser/resources/settings/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Settings"
+}
diff --git a/chrome/browser/resources/settings/DIR_METADATA b/chrome/browser/resources/settings/DIR_METADATA
index 704a8962..fc61f1b9 100644
--- a/chrome/browser/resources/settings/DIR_METADATA
+++ b/chrome/browser/resources/settings/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Settings"
-}
+mixins: "//chrome/browser/resources/settings/COMMON_METADATA"
diff --git a/chrome/browser/resources/settings/chromeos/COMMON_METADATA b/chrome/browser/resources/settings/chromeos/COMMON_METADATA
new file mode 100644
index 0000000..eeb8ec9
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "OS>Systems>Settings"
+}
diff --git a/chrome/browser/resources/settings/chromeos/DIR_METADATA b/chrome/browser/resources/settings/chromeos/DIR_METADATA
index eeb8ec9..e84643a 100644
--- a/chrome/browser/resources/settings/chromeos/DIR_METADATA
+++ b/chrome/browser/resources/settings/chromeos/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "OS>Systems>Settings"
-}
+mixins: "//chrome/browser/resources/settings/chromeos/COMMON_METADATA"
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/fingerprint_list.html b/chrome/browser/resources/settings/chromeos/os_people_page/fingerprint_list.html
index 90f78c8..58a401b91 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/fingerprint_list.html
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/fingerprint_list.html
@@ -75,7 +75,8 @@
           icon-class="cr:help-outline" icon-aria-label="$i18n{learnMore}">
         <localized-link id="fingerprintNotice"
             localized-string="$i18n{lockScreenFingerprintNotice}"
-            link-url="$i18n{fingerprintLearnMoreLink}">
+            link-url="$i18n{fingerprintLearnMoreLink}"
+            slot="tooltip-text">
           <!-- paper-tooltip probes for children textContent to decide whether
             to show tooltip or not-->
           _
diff --git a/chrome/browser/resources/signin/DIR_METADATA b/chrome/browser/resources/signin/DIR_METADATA
index 781bdd95..95ad5b6 100644
--- a/chrome/browser/resources/signin/DIR_METADATA
+++ b/chrome/browser/resources/signin/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Services>SignIn"
-}
+mixins: "//components/signin/COMMON_METADATA"
diff --git a/chrome/browser/resources/video_tutorials/DIR_METADATA b/chrome/browser/resources/video_tutorials/DIR_METADATA
index a03d8d6d..00888370 100644
--- a/chrome/browser/resources/video_tutorials/DIR_METADATA
+++ b/chrome/browser/resources/video_tutorials/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Upboarding>VideoTutorials"
-}
-team_email: "chrome-upboarding-eng@google.com"
+mixins: "//chrome/browser/video_tutorials/COMMON_METADATA"
diff --git a/chrome/browser/safe_browsing/COMMON_METADATA b/chrome/browser/safe_browsing/COMMON_METADATA
new file mode 100644
index 0000000..ee2d9cf5
--- /dev/null
+++ b/chrome/browser/safe_browsing/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "Services>Safebrowsing"
+}
+team_email: "safebrowsing@chromium.org"
diff --git a/chrome/browser/safe_browsing/DIR_METADATA b/chrome/browser/safe_browsing/DIR_METADATA
index ee2d9cf5..645a0c1 100644
--- a/chrome/browser/safe_browsing/DIR_METADATA
+++ b/chrome/browser/safe_browsing/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Services>Safebrowsing"
-}
-team_email: "safebrowsing@chromium.org"
+mixins: "//chrome/browser/safe_browsing/COMMON_METADATA"
diff --git a/chrome/browser/search/DIR_METADATA b/chrome/browser/search/DIR_METADATA
index 4c751468..10d7b81 100644
--- a/chrome/browser/search/DIR_METADATA
+++ b/chrome/browser/search/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>NewTabPage"
-}
-team_email: "ntp-dev@chromium.org"
+mixins: "//components/search/COMMON_METADATA"
diff --git a/chrome/browser/search_engines/DIR_METADATA b/chrome/browser/search_engines/DIR_METADATA
index c4995e8..1249d12 100644
--- a/chrome/browser/search_engines/DIR_METADATA
+++ b/chrome/browser/search_engines/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Search"
-}
+mixins: "//components/search_engines/COMMON_METADATA"
diff --git a/chrome/browser/search_provider_logos/DIR_METADATA b/chrome/browser/search_provider_logos/DIR_METADATA
index eb6250a8..1f479675 100644
--- a/chrome/browser/search_provider_logos/DIR_METADATA
+++ b/chrome/browser/search_provider_logos/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>NewTabPage"
-}
+mixins: "//components/search_provider_logos/COMMON_METADATA"
diff --git a/chrome/browser/segmentation_platform/DIR_METADATA b/chrome/browser/segmentation_platform/DIR_METADATA
index e90fa6294..837ac09 100644
--- a/chrome/browser/segmentation_platform/DIR_METADATA
+++ b/chrome/browser/segmentation_platform/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>SegmentationPlatform"
-}
+mixins: "//components/segmentation_platform/COMMON_METADATA"
 
-team_email: "chrome-segmentation-platform@google.com"
diff --git a/chrome/browser/send_tab_to_self/DIR_METADATA b/chrome/browser/send_tab_to_self/DIR_METADATA
index 221823e82..024779e 100644
--- a/chrome/browser/send_tab_to_self/DIR_METADATA
+++ b/chrome/browser/send_tab_to_self/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Sharing"
-}
+mixins: "//components/send_tab_to_self/COMMON_METADATA"
diff --git a/chrome/browser/serial/DIR_METADATA b/chrome/browser/serial/DIR_METADATA
index ee7c43e..423968b 100644
--- a/chrome/browser/serial/DIR_METADATA
+++ b/chrome/browser/serial/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Blink>Serial"
-}
+mixins: "//content/browser/serial/COMMON_METADATA"
diff --git a/chrome/browser/settings/DIR_METADATA b/chrome/browser/settings/DIR_METADATA
new file mode 100644
index 0000000..971e38c
--- /dev/null
+++ b/chrome/browser/settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/settings/COMMON_METADATA"
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DIR_METADATA b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DIR_METADATA
new file mode 100644
index 0000000..024779e
--- /dev/null
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/send_tab_to_self/COMMON_METADATA"
diff --git a/chrome/browser/sharesheet/COMMON_METADATA b/chrome/browser/sharesheet/COMMON_METADATA
new file mode 100644
index 0000000..2f2cc53
--- /dev/null
+++ b/chrome/browser/sharesheet/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail: {
+  component: "Platform>Apps>Foundation>Sharesheet"
+}
+team_email: "chromeos-apps-foundation-team@google.com"
+os: CHROME_OS
diff --git a/chrome/browser/sharesheet/DIR_METADATA b/chrome/browser/sharesheet/DIR_METADATA
index 2f2cc53..677ffc81 100644
--- a/chrome/browser/sharesheet/DIR_METADATA
+++ b/chrome/browser/sharesheet/DIR_METADATA
@@ -1,5 +1 @@
-monorail: {
-  component: "Platform>Apps>Foundation>Sharesheet"
-}
-team_email: "chromeos-apps-foundation-team@google.com"
-os: CHROME_OS
+mixins: "//chrome/browser/sharesheet/COMMON_METADATA"
diff --git a/chrome/browser/sharing/COMMON_METADATA b/chrome/browser/sharing/COMMON_METADATA
new file mode 100644
index 0000000..221823e82
--- /dev/null
+++ b/chrome/browser/sharing/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Browser>Sharing"
+}
diff --git a/chrome/browser/sharing/DIR_METADATA b/chrome/browser/sharing/DIR_METADATA
index 221823e82..c1d4532f 100644
--- a/chrome/browser/sharing/DIR_METADATA
+++ b/chrome/browser/sharing/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Sharing"
-}
+mixins: "//chrome/browser/sharing/COMMON_METADATA"
diff --git a/chrome/browser/signin/DIR_METADATA b/chrome/browser/signin/DIR_METADATA
index b368f1d..95ad5b6 100644
--- a/chrome/browser/signin/DIR_METADATA
+++ b/chrome/browser/signin/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Services>SignIn"
-}
-team_email: "chrome-signin@chromium.org"
+mixins: "//components/signin/COMMON_METADATA"
diff --git a/chrome/browser/subresource_filter/DIR_METADATA b/chrome/browser/subresource_filter/DIR_METADATA
index 04cdbc4..2ada13c 100644
--- a/chrome/browser/subresource_filter/DIR_METADATA
+++ b/chrome/browser/subresource_filter/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>AdFilter"
-}
+mixins: "//components/subresource_filter/COMMON_METADATA"
diff --git a/chrome/browser/sync/DIR_METADATA b/chrome/browser/sync/DIR_METADATA
index 59732b8..4a58e65 100644
--- a/chrome/browser/sync/DIR_METADATA
+++ b/chrome/browser/sync/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Services>Sync"
-}
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/chrome/browser/themes/COMMON_METADATA b/chrome/browser/themes/COMMON_METADATA
new file mode 100644
index 0000000..2cead19b
--- /dev/null
+++ b/chrome/browser/themes/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Browser>Themes"
+}
diff --git a/chrome/browser/themes/DIR_METADATA b/chrome/browser/themes/DIR_METADATA
index 2cead19b..826932d7 100644
--- a/chrome/browser/themes/DIR_METADATA
+++ b/chrome/browser/themes/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Themes"
-}
+mixins: "//chrome/browser/themes/COMMON_METADATA"
diff --git a/chrome/browser/translate/DIR_METADATA b/chrome/browser/translate/DIR_METADATA
index f13e6d64..58ea368c 100644
--- a/chrome/browser/translate/DIR_METADATA
+++ b/chrome/browser/translate/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Language>Translate"
-}
+mixins: "//components/translate/COMMON_METADATA"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 6caabc0..65becea 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2157,6 +2157,10 @@
       "ash/shelf/arc_playstore_shortcut_shelf_item_controller.h",
       "ash/shelf/arc_shelf_spinner_item_controller.cc",
       "ash/shelf/arc_shelf_spinner_item_controller.h",
+      "ash/shelf/browser_app_shelf_controller.cc",
+      "ash/shelf/browser_app_shelf_controller.h",
+      "ash/shelf/browser_app_shelf_item_controller.cc",
+      "ash/shelf/browser_app_shelf_item_controller.h",
       "ash/shelf/browser_shortcut_shelf_item_controller.cc",
       "ash/shelf/browser_shortcut_shelf_item_controller.h",
       "ash/shelf/browser_status_monitor.cc",
diff --git a/chrome/browser/ui/android/DIR_METADATA b/chrome/browser/ui/android/DIR_METADATA
new file mode 100644
index 0000000..c69388e
--- /dev/null
+++ b/chrome/browser/ui/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/chrome/browser/ui/android/appmenu/COMMON_METADATA b/chrome/browser/ui/android/appmenu/COMMON_METADATA
new file mode 100644
index 0000000..af4edb8
--- /dev/null
+++ b/chrome/browser/ui/android/appmenu/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Mobile>AppMenu"
+}
+team_email: "clank-app-team@google.com"
+os: ANDROID
diff --git a/chrome/browser/ui/android/appmenu/DIR_METADATA b/chrome/browser/ui/android/appmenu/DIR_METADATA
index af4edb8..9421435f 100644
--- a/chrome/browser/ui/android/appmenu/DIR_METADATA
+++ b/chrome/browser/ui/android/appmenu/DIR_METADATA
@@ -1,5 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>AppMenu"
-}
-team_email: "clank-app-team@google.com"
-os: ANDROID
+mixins: "//chrome/browser/ui/android/appmenu/COMMON_METADATA"
diff --git a/chrome/browser/ui/android/autofill/DIR_METADATA b/chrome/browser/ui/android/autofill/DIR_METADATA
new file mode 100644
index 0000000..cb63906
--- /dev/null
+++ b/chrome/browser/ui/android/autofill/DIR_METADATA
@@ -0,0 +1,2 @@
+mixins: "//components/autofill/COMMON_METADATA"
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/autofill/COMMON_METADATA"
diff --git a/chrome/browser/ui/android/default_browser_promo/DIR_METADATA b/chrome/browser/ui/android/default_browser_promo/DIR_METADATA
index 36e073a..ab43d157 100644
--- a/chrome/browser/ui/android/default_browser_promo/DIR_METADATA
+++ b/chrome/browser/ui/android/default_browser_promo/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>Messages"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/browser/ui/android/favicon/DIR_METADATA b/chrome/browser/ui/android/favicon/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/browser/ui/android/favicon/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/browser/ui/android/layouts/DIR_METADATA b/chrome/browser/ui/android/layouts/DIR_METADATA
index d8125201..516e136d 100644
--- a/chrome/browser/ui/android/layouts/DIR_METADATA
+++ b/chrome/browser/ui/android/layouts/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>CompositedUI"
 }
 team_email: "chrome-android-app@chromium.org"
-os: ANDROID
diff --git a/chrome/browser/ui/android/multiwindow/DIR_METADATA b/chrome/browser/ui/android/multiwindow/DIR_METADATA
index 052b88d..fcc5510 100644
--- a/chrome/browser/ui/android/multiwindow/DIR_METADATA
+++ b/chrome/browser/ui/android/multiwindow/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>MultiInstance"
 }
 team_email: "chrome-android-app@chromium.org"
-os: ANDROID
diff --git a/chrome/browser/ui/android/native_page/DIR_METADATA b/chrome/browser/ui/android/native_page/DIR_METADATA
deleted file mode 100644
index b4dcb712..0000000
--- a/chrome/browser/ui/android/native_page/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
diff --git a/chrome/browser/ui/android/omnibox/DIR_METADATA b/chrome/browser/ui/android/omnibox/DIR_METADATA
index db98947..07a4669 100644
--- a/chrome/browser/ui/android/omnibox/DIR_METADATA
+++ b/chrome/browser/ui/android/omnibox/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Omnibox"
 }
-os: ANDROID
diff --git a/chrome/browser/ui/android/quickactionsearchwidget/DIR_METADATA b/chrome/browser/ui/android/quickactionsearchwidget/DIR_METADATA
index 0c198a7f..c69f281 100644
--- a/chrome/browser/ui/android/quickactionsearchwidget/DIR_METADATA
+++ b/chrome/browser/ui/android/quickactionsearchwidget/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>SearchWidget"
 }
 team_email: "seacow-team@google.com"
-os: ANDROID
\ No newline at end of file
diff --git a/chrome/browser/ui/android/safe_browsing/DIR_METADATA b/chrome/browser/ui/android/safe_browsing/DIR_METADATA
index 6408b73..67265de 100644
--- a/chrome/browser/ui/android/safe_browsing/DIR_METADATA
+++ b/chrome/browser/ui/android/safe_browsing/DIR_METADATA
@@ -1,3 +1,4 @@
+mixins: "//chrome/browser/safe_browsing/COMMON_METADATA"
 monorail {
   component: "UI>Browser>SafeBrowsing"
 }
diff --git a/chrome/browser/ui/android/searchactivityutils/DIR_METADATA b/chrome/browser/ui/android/searchactivityutils/DIR_METADATA
index 0c198a7f..c69f281 100644
--- a/chrome/browser/ui/android/searchactivityutils/DIR_METADATA
+++ b/chrome/browser/ui/android/searchactivityutils/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>SearchWidget"
 }
 team_email: "seacow-team@google.com"
-os: ANDROID
\ No newline at end of file
diff --git a/chrome/browser/ui/android/tab_contents/DIR_METADATA b/chrome/browser/ui/android/tab_contents/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/browser/ui/android/tab_contents/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/browser/ui/android/tab_model/DIR_METADATA b/chrome/browser/ui/android/tab_model/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/browser/ui/android/tab_model/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/browser/ui/android/theme/DIR_METADATA b/chrome/browser/ui/android/theme/DIR_METADATA
index d2c98af1..9601a0e9 100644
--- a/chrome/browser/ui/android/theme/DIR_METADATA
+++ b/chrome/browser/ui/android/theme/DIR_METADATA
@@ -1,5 +1 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
 team_email: "chrome-android-app@chromium.org"
-os: ANDROID
diff --git a/chrome/browser/ui/android/toolbar/COMMON_METADATA b/chrome/browser/ui/android/toolbar/COMMON_METADATA
new file mode 100644
index 0000000..31157b6a
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Toolbar"
+}
+os: ANDROID
diff --git a/chrome/browser/ui/android/toolbar/DIR_METADATA b/chrome/browser/ui/android/toolbar/DIR_METADATA
index 31157b6a..0d3fa4a0 100644
--- a/chrome/browser/ui/android/toolbar/DIR_METADATA
+++ b/chrome/browser/ui/android/toolbar/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Toolbar"
-}
-os: ANDROID
+mixins: "//chrome/browser/ui/android/toolbar/COMMON_METADATA"
diff --git a/chrome/browser/ui/android/webid/DIR_METADATA b/chrome/browser/ui/android/webid/DIR_METADATA
index 76412c2..136e07617 100644
--- a/chrome/browser/ui/android/webid/DIR_METADATA
+++ b/chrome/browser/ui/android/webid/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Blink>Identity>WebID"
-}
+mixins: "//content/browser/webid/COMMON_METADATA"
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
index 76b77edd..02cfab61 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
@@ -41,6 +41,7 @@
 
 using crx_file::id_util::GenerateId;
 using testing::ElementsAre;
+using ItemTestApi = ChromeAppListItem::TestApi;
 
 namespace {
 
@@ -974,11 +975,11 @@
   std::unique_ptr<ChromeAppListItem> page_break_item3 =
       std::make_unique<ChromeAppListItem>(profile_.get(), kPageBreakItemId3,
                                           model_updater());
-  page_break_item1->SetPosition(syncer::StringOrdinal("bm"));
+  ItemTestApi(page_break_item1.get()).SetPosition(syncer::StringOrdinal("bm"));
   page_break_item1->SetIsPageBreak(true);
-  page_break_item2->SetPosition(syncer::StringOrdinal("cm"));
+  ItemTestApi(page_break_item2.get()).SetPosition(syncer::StringOrdinal("cm"));
   page_break_item2->SetIsPageBreak(true);
-  page_break_item3->SetPosition(syncer::StringOrdinal("dm"));
+  ItemTestApi(page_break_item3.get()).SetPosition(syncer::StringOrdinal("dm"));
   page_break_item3->SetIsPageBreak(true);
   app_list_syncable_service()->AddItem(std::move(page_break_item1));
   app_list_syncable_service()->AddItem(std::move(page_break_item2));
@@ -1263,7 +1264,7 @@
         std::make_unique<ChromeAppListItem>(
             profile_.get(), GenerateId("item_id" + base::NumberToString(i)),
             model_updater());
-    item->SetPosition(last_app_position);
+    ItemTestApi(item.get()).SetPosition(last_app_position);
     model_updater()->AddItem(std::move(item));
     if (i < max_items_in_first_page - 2)
       last_app_position = last_app_position.CreateAfter();
@@ -1277,7 +1278,7 @@
           profile_.get(), GenerateId("page_break_item_id"), model_updater());
   const syncer::StringOrdinal page_break_position =
       last_app_position.CreateAfter();
-  page_break_item->SetPosition(page_break_position);
+  ItemTestApi(page_break_item.get()).SetPosition(page_break_position);
   page_break_item->SetIsPageBreak(true);
   model_updater()->AddItem((std::move(page_break_item)));
   EXPECT_TRUE(last_app_position.CreateBetween(page_break_position)
@@ -1289,7 +1290,8 @@
           profile_.get(),
           GenerateId("item_id" + base::NumberToString(max_items_in_first_page)),
           model_updater());
-  app_item->SetPosition(last_app_position.CreateBetween(page_break_position));
+  ItemTestApi(app_item.get())
+      .SetPosition(last_app_position.CreateBetween(page_break_position));
   model_updater()->AddItem(std::move(app_item));
   EXPECT_TRUE(page_break_position.CreateAfter().Equals(
       model_updater()->GetFirstAvailablePosition()));
@@ -1311,7 +1313,7 @@
         std::make_unique<ChromeAppListItem>(
             profile_.get(), GenerateId("item_id" + base::NumberToString(i)),
             model_updater());
-    item->SetPosition(last_app_position);
+    ItemTestApi(item.get()).SetPosition(last_app_position);
     model_updater()->AddItem(std::move(item));
     if (i < max_items_in_first_page - 2)
       last_app_position = last_app_position.CreateAfter();
@@ -1322,7 +1324,7 @@
   std::unique_ptr<ChromeAppListItem> page_break_item =
       std::make_unique<ChromeAppListItem>(
           profile_.get(), GenerateId("page_break_item_id"), model_updater());
-  page_break_item->SetPosition(last_app_position);
+  ItemTestApi(page_break_item.get()).SetPosition(last_app_position);
   page_break_item->SetIsPageBreak(true);
   model_updater()->AddItem((std::move(page_break_item)));
   EXPECT_TRUE(last_app_position.CreateAfter().Equals(
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_item.cc b/chrome/browser/ui/app_list/app_service/app_service_app_item.cc
index 514ab20..d0ec4856 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_app_item.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_item.cc
@@ -38,18 +38,17 @@
       is_platform_app_(false) {
   OnAppUpdate(app_update, true);
   if (sync_item && sync_item->item_ordinal.IsValid()) {
-    UpdateFromSync(sync_item);
-  } else if (app_type_ == apps::mojom::AppType::kRemote) {
-    ash::RemoteAppsManager* remote_apps_manager =
-        ash::RemoteAppsManagerFactory::GetForProfile(profile);
-
-    if (remote_apps_manager->ShouldAddToFront(app_update.AppId())) {
-      SetPosition(model_updater->GetPositionBeforeFirstItem());
-    } else {
-      SetDefaultPositionIfApplicable(model_updater);
-    }
+    InitFromSync(sync_item);
   } else {
-    SetDefaultPositionIfApplicable(model_updater);
+    syncer::StringOrdinal default_position;
+    if (app_type_ == apps::mojom::AppType::kRemote &&
+        ash::RemoteAppsManagerFactory::GetForProfile(profile)->ShouldAddToFront(
+            app_update.AppId())) {
+      default_position = model_updater->GetPositionBeforeFirstItem();
+    } else {
+      default_position = CalculateDefaultPositionIfApplicable(model_updater);
+    }
+    SetPosition(default_position);
 
     // Crostini apps and the Terminal System App start in the crostini folder.
     if (app_type_ == apps::mojom::AppType::kCrostini ||
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc
index 885694f..cbaf1e4 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder.cc
@@ -56,7 +56,9 @@
 
     if (!parent_->GetSyncItem(ash::kCrostiniFolderId,
                               sync_pb::AppListSpecifics::TYPE_FOLDER)) {
-      item->SetDefaultPositionIfApplicable(parent_->model_updater());
+      item->model_updater()->SetItemPosition(
+          item->id(),
+          item->CalculateDefaultPositionIfApplicable(parent_->model_updater()));
     }
 
     // Reset the folder name whether it's in the sync service or not
diff --git a/chrome/browser/ui/app_list/chrome_app_list_item.cc b/chrome/browser/ui/app_list/chrome_app_list_item.cc
index 20ba1d96..37356124 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_item.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_item.cc
@@ -123,7 +123,7 @@
                                           : AppListClientImpl::GetInstance();
 }
 
-void ChromeAppListItem::UpdateFromSync(
+void ChromeAppListItem::InitFromSync(
     const app_list::AppListSyncableService::SyncItem* sync_item) {
   DCHECK(sync_item && sync_item->item_ordinal.IsValid());
   // An existing synced position exists, use that.
@@ -133,7 +133,7 @@
     SetName(sync_item->item_name);
 }
 
-void ChromeAppListItem::SetDefaultPositionIfApplicable(
+syncer::StringOrdinal ChromeAppListItem::CalculateDefaultPositionIfApplicable(
     AppListModelUpdater* model_updater) {
   syncer::StringOrdinal page_ordinal;
   syncer::StringOrdinal launch_ordinal;
@@ -141,23 +141,21 @@
   if (app_sorting->GetDefaultOrdinals(id(), &page_ordinal, &launch_ordinal) &&
       page_ordinal.IsValid() && launch_ordinal.IsValid()) {
     // Set the default position if it exists.
-    SetPosition(syncer::StringOrdinal(page_ordinal.ToInternalValue() +
-                                      launch_ordinal.ToInternalValue()));
-    return;
+    return syncer::StringOrdinal(page_ordinal.ToInternalValue() +
+                                 launch_ordinal.ToInternalValue());
   }
 
   if (model_updater) {
     // Set the first available position in the app list.
-    SetPosition(model_updater->GetFirstAvailablePosition());
-    return;
+    return model_updater->GetFirstAvailablePosition();
   }
 
   // Set the natural position.
   app_sorting->EnsureValidOrdinals(id(), syncer::StringOrdinal());
   page_ordinal = app_sorting->GetPageOrdinal(id());
   launch_ordinal = app_sorting->GetAppLaunchOrdinal(id());
-  SetPosition(syncer::StringOrdinal(page_ordinal.ToInternalValue() +
-                                    launch_ordinal.ToInternalValue()));
+  return syncer::StringOrdinal(page_ordinal.ToInternalValue() +
+                               launch_ordinal.ToInternalValue());
 }
 
 void ChromeAppListItem::LoadIcon() {
@@ -214,9 +212,6 @@
 
 void ChromeAppListItem::SetPosition(const syncer::StringOrdinal& position) {
   metadata_->position = position;
-  AppListModelUpdater* updater = model_updater();
-  if (updater)
-    updater->SetItemPosition(id(), position);
 }
 
 void ChromeAppListItem::SetIsPersistent(bool is_persistent) {
diff --git a/chrome/browser/ui/app_list/chrome_app_list_item.h b/chrome/browser/ui/app_list/chrome_app_list_item.h
index 9171a9dc..2604208 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_item.h
+++ b/chrome/browser/ui/app_list/chrome_app_list_item.h
@@ -81,7 +81,6 @@
                            const std::string& short_name);
   void SetAppStatus(ash::AppStatus app_status);
   void SetFolderId(const std::string& folder_id);
-  void SetPosition(const syncer::StringOrdinal& position);
   void SetIsPageBreak(bool is_page_break);
   void SetIsPersistent(bool is_persistent);
 
@@ -117,11 +116,16 @@
 
   std::string ToDebugString() const;
 
-  // Set the default position if it exists. Otherwise set the first available
-  // position in the app list if |model_updater| is not null.
-  void SetDefaultPositionIfApplicable(AppListModelUpdater* model_updater);
+  // Returns the default position if it exists. Otherwise returns the position
+  // for a new item if |model_updater| is not null.
+  syncer::StringOrdinal CalculateDefaultPositionIfApplicable(
+      AppListModelUpdater* model_updater);
+
+  AppListModelUpdater* model_updater() { return model_updater_; }
 
  protected:
+  friend class ChromeAppListModelUpdater;
+
   ChromeAppListItem(Profile* profile, const std::string& app_id);
 
   Profile* profile() const { return profile_; }
@@ -130,13 +134,15 @@
 
   AppListControllerDelegate* GetController();
 
-  AppListModelUpdater* model_updater() { return model_updater_; }
+  void SetPosition(const syncer::StringOrdinal& position);
+
   void set_model_updater(AppListModelUpdater* model_updater) {
     model_updater_ = model_updater;
   }
 
-  // Updates item position and name from |sync_item|. |sync_item| must be valid.
-  void UpdateFromSync(
+  // Initializes item position and name from `sync_item`. `sync_item` must be
+  // valid.
+  void InitFromSync(
       const app_list::AppListSyncableService::SyncItem* sync_item);
 
   // Get the context menu of a certain app. This could be different for
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
index a79edaf..814c9375 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
@@ -248,9 +248,13 @@
   ChromeAppListItem* item = FindItem(id);
   if (!item)
     return;
-  std::unique_ptr<ash::AppListItemMetadata> data = item->CloneMetadata();
-  data->position = new_position;
-  app_list_controller_->SetItemMetadata(id, std::move(data));
+
+  DCHECK(new_position.IsValid());
+  if (item->position().IsValid() && item->position().Equals(new_position))
+    return;
+
+  item->SetPosition(new_position);
+  app_list_controller_->SetItemMetadata(id, item->CloneMetadata());
 }
 
 void ChromeAppListModelUpdater::SetItemIsPersistent(const std::string& id,
@@ -466,7 +470,7 @@
       (!chrome_item->position().IsValid() ||
        !chrome_item->position().Equals(sync_item->item_ordinal))) {
     // This updates the position in both chrome and ash:
-    chrome_item->SetPosition(sync_item->item_ordinal);
+    SetItemPosition(chrome_item->id(), sync_item->item_ordinal);
   }
   // Only update the item name if it is a Folder or the name is empty.
   if (update_name && sync_item->item_name != chrome_item->name() &&
diff --git a/chrome/browser/ui/app_list/page_break_app_item.cc b/chrome/browser/ui/app_list/page_break_app_item.cc
index 354b89e8..9543ee7 100644
--- a/chrome/browser/ui/app_list/page_break_app_item.cc
+++ b/chrome/browser/ui/app_list/page_break_app_item.cc
@@ -18,12 +18,12 @@
   if (sync_item) {
     DCHECK_EQ(sync_item->item_type, sync_pb::AppListSpecifics::TYPE_PAGE_BREAK);
     if (sync_item->item_ordinal.IsValid()) {
-      UpdateFromSync(sync_item);
+      InitFromSync(sync_item);
       return;
     }
   }
 
-  SetDefaultPositionIfApplicable(model_updater);
+  SetPosition(CalculateDefaultPositionIfApplicable(model_updater));
 
   // Set model updater last to avoid being called during construction.
   set_model_updater(model_updater);
diff --git a/chrome/browser/ui/app_list/search/ranking/score_normalizer.md b/chrome/browser/ui/app_list/search/ranking/score_normalizer.md
new file mode 100644
index 0000000..656dd28
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/ranking/score_normalizer.md
@@ -0,0 +1,137 @@
+# Score normalizer
+
+The score normalizer is a heuristic algorithm that attempts to map a incoming
+stream of numbers drawn from some unknown distribution to a uniform
+distribution. This allows us to directly compare scores produced by different
+underlying distributions, namely, by different search providers.
+
+## Overview and terminology
+
+The input to the normalizer is a stream of scores, `x`, drawn from an
+underlying continuous distribution, `P(x)`. Its goal is to learn a function
+`f(x)` such that `f(x ~ P)` is a uniform distribution over `[0,1]`.
+
+## Reservoir sampling
+
+Reservoir sampling is a method for computing `f`. Its simplest form is:
+
+- Take the first `N` (eg. 100) scores as a 'reservoir'.
+- Define `f(x) = sum(y < x for y in reservoir) / N`
+
+In other words, we take the first `N` scores as a reservoir, and then
+normalize a new score by computing its quantile within the reservoir.
+
+We've constructed `f` by choosing a series of dividers (the reservoir scores)
+which we hope are a representative sample of `P`. Consequently, a new `x ~ P`
+will fall into any 'bucket' between two dividers with equal probability. So,
+the index of the bucket x falls into is the quantile of x within `P`. Thus,
+with some allowance for the fact that f is discrete, `f(x ~ P) ~= U(0,1)`.
+
+The drawback of this is that the reservoir needs to be quite large before
+this is effective.
+
+## Bin-entropy reservoir sampling
+
+We're going to trade off some accuracy for efficiency, and build on the core
+idea of reservoir sampling. We will store 'bins' that cover the real line, and
+try to keep the number of elements we've seen in each bin approximately equal.
+Then we can compute `f(x)` by using the bin index of `x` as a quantile.
+
+__Data structure__. We store a vector of N 'bins', each one with a count and
+a lower divider. The bottom bin always has a lower divider of negative
+infinity. `bins[i].count` roughly tracks the number of scores we've seen
+between `bins[i-1].lower_divider` and `bins[i].lower_divider`.
+
+__Algorithm overview.__ Each time a score is recorded, we increment the count
+of the appropriate bin. Then, we propose a repartition of the bins as follows:
+
+- Split the bin corresponding to the new score into two bins, divided by the
+  new score. Halve the counts of the old bin into the two new bins.
+
+- Merge together the two smallest contiguous bins, so that the total number of
+  bins stays equal.
+
+We accept this repartition if it increases the evenness across all bins, which
+we measure using entropy. For simplicity, we prevent the merged bins from
+containing either of the split bins.
+
+__Entropy.__ Given a collection of bins, its entropy is:
+
+```
+H(p) = -sum( bin.count/total * log(bin.count/total) for bin in bins )
+```
+
+Entropy has two key properties:
+1. The discrete distribution with maximum entropy is the uniform distribution.
+2. Entropy is convex.
+
+As such, we can make our bins as uniform as possible by seeking to maximize
+entropy. This is implemented by only accepting a repartition if it increases
+entropy.
+
+__Fast entropy calculations.__ Suppose we are considering a repartition that:
+ - splits bin `s` into `s_l` and `s_r`,
+ - merges bins `m_l` and `m_r` into `m`.
+
+We don't need to compute the full entropy over the old and new sets of bins,
+because the entropy contributions of bins not related to the split or merge
+cancel out. As such, we can calculate this with only six terms as follows,
+where `p(bin) = bin.count / total`.
+
+```
+H(new) - H(old) =   [ -p(s_l) log p(s_l) - p(s_r) log p(s_r) - p(m) log p(m) ]
+                  - [ -p(s) log p(s) - p(m_l) log p(m_l) - p(m_r) log p(m_r) ]
+```
+
+__Algorithm pseudocode.__ This leaves us with the following algorithm for
+an update.
+
+```
+def update(score):
+  if there aren't N bins yet:
+    insert Bin(lower_divider=score, count=1)
+    return
+
+  s = score's bin
+  s.count++
+
+  m_l, m_r = smallest contiguous pair of bins separate from s
+  m = Bin(lower_divider=m_l.lower_divider, count=m_l.count + m_r.count)
+
+  s_l = Bin(lower_divider=s.lower_divider, count=s.count/2)
+  s_r = Bin(lower_divider=score, count=s.count/2)
+
+  if H(new) > H(old):
+    replace s with s_l and s_r
+    replace m_l and m_r with m
+```
+
+## Performance
+
+We did some benchmarking under these conditions:
+ - Two tests: samples from `Beta(2,5)`, and a power-law distribution.
+ - The bin-entropy algorithm targeting 5 bins.
+ - The 'simple' algorithm from above storing `N` samples.
+ - The 'better-simple' algorithm that stores the last `N` samples and uses
+   them to decide the dividers for 5 bins.
+
+Results showed that the bin-entropy algorithm performs about as well as the
+better-simple algorithm when `N = 150`, and actually slightly outperforms it for
+`N < 150`. This may be due to the split/merge making it less sensitive to noise.
+It's difficult to compare the results of the simple algorithm because the number
+of bins is different, but the results were significantly noisier than the
+better-simple algorithm.
+
+# Ideas for improvement
+
+Here are some things that anecdotally improve performance:
+
+ - The algorithm loses information when a bin is split, because splitting the
+   counts evenly is uninformed. Tracking moments of the distribution within
+   each bin can help make this a more informed choice.
+
+ - We only perform one split/merge operation per insert, but it's possible
+   several split-merges should be done after one insert.
+
+ - Allowing the merged bins to contain one of the split bins provides a small
+   improvement in performance.
diff --git a/chrome/browser/ui/app_list/test/fake_app_list_model_updater.cc b/chrome/browser/ui/app_list/test/fake_app_list_model_updater.cc
index aa351e590..a591513 100644
--- a/chrome/browser/ui/app_list/test/fake_app_list_model_updater.cc
+++ b/chrome/browser/ui/app_list/test/fake_app_list_model_updater.cc
@@ -71,6 +71,16 @@
     observer.OnAppListItemUpdated(item);
 }
 
+void FakeAppListModelUpdater::SetItemPosition(
+    const std::string& id,
+    const syncer::StringOrdinal& new_position) {
+  ChromeAppListItem* item = FindItem(id);
+  if (!item)
+    return;
+
+  ChromeAppListItem::TestApi(item).SetPosition(new_position);
+}
+
 void FakeAppListModelUpdater::SetSearchEngineIsGoogle(bool is_google) {
   search_engine_is_google_ = is_google;
 }
@@ -208,7 +218,7 @@
       (!chrome_item->position().IsValid() ||
        !chrome_item->position().Equals(sync_item->item_ordinal))) {
     // This updates the position in both chrome and ash:
-    chrome_item->SetPosition(sync_item->item_ordinal);
+    SetItemPosition(chrome_item->id(), sync_item->item_ordinal);
   }
   // Only update the item name if it is a Folder or the name is empty.
   if (update_name && sync_item->item_name != chrome_item->name() &&
diff --git a/chrome/browser/ui/app_list/test/fake_app_list_model_updater.h b/chrome/browser/ui/app_list/test/fake_app_list_model_updater.h
index a3d668f..2c2066d 100644
--- a/chrome/browser/ui/app_list/test/fake_app_list_model_updater.h
+++ b/chrome/browser/ui/app_list/test/fake_app_list_model_updater.h
@@ -41,6 +41,8 @@
   void SetItemIcon(const std::string& id, const gfx::ImageSkia& icon) override;
   void SetItemFolderId(const std::string& id,
                        const std::string& folder_id) override;
+  void SetItemPosition(const std::string& id,
+                       const syncer::StringOrdinal& new_position) override;
   // For SearchModel:
   void SetSearchEngineIsGoogle(bool is_google) override;
   void PublishSearchResults(
diff --git a/chrome/browser/ui/apps/DIR_METADATA b/chrome/browser/ui/apps/DIR_METADATA
new file mode 100644
index 0000000..0f723e54
--- /dev/null
+++ b/chrome/browser/ui/apps/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//apps/COMMON_METADATA"
diff --git a/chrome/browser/ui/ash/accessibility/DIR_METADATA b/chrome/browser/ui/ash/accessibility/DIR_METADATA
index 299fade..c775858 100644
--- a/chrome/browser/ui/ash/accessibility/DIR_METADATA
+++ b/chrome/browser/ui/ash/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail {
   component: "UI>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/chrome/browser/ui/ash/assistant/DIR_METADATA b/chrome/browser/ui/ash/assistant/DIR_METADATA
index 5cf9e51..cfb0c371 100644
--- a/chrome/browser/ui/ash/assistant/DIR_METADATA
+++ b/chrome/browser/ui/ash/assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Shell>Assistant"
-}
+mixins: "//chromeos/assistant/COMMON_METADATA"
diff --git a/chrome/browser/ui/ash/holding_space/DIR_METADATA b/chrome/browser/ui/ash/holding_space/DIR_METADATA
index 982c76d..4820d9d 100644
--- a/chrome/browser/ui/ash/holding_space/DIR_METADATA
+++ b/chrome/browser/ui/ash/holding_space/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Shell>HoldingSpace"
-}
+mixins: "//ash/public/cpp/holding_space/COMMON_METADATA"
diff --git a/chrome/browser/ui/ash/keyboard/DIR_METADATA b/chrome/browser/ui/ash/keyboard/DIR_METADATA
index 1ae4c22..671c987 100644
--- a/chrome/browser/ui/ash/keyboard/DIR_METADATA
+++ b/chrome/browser/ui/ash/keyboard/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Inputs"
-}
+mixins: "//ash/keyboard/COMMON_METADATA"
diff --git a/chrome/browser/ui/ash/sharesheet/DIR_METADATA b/chrome/browser/ui/ash/sharesheet/DIR_METADATA
index 2f2cc53..677ffc81 100644
--- a/chrome/browser/ui/ash/sharesheet/DIR_METADATA
+++ b/chrome/browser/ui/ash/sharesheet/DIR_METADATA
@@ -1,5 +1 @@
-monorail: {
-  component: "Platform>Apps>Foundation>Sharesheet"
-}
-team_email: "chromeos-apps-foundation-team@google.com"
-os: CHROME_OS
+mixins: "//chrome/browser/sharesheet/COMMON_METADATA"
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc
index 0c8012d..7fe18d11 100644
--- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_browsertest.cc
@@ -1019,6 +1019,11 @@
 
 INSTANTIATE_TEST_SUITE_P(All,
                          AppServiceAppWindowSystemWebAppBrowserTest,
-                         ::testing::Values(CrosapiParam::kDisabled,
-                                           CrosapiParam::kEnabled),
+                         // TODO(crbug.com/1203992): Tests are not run with the
+                         // flag enabled for now, because WebAppsCrosapi
+                         // automatically enables new browser app tracking, but
+                         // it doesn't implement app service instance registry
+                         // updates yet, so the test will fail with the flag
+                         // enabled.
+                         ::testing::Values(CrosapiParam::kDisabled),
                          WithCrosapiParam::ParamToString);
diff --git a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_shelf_controller.cc b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_shelf_controller.cc
index a840abd..39548c0 100644
--- a/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_shelf_controller.cc
+++ b/chrome/browser/ui/ash/shelf/app_service/app_service_app_window_shelf_controller.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chromeos/ui/base/window_properties.h"
 #include "components/account_id/account_id.h"
@@ -167,6 +168,12 @@
   if (!widget || !widget->is_top_level())
     return;
 
+  if (base::FeatureList::IsEnabled(features::kWebAppsCrosapi) &&
+      crosapi::browser_util::IsLacrosWindow(window)) {
+    // Ignore all Lacros windows, handled by BrowserAppShelfController.
+    return;
+  }
+
   observed_windows_.AddObservation(window);
   if (arc_tracker_)
     arc_tracker_->AddCandidateWindow(window);
diff --git a/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.cc b/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.cc
new file mode 100644
index 0000000..f41d107
--- /dev/null
+++ b/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.cc
@@ -0,0 +1,173 @@
+// 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/ash/shelf/browser_app_shelf_controller.h"
+
+#include <memory>
+
+#include "ash/public/cpp/shelf_model.h"
+#include "ash/public/cpp/window_properties.h"
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/browser_app_instance.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_registry.h"
+#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ui/ash/shelf/browser_app_shelf_item_controller.h"
+#include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h"
+#include "chrome/browser/ui/ash/shelf/chrome_shelf_item_factory.h"
+#include "chrome/browser/ui/ash/shelf/shelf_controller_helper.h"
+#include "chrome/browser/ui/ash/shelf/shelf_spinner_controller.h"
+#include "extensions/common/constants.h"
+#include "ui/aura/window.h"
+
+namespace {
+
+void MaybeUpdateStringProperty(aura::Window* window,
+                               const ui::ClassProperty<std::string*>* property,
+                               const std::string& value) {
+  std::string* old_value = window->GetProperty(ash::kAppIDKey);
+  if (!old_value || *old_value != value) {
+    window->SetProperty(property, value);
+  }
+}
+
+}  // namespace
+
+BrowserAppShelfController::BrowserAppShelfController(
+    Profile* profile,
+    ash::ShelfModel& model,
+    ChromeShelfItemFactory& shelf_item_factory,
+    ShelfSpinnerController& shelf_spinner_controller)
+    : profile_(profile),
+      model_(model),
+      shelf_item_factory_(shelf_item_factory),
+      shelf_spinner_controller_(shelf_spinner_controller),
+      browser_app_instance_registry_(
+          *apps::AppServiceProxyFactory::GetForProfile(profile)
+               ->BrowserAppInstanceRegistry()) {
+  registry_observation_.Observe(&browser_app_instance_registry_);
+}
+
+BrowserAppShelfController::~BrowserAppShelfController() = default;
+
+void BrowserAppShelfController::OnBrowserWindowAdded(
+    const apps::BrowserWindowInstance& instance) {
+  ash::ShelfID id(crosapi::browser_util::IsLacrosWindow(instance.window)
+                      ? extension_misc::kLacrosAppId
+                      : extension_misc::kChromeAppId);
+  CreateOrUpdateShelfItem(id, ash::STATUS_RUNNING);
+  MaybeUpdateBrowserWindowProperties(instance.window);
+}
+
+void BrowserAppShelfController::OnBrowserWindowRemoved(
+    const apps::BrowserWindowInstance& instance) {
+  bool is_running =
+      crosapi::browser_util::IsLacrosWindow(instance.window)
+          ? browser_app_instance_registry_.IsLacrosBrowserRunning()
+          : browser_app_instance_registry_.IsAshBrowserRunning();
+  if (!is_running) {
+    ash::ShelfID id(crosapi::browser_util::IsLacrosWindow(instance.window)
+                        ? extension_misc::kLacrosAppId
+                        : extension_misc::kChromeAppId);
+    SetShelfItemClosed(id);
+  }
+}
+
+void BrowserAppShelfController::OnBrowserAppAdded(
+    const apps::BrowserAppInstance& instance) {
+  ash::ShelfID id(instance.app_id);
+  switch (instance.type) {
+    case apps::BrowserAppInstance::Type::kAppWindow: {
+      shelf_spinner_controller_.CloseSpinner(instance.app_id);
+      CreateOrUpdateShelfItem(id, ash::STATUS_RUNNING);
+      break;
+    }
+    case apps::BrowserAppInstance::Type::kAppTab:
+      // New shelf item is not automatically created for unpinned tabbed apps.
+      if (const ash::ShelfItem* item = model_.ItemByID(id)) {
+        UpdateShelfItemStatus(*item, ash::STATUS_RUNNING);
+      }
+      break;
+  }
+  MaybeUpdateBrowserWindowProperties(instance.window);
+}
+
+void BrowserAppShelfController::OnBrowserAppUpdated(
+    const apps::BrowserAppInstance& instance) {
+  MaybeUpdateBrowserWindowProperties(instance.window);
+}
+
+void BrowserAppShelfController::OnBrowserAppRemoved(
+    const apps::BrowserAppInstance& instance) {
+  MaybeUpdateBrowserWindowProperties(instance.window);
+  if (!browser_app_instance_registry_.IsAppRunning(instance.app_id)) {
+    ash::ShelfID id(instance.app_id);
+    SetShelfItemClosed(id);
+  }
+}
+
+void BrowserAppShelfController::UpdateShelfItemStatus(
+    const ash::ShelfItem& item,
+    ash::ShelfItemStatus status) {
+  auto new_item = item;
+  new_item.status = status;
+  model_.Set(model_.ItemIndexByID(item.id), new_item);
+}
+
+void BrowserAppShelfController::CreateOrUpdateShelfItem(
+    const ash::ShelfID& id,
+    ash::ShelfItemStatus status) {
+  const ash::ShelfItem* item = model_.ItemByID(id);
+  if (item) {
+    UpdateShelfItemStatus(*item, status);
+    return;
+  }
+
+  ash::ShelfItem new_item;
+  std::unique_ptr<ash::ShelfItemDelegate> delegate;
+  shelf_item_factory_.CreateShelfItemForAppId(id.app_id, &new_item, &delegate);
+  new_item.type = ash::TYPE_APP;
+  new_item.status = status;
+  new_item.app_status =
+      ShelfControllerHelper::GetAppStatus(profile_, id.app_id);
+  model_.AddAt(model_.item_count(), new_item, std::move(delegate));
+}
+
+void BrowserAppShelfController::SetShelfItemClosed(const ash::ShelfID& id) {
+  const ash::ShelfItem* item = model_.ItemByID(id);
+  if (!item) {
+    // There is no shelf item for unpinned apps running in a browser tab.
+    return;
+  }
+
+  if (ash::IsPinnedShelfItemType(item->type)) {
+    UpdateShelfItemStatus(*item, ash::STATUS_CLOSED);
+  } else {
+    int index = model_.ItemIndexByID(id);
+    model_.RemoveItemAt(index);
+  }
+}
+
+void BrowserAppShelfController::MaybeUpdateBrowserWindowProperties(
+    aura::Window* window) {
+  // If it's a browser window, this app ID will be used as app ID and/or shelf
+  // ID.
+  std::string browser_app_id = crosapi::browser_util::IsLacrosWindow(window)
+                                   ? extension_misc::kLacrosAppId
+                                   : extension_misc::kChromeAppId;
+
+  const apps::BrowserAppInstance* active_instance =
+      browser_app_instance_registry_.GetActiveAppInstanceForWindow(window);
+  // App ID of the window is set to the app ID of the active tab. If the active
+  // tab has no app, window's app ID is set to Chrome's ID.
+  std::string app_id =
+      active_instance ? active_instance->app_id : browser_app_id;
+  MaybeUpdateStringProperty(window, ash::kAppIDKey, app_id);
+
+  // Shelf ID is set to match the app's item on the shelf, if it exists.
+  const ash::ShelfItem* item = model_.ItemByID(ash::ShelfID(app_id));
+  // There is no shelf item for unpinned apps running in a browser tab.
+  ash::ShelfID shelf_id = item ? item->id : ash::ShelfID(browser_app_id);
+  MaybeUpdateStringProperty(window, ash::kShelfIDKey, shelf_id.Serialize());
+}
diff --git a/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.h b/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.h
new file mode 100644
index 0000000..5cd7a88
--- /dev/null
+++ b/chrome/browser/ui/ash/shelf/browser_app_shelf_controller.h
@@ -0,0 +1,86 @@
+// 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_ASH_SHELF_BROWSER_APP_SHELF_CONTROLLER_H_
+#define CHROME_BROWSER_UI_ASH_SHELF_BROWSER_APP_SHELF_CONTROLLER_H_
+
+#include "ash/public/cpp/shelf_types.h"
+#include "base/scoped_observation.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_observer.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_registry.h"
+
+namespace apps {
+struct BrowserAppInstance;
+class BrowserAppInstanceRegistry;
+}  // namespace apps
+
+namespace ash {
+class ShelfModel;
+struct ShelfItem;
+}  // namespace ash
+
+namespace aura {
+class Window;
+}
+
+class ShelfSpinnerController;
+class ChromeShelfItemFactory;
+
+// Updates the shelf model in response to |BrowserAppInstanceRegistry| events.
+//
+// Observes the |BrowserAppInstanceRegistry| for lifecycle events of
+// - browser-based apps in tabs and windows (web apps, system web apps) in Ash
+//   and Lacros,
+// - browser windows in Ash and Lacros.
+//
+// Updates to the shelf model:
+// - sets shelf item status when an app is running or stopped,
+// - creates or removes shelf items when necessary.
+class BrowserAppShelfController : public apps::BrowserAppInstanceObserver {
+ public:
+  BrowserAppShelfController(Profile* profile,
+                            ash::ShelfModel& model,
+                            ChromeShelfItemFactory& shelf_item_factory,
+                            ShelfSpinnerController& shelf_spinner_controller);
+
+  BrowserAppShelfController(const BrowserAppShelfController&) = delete;
+  BrowserAppShelfController& operator=(const BrowserAppShelfController&) =
+      delete;
+
+  ~BrowserAppShelfController() override;
+
+  // apps::BrowserAppInstanceObserver overrides:
+  void OnBrowserWindowAdded(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserWindowRemoved(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserAppAdded(const apps::BrowserAppInstance& instance) override;
+  void OnBrowserAppUpdated(const apps::BrowserAppInstance& instance) override;
+  void OnBrowserAppRemoved(const apps::BrowserAppInstance& instance) override;
+
+ private:
+  // Creates a shelf item if it doesn't exist and sets its status.
+  void CreateOrUpdateShelfItem(const ash::ShelfID& id,
+                               ash::ShelfItemStatus status);
+  // Sets shelf item status to closed and removes it if it's not pinned.
+  void SetShelfItemClosed(const ash::ShelfID& id);
+  void UpdateShelfItemStatus(const ash::ShelfItem& item,
+                             ash::ShelfItemStatus status);
+  // Updates Aura window's app-related keys when the active app associated with
+  // this window changes.
+  void MaybeUpdateBrowserWindowProperties(aura::Window* window);
+
+  Profile* profile_;
+  ash::ShelfModel& model_;
+  ChromeShelfItemFactory& shelf_item_factory_;
+  ShelfSpinnerController& shelf_spinner_controller_;
+
+  apps::BrowserAppInstanceRegistry& browser_app_instance_registry_;
+
+  base::ScopedObservation<apps::BrowserAppInstanceRegistry,
+                          apps::BrowserAppInstanceObserver>
+      registry_observation_{this};
+};
+
+#endif  // CHROME_BROWSER_UI_ASH_SHELF_BROWSER_APP_SHELF_CONTROLLER_H_
diff --git a/chrome/browser/ui/ash/shelf/browser_app_shelf_item_controller.cc b/chrome/browser/ui/ash/shelf/browser_app_shelf_item_controller.cc
new file mode 100644
index 0000000..948aa08
--- /dev/null
+++ b/chrome/browser/ui/ash/shelf/browser_app_shelf_item_controller.cc
@@ -0,0 +1,201 @@
+// 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/ash/shelf/browser_app_shelf_item_controller.h"
+
+#include "base/memory/weak_ptr.h"
+#include "base/notreached.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/unguessable_token.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_chromeos.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_registry.h"
+#include "chrome/browser/ash/crosapi/browser_util.h"
+#include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h"
+#include "chrome/browser/ui/ash/shelf/shelf_context_menu.h"
+#include "extensions/common/constants.h"
+#include "ui/aura/client/aura_constants.h"
+
+BrowserAppShelfItemController::BrowserAppShelfItemController(
+    const ash::ShelfID& shelf_id,
+    Profile* profile)
+    : ash::ShelfItemDelegate(shelf_id),
+      profile_(profile),
+      registry_(*apps::AppServiceProxyFactory::GetForProfile(profile_)
+                     ->BrowserAppInstanceRegistry()) {
+  registry_observation_.Observe(&registry_);
+  LoadAppMenuIcon();
+}
+
+BrowserAppShelfItemController::~BrowserAppShelfItemController() = default;
+
+void BrowserAppShelfItemController::ItemSelected(
+    std::unique_ptr<ui::Event> event,
+    int64_t display_id,
+    ash::ShelfLaunchSource source,
+    ItemSelectedCallback callback,
+    const ItemFilterPredicate& filter_predicate) {
+  auto instances = GetMatchingInstances(filter_predicate);
+  switch (instances.size()) {
+    case 0:
+      // Nothing is running, launch.
+      std::move(callback).Run(ash::SHELF_ACTION_NEW_WINDOW_CREATED, {});
+      ChromeShelfController::instance()->LaunchApp(
+          ash::ShelfID(shelf_id()), source, ui::EF_NONE, display_id);
+      break;
+    case 1:
+      // One instance is running, activate it.
+      // TODO(crbug.com/1203992): Implement instance activation.
+      NOTIMPLEMENTED();
+      FALLTHROUGH;  // for now to finish with a callback
+    default:
+      // Multiple instances activated, show the list of running instances.
+      std::move(callback).Run(
+          ash::SHELF_ACTION_NONE,
+          GetAppMenuItems(event ? event->flags() : ui::EF_NONE,
+                          filter_predicate));
+      break;
+  }
+}
+
+BrowserAppShelfItemController::AppMenuItems
+BrowserAppShelfItemController::GetAppMenuItems(
+    int event_flags,
+    const ItemFilterPredicate& filter_predicate) {
+  AppMenuItems items;
+  for (const auto& pair : GetMatchingInstances(filter_predicate)) {
+    int command_id = pair.first;
+    base::UnguessableToken id = pair.second;
+    if (shelf_id().app_id == extension_misc::kLacrosAppId) {
+      const apps::BrowserWindowInstance* instance =
+          registry_.GetBrowserWindowInstanceById(id);
+      DCHECK(instance);
+      items.push_back({command_id, instance->window->GetTitle(), menu_icon_});
+    } else {
+      const apps::BrowserAppInstance* instance =
+          registry_.GetAppInstanceById(id);
+      DCHECK(instance);
+      items.push_back(
+          {command_id, base::UTF8ToUTF16(instance->title), menu_icon_});
+    }
+  }
+  return items;
+}
+
+void BrowserAppShelfItemController::GetContextMenu(
+    int64_t display_id,
+    GetContextMenuCallback callback) {
+  ChromeShelfController* controller = ChromeShelfController::instance();
+  const ash::ShelfItem* item = controller->GetItem(shelf_id());
+  context_menu_ = ShelfContextMenu::Create(controller, item, display_id);
+  context_menu_->GetMenuModel(std::move(callback));
+}
+
+void BrowserAppShelfItemController::ExecuteCommand(bool from_context_menu,
+                                                   int64_t command_id,
+                                                   int32_t event_flags,
+                                                   int64_t display_id) {
+  // Item selected from menu.
+  // TODO(crbug.com/1203992): Implement instance activation.
+  NOTIMPLEMENTED();
+}
+
+void BrowserAppShelfItemController::Close() {
+  apps::AppServiceProxyFactory::GetForProfile(profile_)->StopApp(
+      shelf_id().app_id);
+}
+
+void BrowserAppShelfItemController::OnBrowserWindowAdded(
+    const apps::BrowserWindowInstance& instance) {
+  if (!(shelf_id().app_id == extension_misc::kLacrosAppId &&
+        crosapi::browser_util::IsLacrosWindow(instance.window))) {
+    // Only handle Lacros browser windows.
+    return;
+  }
+  int command = ++last_command_id_;
+  command_to_instance_map_[command] = instance.id;
+}
+
+void BrowserAppShelfItemController::OnBrowserWindowRemoved(
+    const apps::BrowserWindowInstance& instance) {
+  if (!(shelf_id().app_id == extension_misc::kLacrosAppId &&
+        crosapi::browser_util::IsLacrosWindow(instance.window))) {
+    // Only handle Lacros browser windows.
+    return;
+  }
+  int command = GetInstanceCommand(instance.id);
+  command_to_instance_map_.erase(command);
+}
+
+void BrowserAppShelfItemController::OnBrowserAppAdded(
+    const apps::BrowserAppInstance& instance) {
+  if (shelf_id().app_id != instance.app_id) {
+    return;
+  }
+  int command = ++last_command_id_;
+  command_to_instance_map_[command] = instance.id;
+}
+
+void BrowserAppShelfItemController::OnBrowserAppRemoved(
+    const apps::BrowserAppInstance& instance) {
+  if (shelf_id().app_id != instance.app_id) {
+    return;
+  }
+  int command = GetInstanceCommand(instance.id);
+  command_to_instance_map_.erase(command);
+}
+
+std::vector<std::pair<int, base::UnguessableToken>>
+BrowserAppShelfItemController::GetMatchingInstances(
+    const ItemFilterPredicate& filter_predicate) {
+  // Iterating the map keyed by command ID, so the instances are automatically
+  // sorted by launch order.
+  std::vector<std::pair<int, base::UnguessableToken>> result;
+  for (const auto& pair : command_to_instance_map_) {
+    base::UnguessableToken id = pair.second;
+    aura::Window* window = nullptr;
+    if (shelf_id().app_id == extension_misc::kLacrosAppId) {
+      const apps::BrowserWindowInstance* instance =
+          registry_.GetBrowserWindowInstanceById(id);
+      DCHECK(instance);
+      window = instance->window;
+    } else {
+      const apps::BrowserAppInstance* instance =
+          registry_.GetAppInstanceById(id);
+      DCHECK(instance);
+      window = instance->window;
+    }
+    if (filter_predicate.is_null() || filter_predicate.Run(window)) {
+      result.push_back(pair);
+    }
+  }
+  return result;
+}
+
+int BrowserAppShelfItemController::GetInstanceCommand(
+    const base::UnguessableToken& id) {
+  auto it = base::ranges::find_if(
+      command_to_instance_map_,
+      [&id](const auto& pair) { return pair.second == id; });
+  DCHECK(it != command_to_instance_map_.end());
+  return it->first;
+}
+
+void BrowserAppShelfItemController::LoadAppMenuIcon() {
+  const std::string& app_id = shelf_id().app_id;
+  auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile_);
+  icon_loader_releaser_ = proxy->LoadIcon(
+      proxy->AppRegistryCache().GetAppType(app_id), app_id,
+      apps::mojom::IconType::kStandard,
+      // matches favicon size
+      /* size_hint_in_dip= */ extension_misc::EXTENSION_ICON_BITTY,
+      /* allow_placeholder_icon= */ false,
+      base::BindOnce(&BrowserAppShelfItemController::DidLoadAppMenuIcon,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BrowserAppShelfItemController::DidLoadAppMenuIcon(
+    apps::mojom::IconValuePtr icon_value) {
+  menu_icon_ = icon_value->uncompressed;
+}
diff --git a/chrome/browser/ui/ash/shelf/browser_app_shelf_item_controller.h b/chrome/browser/ui/ash/shelf/browser_app_shelf_item_controller.h
new file mode 100644
index 0000000..707cde49
--- /dev/null
+++ b/chrome/browser/ui/ash/shelf/browser_app_shelf_item_controller.h
@@ -0,0 +1,101 @@
+// 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_ASH_SHELF_BROWSER_APP_SHELF_ITEM_CONTROLLER_H_
+#define CHROME_BROWSER_UI_ASH_SHELF_BROWSER_APP_SHELF_ITEM_CONTROLLER_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "ash/public/cpp/shelf_item_delegate.h"
+#include "base/containers/flat_map.h"
+#include "base/scoped_observation.h"
+#include "base/unguessable_token.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_observer.h"
+#include "chrome/browser/apps/app_service/browser_app_instance_registry.h"
+#include "components/services/app_service/public/cpp/icon_loader.h"
+#include "components/services/app_service/public/mojom/types.mojom.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace apps {
+class BrowserAppInstanceRegistry;
+}
+
+class Profile;
+class ShelfContextMenu;
+
+class BrowserAppShelfItemController : public ash::ShelfItemDelegate,
+                                      public apps::BrowserAppInstanceObserver {
+ public:
+  BrowserAppShelfItemController(const ash::ShelfID& shelf_id, Profile* profile);
+
+  BrowserAppShelfItemController(const BrowserAppShelfItemController&) = delete;
+  BrowserAppShelfItemController& operator=(
+      const BrowserAppShelfItemController&) = delete;
+
+  ~BrowserAppShelfItemController() override;
+
+  // ash::ShelfItemDelegate overrides:
+  void ItemSelected(std::unique_ptr<ui::Event> event,
+                    int64_t display_id,
+                    ash::ShelfLaunchSource source,
+                    ItemSelectedCallback callback,
+                    const ItemFilterPredicate& filter_predicate) override;
+  AppMenuItems GetAppMenuItems(
+      int event_flags,
+      const ItemFilterPredicate& filter_predicate) override;
+  void GetContextMenu(int64_t display_id,
+                      GetContextMenuCallback callback) override;
+  void ExecuteCommand(bool from_context_menu,
+                      int64_t command_id,
+                      int32_t event_flags,
+                      int64_t display_id) override;
+  void Close() override;
+
+  // BrowserAppInstanceObserver overrides:
+  void OnBrowserWindowAdded(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserWindowRemoved(
+      const apps::BrowserWindowInstance& instance) override;
+  void OnBrowserAppAdded(const apps::BrowserAppInstance& instance) override;
+  void OnBrowserAppRemoved(const apps::BrowserAppInstance& instance) override;
+
+ private:
+  // Gets a list of instances (a pair of app menu command ID and instance ID)
+  // matching the predicate.
+  std::vector<std::pair<int, base::UnguessableToken>> GetMatchingInstances(
+      const ItemFilterPredicate& filter_predicate);
+  // Gets the command ID for this item. The item must exist.
+  int GetInstanceCommand(const base::UnguessableToken& id);
+
+  void LoadAppMenuIcon();
+  void DidLoadAppMenuIcon(apps::mojom::IconValuePtr icon_value);
+
+  Profile* profile_;
+  apps::BrowserAppInstanceRegistry& registry_;
+
+  // ShelfContextMenu instance needs to be alive for the duration of the
+  // GetMenuModel call.
+  std::unique_ptr<ShelfContextMenu> context_menu_;
+
+  std::unique_ptr<apps::IconLoader::Releaser> icon_loader_releaser_;
+  gfx::ImageSkia menu_icon_;
+
+  // Map of app menu item command IDs to instance IDs, used to maintain a stable
+  // association of instances to command IDs and to order the items by launch
+  // time. The set of instances is usually under 10 items so a flat map is
+  // sufficient.
+  base::flat_map<int, base::UnguessableToken> command_to_instance_map_;
+  int last_command_id_{0};
+
+  base::ScopedObservation<apps::BrowserAppInstanceRegistry,
+                          apps::BrowserAppInstanceObserver>
+      registry_observation_{this};
+
+  base::WeakPtrFactory<BrowserAppShelfItemController> weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_UI_ASH_SHELF_BROWSER_APP_SHELF_ITEM_CONTROLLER_H_
diff --git a/chrome/browser/ui/ash/shelf/browser_status_monitor.cc b/chrome/browser/ui/ash/shelf/browser_status_monitor.cc
index b99be7ba..e2f8956 100644
--- a/chrome/browser/ui/ash/shelf/browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/shelf/browser_status_monitor.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
+#include "chrome/common/chrome_features.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
@@ -121,6 +122,9 @@
 }
 
 void BrowserStatusMonitor::ActiveUserChanged(const std::string& user_email) {
+  if (base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    return;
+  }
   // When the active profile changes, all windowed and tabbed apps owned by the
   // newly selected profile are added to the shelf, and the ones owned by other
   // profiles are removed.
@@ -170,6 +174,7 @@
 
 void BrowserStatusMonitor::UpdateAppItemState(content::WebContents* contents,
                                               bool remove) {
+  DCHECK(!base::FeatureList::IsEnabled(features::kWebAppsCrosapi));
   DCHECK(contents);
   DCHECK(initialized_);
   // It is possible to come here from Browser::SwapTabContent where the contents
@@ -183,6 +188,7 @@
 }
 
 void BrowserStatusMonitor::UpdateBrowserItemState() {
+  DCHECK(!base::FeatureList::IsEnabled(features::kWebAppsCrosapi));
   DCHECK(initialized_);
   shelf_controller_->UpdateBrowserItemState();
 }
@@ -194,9 +200,11 @@
   DCHECK(insert_result.second);
 #endif
 
-  if (IsAppBrowser(browser) &&
-      multi_user_util::IsProfileFromActiveUser(browser->profile())) {
-    AddAppBrowserToShelf(browser);
+  if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    if (IsAppBrowser(browser) &&
+        multi_user_util::IsProfileFromActiveUser(browser->profile())) {
+      AddAppBrowserToShelf(browser);
+    }
   }
 }
 
@@ -207,12 +215,14 @@
   DCHECK_EQ(num_removed, 1U);
 #endif
 
-  if (IsAppBrowser(browser) &&
-      multi_user_util::IsProfileFromActiveUser(browser->profile())) {
-    RemoveAppBrowserFromShelf(browser);
-  }
+  if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    if (IsAppBrowser(browser) &&
+        multi_user_util::IsProfileFromActiveUser(browser->profile())) {
+      RemoveAppBrowserFromShelf(browser);
+    }
 
-  UpdateBrowserItemState();
+    UpdateBrowserItemState();
+  }
   if (app_service_instance_helper_)
     app_service_instance_helper_->OnBrowserRemoved();
 }
@@ -246,7 +256,9 @@
         OnTabInserted(tab_strip_model, contents.contents);
       }
     }
-    UpdateBrowserItemState();
+    if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+      UpdateBrowserItemState();
+    }
   } else if (change.type() == TabStripModelChange::kRemoved) {
     auto* remove = change.GetRemove();
     for (const auto& contents : remove->contents) {
@@ -289,6 +301,7 @@
 }
 
 void BrowserStatusMonitor::AddAppBrowserToShelf(Browser* browser) {
+  DCHECK(!base::FeatureList::IsEnabled(features::kWebAppsCrosapi));
   DCHECK(IsAppBrowser(browser));
   DCHECK(initialized_);
 
@@ -305,6 +318,7 @@
 }
 
 void BrowserStatusMonitor::RemoveAppBrowserFromShelf(Browser* browser) {
+  DCHECK(!base::FeatureList::IsEnabled(features::kWebAppsCrosapi));
   DCHECK(IsAppBrowser(browser));
   DCHECK(initialized_);
 
@@ -318,11 +332,13 @@
 }
 
 bool BrowserStatusMonitor::IsAppBrowserInShelf(Browser* browser) {
+  DCHECK(!base::FeatureList::IsEnabled(features::kWebAppsCrosapi));
   return browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end();
 }
 
 bool BrowserStatusMonitor::IsAppBrowserInShelfWithAppId(
     const std::string& app_id) {
+  DCHECK(!base::FeatureList::IsEnabled(features::kWebAppsCrosapi));
   for (const auto& iter : browser_to_app_id_map_) {
     if (iter.second == app_id)
       return true;
@@ -333,22 +349,24 @@
 void BrowserStatusMonitor::OnActiveTabChanged(
     content::WebContents* old_contents,
     content::WebContents* new_contents) {
-  Browser* browser = nullptr;
-  // Use |new_contents|. |old_contents| could be nullptr.
-  DCHECK(new_contents);
-  browser = chrome::FindBrowserWithWebContents(new_contents);
+  if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    Browser* browser = nullptr;
+    // Use |new_contents|. |old_contents| could be nullptr.
+    DCHECK(new_contents);
+    browser = chrome::FindBrowserWithWebContents(new_contents);
 
-  // Update immediately on a tab change.
-  if (old_contents &&
-      (TabStripModel::kNoTab !=
-       browser->tab_strip_model()->GetIndexOfWebContents(old_contents))) {
-    UpdateAppItemState(old_contents, false /*remove*/);
-  }
+    // Update immediately on a tab change.
+    if (old_contents &&
+        (TabStripModel::kNoTab !=
+         browser->tab_strip_model()->GetIndexOfWebContents(old_contents))) {
+      UpdateAppItemState(old_contents, false /*remove*/);
+    }
 
-  if (new_contents) {
-    UpdateAppItemState(new_contents, false /*remove*/);
-    UpdateBrowserItemState();
-    SetShelfIDForBrowserWindowContents(browser, new_contents);
+    if (new_contents) {
+      UpdateAppItemState(new_contents, false /*remove*/);
+      UpdateBrowserItemState();
+      SetShelfIDForBrowserWindowContents(browser, new_contents);
+    }
   }
 
   if (app_service_instance_helper_) {
@@ -360,51 +378,57 @@
 void BrowserStatusMonitor::OnTabReplaced(TabStripModel* tab_strip_model,
                                          content::WebContents* old_contents,
                                          content::WebContents* new_contents) {
-  DCHECK(old_contents && new_contents);
-  Browser* browser = chrome::FindBrowserWithWebContents(new_contents);
+  if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    DCHECK(old_contents && new_contents);
+    Browser* browser = chrome::FindBrowserWithWebContents(new_contents);
 
-  UpdateAppItemState(old_contents, true /*remove*/);
-  RemoveWebContentsObserver(old_contents);
+    UpdateAppItemState(old_contents, true /*remove*/);
+    RemoveWebContentsObserver(old_contents);
 
-  UpdateAppItemState(new_contents, false /*remove*/);
-  UpdateBrowserItemState();
+    UpdateAppItemState(new_contents, false /*remove*/);
+    UpdateBrowserItemState();
 
-  if (browser && IsAppBrowserInShelf(browser) &&
-      multi_user_util::IsProfileFromActiveUser(browser->profile())) {
-    shelf_controller_->SetAppStatus(
-        web_app::GetAppIdFromApplicationName(browser->app_name()),
-        ash::STATUS_RUNNING);
+    if (browser && IsAppBrowserInShelf(browser) &&
+        multi_user_util::IsProfileFromActiveUser(browser->profile())) {
+      shelf_controller_->SetAppStatus(
+          web_app::GetAppIdFromApplicationName(browser->app_name()),
+          ash::STATUS_RUNNING);
+    }
+
+    if (tab_strip_model->GetActiveWebContents() == new_contents)
+      SetShelfIDForBrowserWindowContents(browser, new_contents);
+
+    AddWebContentsObserver(new_contents);
   }
 
-  if (tab_strip_model->GetActiveWebContents() == new_contents)
-    SetShelfIDForBrowserWindowContents(browser, new_contents);
-
-  AddWebContentsObserver(new_contents);
-
   if (app_service_instance_helper_)
     app_service_instance_helper_->OnTabReplaced(old_contents, new_contents);
 }
 
 void BrowserStatusMonitor::OnTabInserted(TabStripModel* tab_strip_model,
                                          content::WebContents* contents) {
-  UpdateAppItemState(contents, false /*remove*/);
-  // If the contents does not have a visible navigation entry, wait until a
-  // navigation status changes before setting the browser window Shelf ID
-  // (done by the web contents observer added by AddWebContentsObserver()).
-  if (tab_strip_model->GetActiveWebContents() == contents &&
-      contents->GetController().GetVisibleEntry()) {
-    Browser* browser = chrome::FindBrowserWithWebContents(contents);
-    SetShelfIDForBrowserWindowContents(browser, contents);
-  }
+  if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    UpdateAppItemState(contents, false /*remove*/);
+    // If the contents does not have a visible navigation entry, wait until a
+    // navigation status changes before setting the browser window Shelf ID
+    // (done by the web contents observer added by AddWebContentsObserver()).
+    if (tab_strip_model->GetActiveWebContents() == contents &&
+        contents->GetController().GetVisibleEntry()) {
+      Browser* browser = chrome::FindBrowserWithWebContents(contents);
+      SetShelfIDForBrowserWindowContents(browser, contents);
+    }
 
-  AddWebContentsObserver(contents);
+    AddWebContentsObserver(contents);
+  }
   if (app_service_instance_helper_)
     app_service_instance_helper_->OnTabInserted(contents);
 }
 
 void BrowserStatusMonitor::OnTabClosing(content::WebContents* contents) {
-  UpdateAppItemState(contents, true /*remove*/);
-  RemoveWebContentsObserver(contents);
+  if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    UpdateAppItemState(contents, true /*remove*/);
+    RemoveWebContentsObserver(contents);
+  }
   if (app_service_instance_helper_)
     app_service_instance_helper_->OnTabClosing(contents);
 }
@@ -417,6 +441,9 @@
 
 void BrowserStatusMonitor::OnTabNavigationFinished(
     content::WebContents* contents) {
+  if (base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    return;
+  }
   UpdateAppItemState(contents, false /*remove*/);
   UpdateBrowserItemState();
 
@@ -447,7 +474,10 @@
 void BrowserStatusMonitor::SetShelfIDForBrowserWindowContents(
     Browser* browser,
     content::WebContents* web_contents) {
-  shelf_controller_->SetShelfIDForBrowserWindowContents(browser, web_contents);
+  if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    shelf_controller_->SetShelfIDForBrowserWindowContents(browser,
+                                                          web_contents);
+  }
 
   if (app_service_instance_helper_) {
     app_service_instance_helper_->OnSetShelfIDForBrowserWindowContents(
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
index a01c2e0..14a42179 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.cc
@@ -36,7 +36,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/browser_app_instance_tracker.h"
 #include "chrome/browser/apps/icon_standardizer.h"
 #include "chrome/browser/ash/arc/arc_util.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
@@ -51,7 +50,6 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/app_list/md_icon_normalizer.h"
 #include "chrome/browser/ui/apps/app_info_dialog.h"
-#include "chrome/browser/ui/ash/shelf/chrome_shelf_prefs.h"
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
@@ -63,10 +61,12 @@
 #include "chrome/browser/ui/ash/shelf/app_shortcut_shelf_item_controller.h"
 #include "chrome/browser/ui/ash/shelf/app_window_shelf_controller.h"
 #include "chrome/browser/ui/ash/shelf/app_window_shelf_item_controller.h"
+#include "chrome/browser/ui/ash/shelf/browser_app_shelf_controller.h"
 #include "chrome/browser/ui/ash/shelf/browser_shortcut_shelf_item_controller.h"
 #include "chrome/browser/ui/ash/shelf/browser_status_monitor.h"
 #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller_util.h"
 #include "chrome/browser/ui/ash/shelf/chrome_shelf_item_factory.h"
+#include "chrome/browser/ui/ash/shelf/chrome_shelf_prefs.h"
 #include "chrome/browser/ui/ash/shelf/shelf_controller_helper.h"
 #include "chrome/browser/ui/ash/shelf/shelf_extension_app_updater.h"
 #include "chrome/browser/ui/ash/shelf/shelf_spinner_controller.h"
@@ -253,10 +253,9 @@
   app_window_controllers_.emplace_back(std::move(app_service_controller));
   // Create the browser monitor which will inform the shelf of status changes.
   browser_status_monitor_ = std::make_unique<BrowserStatusMonitor>(this);
-  if (base::FeatureList::IsEnabled(features::kBrowserAppInstanceTracking)) {
-    browser_app_instance_tracker_ =
-        apps::AppServiceProxyFactory::GetForProfile(profile)
-            ->BrowserAppInstanceTracker();
+  if (base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    browser_app_shelf_controller_ = std::make_unique<BrowserAppShelfController>(
+        profile, *model_, *shelf_item_factory_, *shelf_spinner_controller_);
   }
 }
 
@@ -547,12 +546,6 @@
   AttachProfile(ProfileManager::GetActiveUserProfile());
   // Update the V1 applications.
   browser_status_monitor_->ActiveUserChanged(account_id.GetUserEmail());
-  // Switch app tracker instance.
-  if (base::FeatureList::IsEnabled(features::kBrowserAppInstanceTracking)) {
-    browser_app_instance_tracker_ = apps::AppServiceProxyFactory::GetForProfile(
-                                        ProfileManager::GetActiveUserProfile())
-                                        ->BrowserAppInstanceTracker();
-  }
   // Save/restore spinners belonging to the old/new user. Must be called before
   // notifying the AppWindowControllers, as some of them assume spinners owned
   // by the new user have already been added to the shelf.
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.h b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.h
index 046102e1..b4f490d 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller.h
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller.h
@@ -38,10 +38,6 @@
 class ShelfControllerHelper;
 class ShelfSpinnerController;
 
-namespace apps {
-class BrowserAppInstanceTracker;
-}
-
 namespace ash {
 class ShelfModel;
 FORWARD_DECLARE_TEST(SpokenFeedbackTest, ShelfIconFocusForward);
@@ -60,6 +56,8 @@
 class BaseWindow;
 }
 
+class BrowserAppShelfController;
+
 // ChromeShelfController helps manage Ash's shelf for Chrome prefs and apps.
 // It helps synchronize shelf state with profile preferences and app content.
 class ChromeShelfController
@@ -462,9 +460,6 @@
   // The owned browser status monitor.
   std::unique_ptr<BrowserStatusMonitor> browser_status_monitor_;
 
-  // The browser app instance tracker for the current profile.
-  apps::BrowserAppInstanceTracker* browser_app_instance_tracker_{nullptr};
-
   // A special observer class to detect user switches.
   std::unique_ptr<ChromeShelfControllerUserSwitchObserver>
       user_switch_observer_;
@@ -474,6 +469,9 @@
   // Responsible for bridging between the shelf and sync/prefs.
   std::unique_ptr<ChromeShelfPrefs> shelf_prefs_;
 
+  // Manages shelf item for browser-based apps and Lacros.
+  std::unique_ptr<BrowserAppShelfController> browser_app_shelf_controller_;
+
   // The list of running & un-pinned applications for different users on hidden
   // desktops.
   using RunningAppListIds = std::vector<std::string>;
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_item_factory.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_item_factory.cc
index f67a544..05a1c5a7 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_item_factory.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_item_factory.cc
@@ -6,9 +6,15 @@
 
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/public/cpp/shelf_types.h"
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/shelf/app_shortcut_shelf_item_controller.h"
 #include "chrome/browser/ui/ash/shelf/arc_playstore_shortcut_shelf_item_controller.h"
+#include "chrome/browser/ui/ash/shelf/browser_app_shelf_item_controller.h"
+#include "chrome/common/chrome_features.h"
+#include "components/services/app_service/public/cpp/types_util.h"
 
 ChromeShelfItemFactory::ChromeShelfItemFactory() = default;
 
@@ -28,6 +34,25 @@
     return true;
   }
 
+  if (base::FeatureList::IsEnabled(features::kWebAppsCrosapi)) {
+    Profile* profile = ProfileManager::GetPrimaryUserProfile();
+    auto* proxy =
+        apps::AppServiceProxyFactory::GetInstance()->GetForProfile(profile);
+    apps::mojom::AppType app_type =
+        proxy->AppRegistryCache().GetAppType(app_id);
+    switch (app_type) {
+      case apps::mojom::AppType::kWeb:
+      case apps::mojom::AppType::kSystemWeb:
+      case apps::mojom::AppType::kStandaloneBrowser:
+        *delegate =
+            std::make_unique<BrowserAppShelfItemController>(shelf_id, profile);
+        return true;
+      default:
+        // Ignore the rest.
+        break;
+    }
+  }
+
   *delegate = std::make_unique<AppShortcutShelfItemController>(shelf_id);
   return true;
 }
diff --git a/chrome/browser/ui/aura/accessibility/DIR_METADATA b/chrome/browser/ui/aura/accessibility/DIR_METADATA
index 299fade..c775858 100644
--- a/chrome/browser/ui/aura/accessibility/DIR_METADATA
+++ b/chrome/browser/ui/aura/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail {
   component: "UI>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/chrome/browser/ui/blocked_content/DIR_METADATA b/chrome/browser/ui/blocked_content/DIR_METADATA
index 7353851..42e50743 100644
--- a/chrome/browser/ui/blocked_content/DIR_METADATA
+++ b/chrome/browser/ui/blocked_content/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>PopupBlocker"
-}
+mixins: "//components/blocked_content/COMMON_METADATA"
diff --git a/chrome/browser/ui/bluetooth/DIR_METADATA b/chrome/browser/ui/bluetooth/DIR_METADATA
index 488eb98..cd51015 100644
--- a/chrome/browser/ui/bluetooth/DIR_METADATA
+++ b/chrome/browser/ui/bluetooth/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Bluetooth"
-}
-team_email: "web-bluetooth@chromium.org"
+mixins: "//content/browser/bluetooth/COMMON_METADATA"
diff --git a/chrome/browser/ui/download/DIR_METADATA b/chrome/browser/ui/download/DIR_METADATA
new file mode 100644
index 0000000..8b1c141
--- /dev/null
+++ b/chrome/browser/ui/download/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/download/COMMON_METADATA"
diff --git a/chrome/browser/ui/extensions/COMMON_METADATA b/chrome/browser/ui/extensions/COMMON_METADATA
new file mode 100644
index 0000000..81a57a13
--- /dev/null
+++ b/chrome/browser/ui/extensions/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Platform>Extensions"
+}
+team_email: "extensions-dev@chromium.org"
diff --git a/chrome/browser/ui/extensions/DIR_METADATA b/chrome/browser/ui/extensions/DIR_METADATA
index 81a57a13..49d375e 100644
--- a/chrome/browser/ui/extensions/DIR_METADATA
+++ b/chrome/browser/ui/extensions/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Platform>Extensions"
-}
-team_email: "extensions-dev@chromium.org"
+mixins: "//chrome/browser/ui/extensions/COMMON_METADATA"
diff --git a/chrome/browser/ui/font_access/DIR_METADATA b/chrome/browser/ui/font_access/DIR_METADATA
index 77e8c1c9..be579e99 100644
--- a/chrome/browser/ui/font_access/DIR_METADATA
+++ b/chrome/browser/ui/font_access/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>Storage>FontAccess"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/font_access/COMMON_METADATA"
diff --git a/chrome/browser/ui/global_media_controls/COMMON_METADATA b/chrome/browser/ui/global_media_controls/COMMON_METADATA
new file mode 100644
index 0000000..85c8924d
--- /dev/null
+++ b/chrome/browser/ui/global_media_controls/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Media>UI"
+}
diff --git a/chrome/browser/ui/global_media_controls/DIR_METADATA b/chrome/browser/ui/global_media_controls/DIR_METADATA
index 85c8924d..1a2e67ff 100644
--- a/chrome/browser/ui/global_media_controls/DIR_METADATA
+++ b/chrome/browser/ui/global_media_controls/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Media>UI"
-}
+mixins: "//chrome/browser/ui/global_media_controls/COMMON_METADATA"
diff --git a/chrome/browser/ui/hid/DIR_METADATA b/chrome/browser/ui/hid/DIR_METADATA
index 5ef1de28..9260825 100644
--- a/chrome/browser/ui/hid/DIR_METADATA
+++ b/chrome/browser/ui/hid/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>HID"
-}
-team_email: "device-dev@chromium.org"
+mixins: "//third_party/blink/renderer/modules/hid/COMMON_METADATA"
diff --git a/chrome/browser/ui/omnibox/DIR_METADATA b/chrome/browser/ui/omnibox/DIR_METADATA
index 07a4669..7a9dec1 100644
--- a/chrome/browser/ui/omnibox/DIR_METADATA
+++ b/chrome/browser/ui/omnibox/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Omnibox"
-}
+mixins: "//components/omnibox/COMMON_METADATA"
diff --git a/chrome/browser/ui/page_action/COMMON_METADATA b/chrome/browser/ui/page_action/COMMON_METADATA
new file mode 100644
index 0000000..0f9cb2b
--- /dev/null
+++ b/chrome/browser/ui/page_action/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Bubbles"
+}
diff --git a/chrome/browser/ui/page_action/DIR_METADATA b/chrome/browser/ui/page_action/DIR_METADATA
index 0f9cb2b..d538d6d8 100644
--- a/chrome/browser/ui/page_action/DIR_METADATA
+++ b/chrome/browser/ui/page_action/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Bubbles"
-}
+mixins: "//chrome/browser/ui/page_action/COMMON_METADATA"
diff --git a/chrome/browser/ui/page_info/COMMON_METADATA b/chrome/browser/ui/page_info/COMMON_METADATA
new file mode 100644
index 0000000..e67d62f
--- /dev/null
+++ b/chrome/browser/ui/page_info/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Bubbles>PageInfo"
+}
+team_email: "security-enamel@chromium.org"
diff --git a/chrome/browser/ui/page_info/DIR_METADATA b/chrome/browser/ui/page_info/DIR_METADATA
index e67d62f..aed523b0 100644
--- a/chrome/browser/ui/page_info/DIR_METADATA
+++ b/chrome/browser/ui/page_info/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Bubbles>PageInfo"
-}
-team_email: "security-enamel@chromium.org"
+mixins: "//chrome/browser/ui/page_info/COMMON_METADATA"
diff --git a/chrome/browser/ui/pdf/DIR_METADATA b/chrome/browser/ui/pdf/DIR_METADATA
new file mode 100644
index 0000000..0563e2c
--- /dev/null
+++ b/chrome/browser/ui/pdf/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//pdf/COMMON_METADATA"
diff --git a/chrome/browser/ui/search/DIR_METADATA b/chrome/browser/ui/search/DIR_METADATA
new file mode 100644
index 0000000..10d7b81
--- /dev/null
+++ b/chrome/browser/ui/search/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/search/COMMON_METADATA"
diff --git a/chrome/browser/ui/search_engines/DIR_METADATA b/chrome/browser/ui/search_engines/DIR_METADATA
index 4bbdcae..1249d12 100644
--- a/chrome/browser/ui/search_engines/DIR_METADATA
+++ b/chrome/browser/ui/search_engines/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Search"
-}
+mixins: "//components/search_engines/COMMON_METADATA"
diff --git a/chrome/browser/ui/send_tab_to_self/DIR_METADATA b/chrome/browser/ui/send_tab_to_self/DIR_METADATA
index 167ca6e..024779e 100644
--- a/chrome/browser/ui/send_tab_to_self/DIR_METADATA
+++ b/chrome/browser/ui/send_tab_to_self/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Sharing"
-}
+mixins: "//components/send_tab_to_self/COMMON_METADATA"
diff --git a/chrome/browser/ui/serial/DIR_METADATA b/chrome/browser/ui/serial/DIR_METADATA
index 9d970329..423968b 100644
--- a/chrome/browser/ui/serial/DIR_METADATA
+++ b/chrome/browser/ui/serial/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Serial"
-}
+mixins: "//content/browser/serial/COMMON_METADATA"
diff --git a/chrome/browser/ui/signin/DIR_METADATA b/chrome/browser/ui/signin/DIR_METADATA
index 5fad689..95ad5b6 100644
--- a/chrome/browser/ui/signin/DIR_METADATA
+++ b/chrome/browser/ui/signin/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Services>SignIn"
-}
+mixins: "//components/signin/COMMON_METADATA"
diff --git a/chrome/browser/ui/sync/DIR_METADATA b/chrome/browser/ui/sync/DIR_METADATA
index 1a6d7ee6..4a58e65 100644
--- a/chrome/browser/ui/sync/DIR_METADATA
+++ b/chrome/browser/ui/sync/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Services>Sync"
-}
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/chrome/browser/ui/translate/DIR_METADATA b/chrome/browser/ui/translate/DIR_METADATA
new file mode 100644
index 0000000..58ea368c
--- /dev/null
+++ b/chrome/browser/ui/translate/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/translate/COMMON_METADATA"
diff --git a/chrome/browser/ui/user_education/COMMON_METADATA b/chrome/browser/ui/user_education/COMMON_METADATA
new file mode 100644
index 0000000..10bfcfdd
--- /dev/null
+++ b/chrome/browser/ui/user_education/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "UI>Browser>UserEducation"
+}
diff --git a/chrome/browser/ui/user_education/DIR_METADATA b/chrome/browser/ui/user_education/DIR_METADATA
index 10bfcfdd..8a9dcf64 100644
--- a/chrome/browser/ui/user_education/DIR_METADATA
+++ b/chrome/browser/ui/user_education/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>UserEducation"
-}
+mixins: "//chrome/browser/ui/user_education/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/accessibility/DIR_METADATA b/chrome/browser/ui/views/accessibility/DIR_METADATA
index 299fade..c775858 100644
--- a/chrome/browser/ui/views/accessibility/DIR_METADATA
+++ b/chrome/browser/ui/views/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail {
   component: "UI>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index 8175e55..5ccacab 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/ui/views/chrome_typography_provider.h"
 #include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/ui/popup_item_ids.h"
+#include "components/autofill/core/browser/ui/popup_types.h"
 #include "components/autofill/core/browser/ui/suggestion.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/omnibox/browser/vector_icons.h"
@@ -67,16 +68,16 @@
 constexpr int kAutofillPopupMinWidth = kAutofillPopupWidthMultiple * 16;
 // TODO(crbug.com/831603): move handling the max width to the base class.
 constexpr int kAutofillPopupMaxWidth = kAutofillPopupWidthMultiple * 38;
-// TODO(crbug.com/1250729): Rename and cleanup once launched.
-constexpr int kAutofillExperimentalAddressesPopupMaxWidth =
-    kAutofillPopupWidthMultiple * 20;
-constexpr int kAutofillExperimentalCreditCardPopupMaxWidth =
-    kAutofillPopupWidthMultiple * 27;
 
 // Max width for the username and masked password.
 constexpr int kAutofillPopupUsernameMaxWidth = 272;
 constexpr int kAutofillPopupPasswordMaxWidth = 108;
 
+// TODO(crbug.com/1250729): Rename and cleanup once launched.
+constexpr int kAutofillExperimentalPopupMinWidth = 0;
+// Max width for address profile suggestion text.
+constexpr int kAutofillPopupAddressProfileMaxWidth = 192;
+
 // The additional height of the row in case it has two lines of text.
 constexpr int kAutofillPopupAdditionalDoubleRowHeight = 22;
 
@@ -367,16 +368,23 @@
   static AutofillPopupSuggestionView* Create(
       AutofillPopupViewNativeViews* popup_view,
       int line_number,
-      int frontend_id);
+      int frontend_id,
+      PopupType popup_type);
 
  protected:
   // AutofillPopupItemView:
   int GetPrimaryTextStyle() override;
   gfx::Font::Weight GetPrimaryTextWeight() const override;
+  std::unique_ptr<views::Label> CreateMainTextView() override;
   std::vector<std::unique_ptr<views::View>> CreateSubtextViews() override;
   AutofillPopupSuggestionView(AutofillPopupViewNativeViews* popup_view,
                               int line_number,
-                              int frontend_id);
+                              int frontend_id,
+                              PopupType popup_type);
+
+ private:
+  // The popup type to which this suggestion belongs.
+  PopupType popup_type_;
 };
 
 BEGIN_METADATA(AutofillPopupSuggestionView, AutofillPopupItemView)
@@ -797,9 +805,10 @@
 AutofillPopupSuggestionView* AutofillPopupSuggestionView::Create(
     AutofillPopupViewNativeViews* popup_view,
     int line_number,
-    int frontend_id) {
-  AutofillPopupSuggestionView* result =
-      new AutofillPopupSuggestionView(popup_view, line_number, frontend_id);
+    int frontend_id,
+    PopupType popup_type) {
+  AutofillPopupSuggestionView* result = new AutofillPopupSuggestionView(
+      popup_view, line_number, frontend_id, popup_type);
   result->Init();
   return result;
 }
@@ -815,11 +824,24 @@
 AutofillPopupSuggestionView::AutofillPopupSuggestionView(
     AutofillPopupViewNativeViews* popup_view,
     int line_number,
-    int frontend_id)
-    : AutofillPopupItemView(popup_view, line_number, frontend_id) {
+    int frontend_id,
+    PopupType popup_type)
+    : AutofillPopupItemView(popup_view, line_number, frontend_id),
+      popup_type_(popup_type) {
   SetFocusBehavior(FocusBehavior::ALWAYS);
 }
 
+std::unique_ptr<views::Label>
+AutofillPopupSuggestionView::CreateMainTextView() {
+  std::unique_ptr<views::Label> label =
+      AutofillPopupItemView::CreateMainTextView();
+  if (popup_type_ == PopupType::kAddresses &&
+      base::FeatureList::IsEnabled(features::kAutofillTypeSpecificPopupWidth)) {
+    label->SetMaximumWidthSingleLine(kAutofillPopupAddressProfileMaxWidth);
+  }
+  return label;
+}
+
 std::vector<std::unique_ptr<views::View>>
 AutofillPopupSuggestionView::CreateSubtextViews() {
   const std::u16string& second_row_label =
@@ -837,6 +859,11 @@
         text, ChromeTextContext::CONTEXT_DIALOG_BODY_TEXT_SMALL,
         views::style::STYLE_SECONDARY);
     KeepLabel(label.get());
+    if (popup_type_ == PopupType::kAddresses &&
+        base::FeatureList::IsEnabled(
+            features::kAutofillTypeSpecificPopupWidth)) {
+      label->SetMaximumWidthSingleLine(kAutofillPopupAddressProfileMaxWidth);
+    }
     labels.emplace_back(std::move(label));
   }
 
@@ -899,7 +926,10 @@
     AutofillPopupViewNativeViews* popup_view,
     int line_number,
     int frontend_id)
-    : AutofillPopupSuggestionView(popup_view, line_number, frontend_id) {
+    : AutofillPopupSuggestionView(popup_view,
+                                  line_number,
+                                  frontend_id,
+                                  PopupType::kPasswords) {
   origin_ = popup_view->controller()->GetSuggestionLabelAt(line_number);
   masked_password_ =
       popup_view->controller()->GetSuggestionAt(line_number).additional_label;
@@ -1265,8 +1295,8 @@
         break;
 
       default:
-        rows_.push_back(AutofillPopupSuggestionView::Create(this, line_number,
-                                                            frontend_id));
+        rows_.push_back(AutofillPopupSuggestionView::Create(
+            this, line_number, frontend_id, controller_->GetPopupType()));
     }
 
     if (has_footer)
@@ -1334,47 +1364,28 @@
   }
 }
 
-AutofillPopupViewNativeViews::PopupWidthLimits
-AutofillPopupViewNativeViews::GetMinimumAndMaximumPopupWidth() const {
-  // TODO(crbug.com/1250729): Remove once launched.
-  if (!base::FeatureList::IsEnabled(
-          features::kAutofillTypeSpecificPopupWidth)) {
-    return {kAutofillPopupMinWidth, kAutofillPopupMaxWidth};
-  }
-
-  switch (controller_->GetPopupType()) {
-    case PopupType::kAddresses:
-    case PopupType::kPasswords:
-      return {0, kAutofillExperimentalAddressesPopupMaxWidth};
-
-    case PopupType::kCreditCards:
-      return {0, kAutofillExperimentalCreditCardPopupMaxWidth};
-
-    case PopupType::kPersonalInformation:
-    case PopupType::kUnspecified:
-      return {kAutofillPopupMinWidth, kAutofillPopupMaxWidth};
-  }
-}
-
 int AutofillPopupViewNativeViews::AdjustWidth(int width) const {
-  PopupWidthLimits width_limits = GetMinimumAndMaximumPopupWidth();
-
-  if (width >= width_limits.maximum_width)
-    return width_limits.maximum_width;
+  if (width >= kAutofillPopupMaxWidth)
+    return kAutofillPopupMaxWidth;
 
   int elem_width = gfx::ToEnclosingRect(controller_->element_bounds()).width();
 
+  int popup_min_width =
+      base::FeatureList::IsEnabled(features::kAutofillTypeSpecificPopupWidth)
+          ? kAutofillExperimentalPopupMinWidth
+          : kAutofillPopupMinWidth;
+
   // If the element width is within the range of legal sizes for the popup, use
   // it as the min width, so that the popup will align with its edges when
   // possible. Do not use this mechanisms if horizontally-centered popups are
   // enabled and always return the minimum widths.
   // TODO(crbug.com/1250729): Remove this mechanisms once launched.
-  int min_width = (width_limits.minimum_width <= elem_width &&
-                   elem_width < width_limits.maximum_width &&
-                   !base::FeatureList::IsEnabled(
-                       features::kAutofillCenterAlignedSuggestions))
-                      ? elem_width
-                      : width_limits.minimum_width;
+  int min_width =
+      (popup_min_width <= elem_width && elem_width < kAutofillPopupMaxWidth &&
+       !base::FeatureList::IsEnabled(
+           features::kAutofillCenterAlignedSuggestions))
+          ? elem_width
+          : popup_min_width;
 
   if (width <= min_width)
     return min_width;
@@ -1394,7 +1405,6 @@
   gfx::Size preferred_size = CalculatePreferredSize();
   gfx::Rect popup_bounds;
 
-
   // When a bubble border is shown, the contents area (inside the shadow) is
   // supposed to be aligned with input element boundaries.
   gfx::Rect element_bounds =
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h
index c6342c3..c548888 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.h
@@ -102,16 +102,6 @@
   AutofillPopupController* controller() { return controller_; }
 
  private:
-  // Limits for the popup width.
-  struct PopupWidthLimits {
-    int minimum_width;
-    int maximum_width;
-  };
-
-  // Returns the minimum and maximum width for the current popup type determined
-  // from |controller_->PopupType()|.
-  PopupWidthLimits GetMinimumAndMaximumPopupWidth() const;
-
   void OnSelectedRowChanged(absl::optional<int> previous_row_selection,
                             absl::optional<int> current_row_selection) override;
   void OnSuggestionsChanged() override;
diff --git a/chrome/browser/ui/views/download/DIR_METADATA b/chrome/browser/ui/views/download/DIR_METADATA
index 6bf7cbf..8b1c141 100644
--- a/chrome/browser/ui/views/download/DIR_METADATA
+++ b/chrome/browser/ui/views/download/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Downloads"
-}
+mixins: "//components/download/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
index e2cb9bf9..befd5af 100644
--- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
+++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -6,6 +6,7 @@
 #include <initializer_list>
 #include <memory>
 #include <string>
+#include <tuple>
 #include <vector>
 
 #include "base/bind.h"
@@ -644,12 +645,15 @@
 
 const char kTestPagePath[] = "/drag_and_drop/page.html";
 
+// bool use_cross_site_subframe, double device_scale_factor.
+using TestParam = std::tuple<bool, double>;
+
 }  // namespace
 
 // Note: Tests that require OS events need to be added to
 // ozone-linux.interactive_ui_tests_wayland.filter.
 class DragAndDropBrowserTest : public InProcessBrowserTest,
-                               public testing::WithParamInterface<bool> {
+                               public testing::WithParamInterface<TestParam> {
  public:
   DragAndDropBrowserTest() = default;
 
@@ -675,6 +679,13 @@
   void CrossTabDrag_Step3(CrossTabDrag_TestState*);
 
  protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    InProcessBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII(
+        "force-device-scale-factor",
+        base::NumberToString(std::get<1>(GetParam())));
+  }
+
   void SetUpOnMainThread() override {
     host_resolver()->AddRule("*", "127.0.0.1");
     content::SetupCrossSiteRedirector(embedded_test_server());
@@ -689,7 +700,7 @@
 
   bool use_cross_site_subframe() {
     // This is controlled by gtest's test param from INSTANTIATE_TEST_SUITE_P.
-    return GetParam();
+    return std::get<0>(GetParam());
   }
 
   content::RenderFrameHost* GetLeftFrame(
@@ -924,9 +935,12 @@
   std::unique_ptr<DragAndDropSimulator> drag_simulator_;
 };
 
+using DragAndDropWithoutScalingBrowserTest = DragAndDropBrowserTest;
+
 // Scenario: drag text from outside the browser and drop to the right frame.
 // Test coverage: dragover, drop DOM events.
-IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DropTextFromOutside) {
+IN_PROC_BROWSER_TEST_P(DragAndDropWithoutScalingBrowserTest,
+                       DropTextFromOutside) {
   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
   ASSERT_TRUE(NavigateToTestPage("a.com"));
   ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html"));
@@ -1162,7 +1176,7 @@
 
 // Scenario: starting a drag in left frame
 // Test coverage: dragstart DOM event, dragstart data passed to the OS.
-IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DragStartInFrame) {
+IN_PROC_BROWSER_TEST_P(DragAndDropWithoutScalingBrowserTest, DragStartInFrame) {
   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
   ASSERT_TRUE(NavigateToTestPage("a.com"));
   ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html"));
@@ -1935,12 +1949,43 @@
 // of a drag operation, and cross-site drags should be allowed across a
 // navigation.
 
-INSTANTIATE_TEST_SUITE_P(SameSiteSubframe,
-                         DragAndDropBrowserTest,
-                         ::testing::Values(false));
+// Injecting input with scaling works as expected on Chromeos.
+#if defined(OS_CHROMEOS)
+constexpr auto ui_scaling_factors = {1.0, 1.25, 2.0};
+constexpr auto maybe_ui_scaling_factors = {1.0, 1.25, 2.0};
+#elif defined(OS_LINUX)
+// Injecting input with non-1x scaling doesn't work correctly with x11 ozone.
+constexpr auto ui_scaling_factors = {1.0};
+constexpr auto maybe_ui_scaling_factors = {1.0};
+#else
+// Injecting input with non-1x scaling has some slight expectation mismatches
+// (possibly due to rounding) on other platforms.
+constexpr auto ui_scaling_factors = {1.0, 1.25, 2.0};
+constexpr auto maybe_ui_scaling_factors = {1.0};
+#endif
 
-INSTANTIATE_TEST_SUITE_P(CrossSiteSubframe,
-                         DragAndDropBrowserTest,
-                         ::testing::Values(true));
+INSTANTIATE_TEST_SUITE_P(
+    SameSiteSubframe,
+    DragAndDropBrowserTest,
+    ::testing::Combine(::testing::Values(false),
+                       ::testing::ValuesIn(ui_scaling_factors)));
+
+INSTANTIATE_TEST_SUITE_P(
+    CrossSiteSubframe,
+    DragAndDropBrowserTest,
+    ::testing::Combine(::testing::Values(true),
+                       ::testing::ValuesIn(ui_scaling_factors)));
+
+INSTANTIATE_TEST_SUITE_P(
+    SameSiteSubframe,
+    DragAndDropWithoutScalingBrowserTest,
+    ::testing::Combine(::testing::Values(false),
+                       ::testing::ValuesIn(maybe_ui_scaling_factors)));
+
+INSTANTIATE_TEST_SUITE_P(
+    CrossSiteSubframe,
+    DragAndDropWithoutScalingBrowserTest,
+    ::testing::Combine(::testing::Values(true),
+                       ::testing::ValuesIn(maybe_ui_scaling_factors)));
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/views/extensions/DIR_METADATA b/chrome/browser/ui/views/extensions/DIR_METADATA
index 81a57a13..49d375e 100644
--- a/chrome/browser/ui/views/extensions/DIR_METADATA
+++ b/chrome/browser/ui/views/extensions/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Platform>Extensions"
-}
-team_email: "extensions-dev@chromium.org"
+mixins: "//chrome/browser/ui/extensions/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/global_media_controls/DIR_METADATA b/chrome/browser/ui/views/global_media_controls/DIR_METADATA
new file mode 100644
index 0000000..1a2e67ff
--- /dev/null
+++ b/chrome/browser/ui/views/global_media_controls/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ui/global_media_controls/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/location_bar/permission_request_chip.cc b/chrome/browser/ui/views/location_bar/permission_request_chip.cc
index d31b5290..1a9ac7c 100644
--- a/chrome/browser/ui/views/location_bar/permission_request_chip.cc
+++ b/chrome/browser/ui/views/location_bar/permission_request_chip.cc
@@ -140,7 +140,9 @@
 
 void PermissionRequestChip::Collapse(bool allow_restart) {
   PermissionChip::Collapse(allow_restart);
-  ShowBlockedBadge();
+  if (!IsBubbleShowing()) {
+    ShowBlockedBadge();
+  }
 }
 
 void PermissionRequestChip::RecordChipButtonPressed() {
diff --git a/chrome/browser/ui/views/omnibox/DIR_METADATA b/chrome/browser/ui/views/omnibox/DIR_METADATA
index 07a4669..7a9dec1 100644
--- a/chrome/browser/ui/views/omnibox/DIR_METADATA
+++ b/chrome/browser/ui/views/omnibox/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Omnibox"
-}
+mixins: "//components/omnibox/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/page_action/DIR_METADATA b/chrome/browser/ui/views/page_action/DIR_METADATA
new file mode 100644
index 0000000..d538d6d8
--- /dev/null
+++ b/chrome/browser/ui/views/page_action/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ui/page_action/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/page_info/DIR_METADATA b/chrome/browser/ui/views/page_info/DIR_METADATA
index e67d62f..aed523b0 100644
--- a/chrome/browser/ui/views/page_info/DIR_METADATA
+++ b/chrome/browser/ui/views/page_info/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Bubbles>PageInfo"
-}
-team_email: "security-enamel@chromium.org"
+mixins: "//chrome/browser/ui/page_info/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/payments/DIR_METADATA b/chrome/browser/ui/views/payments/DIR_METADATA
new file mode 100644
index 0000000..9dddbb4
--- /dev/null
+++ b/chrome/browser/ui/views/payments/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/payments/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/plugin_vm/DIR_METADATA b/chrome/browser/ui/views/plugin_vm/DIR_METADATA
index c6fbc48..e21b1ad 100644
--- a/chrome/browser/ui/views/plugin_vm/DIR_METADATA
+++ b/chrome/browser/ui/views/plugin_vm/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Shell>Containers>PluginVM"
-}
+mixins: "//chrome/browser/ash/plugin_vm/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/send_tab_to_self/DIR_METADATA b/chrome/browser/ui/views/send_tab_to_self/DIR_METADATA
index 167ca6e..024779e 100644
--- a/chrome/browser/ui/views/send_tab_to_self/DIR_METADATA
+++ b/chrome/browser/ui/views/send_tab_to_self/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Sharing"
-}
+mixins: "//components/send_tab_to_self/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/sharing/DIR_METADATA b/chrome/browser/ui/views/sharing/DIR_METADATA
index 167ca6e..c1d4532f 100644
--- a/chrome/browser/ui/views/sharing/DIR_METADATA
+++ b/chrome/browser/ui/views/sharing/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Sharing"
-}
+mixins: "//chrome/browser/sharing/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/translate/DIR_METADATA b/chrome/browser/ui/views/translate/DIR_METADATA
new file mode 100644
index 0000000..58ea368c
--- /dev/null
+++ b/chrome/browser/ui/views/translate/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/translate/COMMON_METADATA"
diff --git a/chrome/browser/ui/views/webid/DIR_METADATA b/chrome/browser/ui/views/webid/DIR_METADATA
new file mode 100644
index 0000000..136e07617
--- /dev/null
+++ b/chrome/browser/ui/views/webid/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/webid/COMMON_METADATA"
diff --git a/chrome/browser/ui/web_applications/DIR_METADATA b/chrome/browser/ui/web_applications/DIR_METADATA
index 11597323..6f93c68 100644
--- a/chrome/browser/ui/web_applications/DIR_METADATA
+++ b/chrome/browser/ui/web_applications/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
+mixins: "//chrome/browser/web_applications/COMMON_METADATA"
diff --git a/chrome/browser/ui/webid/DIR_METADATA b/chrome/browser/ui/webid/DIR_METADATA
index 8019f44..ddc1f459 100644
--- a/chrome/browser/ui/webid/DIR_METADATA
+++ b/chrome/browser/ui/webid/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>Identity>WebID"
-}
+mixins: "//content/browser/webid/COMMON_METADATA"
 team_email: "web-identity@chromium.org"
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/chromeos/cryptohome_web_ui_handler.cc b/chrome/browser/ui/webui/chromeos/cryptohome_web_ui_handler.cc
index 816d8ec7..f5d97ed 100644
--- a/chrome/browser/ui/webui/chromeos/cryptohome_web_ui_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/cryptohome_web_ui_handler.cc
@@ -20,6 +20,17 @@
 
 namespace chromeos {
 
+namespace {
+
+void ForwardToUIThread(base::OnceCallback<void(bool)> ui_callback,
+                       bool result) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  content::GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE, base::BindOnce(std::move(ui_callback), result));
+}
+
+}  // namespace
+
 CryptohomeWebUIHandler::CryptohomeWebUIHandler() {}
 
 CryptohomeWebUIHandler::~CryptohomeWebUIHandler() {}
@@ -48,18 +59,23 @@
       base::BindOnce(&CryptohomeWebUIHandler::OnPkcs11IsTpmTokenReady,
                      weak_ptr_factory_.GetWeakPtr()));
 
-  content::GetIOThreadTaskRunner({})->PostTaskAndReplyWithResult(
-      FROM_HERE, base::BindOnce(&crypto::IsTPMTokenReady, base::OnceClosure()),
-      base::BindOnce(&CryptohomeWebUIHandler::DidGetNSSUtilInfoOnUIThread,
-                     weak_ptr_factory_.GetWeakPtr()));
+  auto ui_callback =
+      base::BindOnce(&CryptohomeWebUIHandler::GotIsTPMTokenEnabledOnUIThread,
+                     weak_ptr_factory_.GetWeakPtr());
+
+  content::GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE, base::BindOnce(&crypto::IsTPMTokenEnabled,
+                                base::BindOnce(&ForwardToUIThread,
+                                               std::move(ui_callback))));
 }
 
-void CryptohomeWebUIHandler::DidGetNSSUtilInfoOnUIThread(
-    bool is_tpm_token_ready) {
+void CryptohomeWebUIHandler::GotIsTPMTokenEnabledOnUIThread(
+    bool is_tpm_token_enabled) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  base::Value is_tpm_token_ready_value(is_tpm_token_ready);
-  SetCryptohomeProperty("is-tpm-token-ready", is_tpm_token_ready_value);
+  base::Value is_tpm_token_enabled_value(is_tpm_token_enabled);
+  SetCryptohomeProperty("is-tpm-token-ready",
+                        std::move(is_tpm_token_enabled_value));
 }
 
 void CryptohomeWebUIHandler::OnGetTpmStatus(
diff --git a/chrome/browser/ui/webui/chromeos/cryptohome_web_ui_handler.h b/chrome/browser/ui/webui/chromeos/cryptohome_web_ui_handler.h
index b17e3f3..b7426fb 100644
--- a/chrome/browser/ui/webui/chromeos/cryptohome_web_ui_handler.h
+++ b/chrome/browser/ui/webui/chromeos/cryptohome_web_ui_handler.h
@@ -19,7 +19,7 @@
 
 class Value;
 
-}  // base
+}  // namespace base
 
 namespace chromeos {
 
@@ -40,7 +40,7 @@
   // This method is called from JavaScript.
   void OnPageLoaded(const base::ListValue* args);
 
-  void DidGetNSSUtilInfoOnUIThread(bool is_tpm_token_ready);
+  void GotIsTPMTokenEnabledOnUIThread(bool is_tpm_token_enabled);
 
   void OnIsMounted(absl::optional<user_data_auth::IsMountedReply> reply);
   void OnPkcs11IsTpmTokenReady(
diff --git a/chrome/browser/ui/webui/chromeos/edu_coexistence/COMMON_METADATA b/chrome/browser/ui/webui/chromeos/edu_coexistence/COMMON_METADATA
new file mode 100644
index 0000000..c0ebf85
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/edu_coexistence/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "FamilyExperiences"
+}
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/chromeos/edu_coexistence/DIR_METADATA b/chrome/browser/ui/webui/chromeos/edu_coexistence/DIR_METADATA
index c0ebf85..b636a0e 100644
--- a/chrome/browser/ui/webui/chromeos/edu_coexistence/DIR_METADATA
+++ b/chrome/browser/ui/webui/chromeos/edu_coexistence/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "FamilyExperiences"
-}
\ No newline at end of file
+mixins: "//chrome/browser/ui/webui/chromeos/edu_coexistence/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc
index b04fe20..092300d 100644
--- a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.cc
@@ -48,10 +48,6 @@
                IDS_LOGIN_APP_DOWNLOADING_SCREEN_NEXT);
   builder->Add("appDownloadingScreenTitle",
                IDS_LOGIN_APP_DOWNLOADING_SCREEN_TITLE);
-  builder->Add("appDownloadingScreenTitleSingular",
-               IDS_LOGIN_APP_DOWNLOADING_SCREEN_TITLE_SINGULAR);
-  builder->Add("appDownloadingScreenTitlePlural",
-               IDS_LOGIN_APP_DOWNLOADING_SCREEN_TITLE_PLURAL);
 }
 
 void AppDownloadingScreenHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index 713924c..bcd06a9 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -107,8 +107,6 @@
                base::Value(ash::TabletMode::Get()->InTabletMode()));
   dict->SetKey("isDemoModeEnabled",
                base::Value(DemoSetupController::IsDemoModeAllowed()));
-  // TODO(crbug.com/1202135):: Remove along with JS part.
-  dict->SetKey("newLayoutEnabled", base::Value(true));
   if (policy::EnrollmentRequisitionManager::IsRemoraRequisition()) {
     dict->SetKey("flowType", base::Value("meet"));
   }
diff --git a/chrome/browser/ui/webui/conflicts/DIR_METADATA b/chrome/browser/ui/webui/conflicts/DIR_METADATA
new file mode 100644
index 0000000..71d433d
--- /dev/null
+++ b/chrome/browser/ui/webui/conflicts/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/win/conflicts/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/customize_themes/DIR_METADATA b/chrome/browser/ui/webui/customize_themes/DIR_METADATA
new file mode 100644
index 0000000..9b77c024
--- /dev/null
+++ b/chrome/browser/ui/webui/customize_themes/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//ui/webui/resources/cr_components/customize_themes/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/download_shelf/COMMON_METADATA b/chrome/browser/ui/webui/download_shelf/COMMON_METADATA
new file mode 100644
index 0000000..6bf7cbf
--- /dev/null
+++ b/chrome/browser/ui/webui/download_shelf/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Downloads"
+}
diff --git a/chrome/browser/ui/webui/download_shelf/DIR_METADATA b/chrome/browser/ui/webui/download_shelf/DIR_METADATA
index 6bf7cbf..2eac3f4e 100644
--- a/chrome/browser/ui/webui/download_shelf/DIR_METADATA
+++ b/chrome/browser/ui/webui/download_shelf/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Downloads"
-}
+mixins: "//chrome/browser/ui/webui/download_shelf/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/federated_learning/DIR_METADATA b/chrome/browser/ui/webui/federated_learning/DIR_METADATA
new file mode 100644
index 0000000..94c4325
--- /dev/null
+++ b/chrome/browser/ui/webui/federated_learning/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/federated_learning/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/history/DIR_METADATA b/chrome/browser/ui/webui/history/DIR_METADATA
index 9b08ae7f..e1981b4 100644
--- a/chrome/browser/ui/webui/history/DIR_METADATA
+++ b/chrome/browser/ui/webui/history/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>History"
-}
+mixins: "//chrome/browser/resources/history/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/history_clusters/DIR_METADATA b/chrome/browser/ui/webui/history_clusters/DIR_METADATA
new file mode 100644
index 0000000..694e2bf
--- /dev/null
+++ b/chrome/browser/ui/webui/history_clusters/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/history_clusters/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/internals/notifications/DIR_METADATA b/chrome/browser/ui/webui/internals/notifications/DIR_METADATA
new file mode 100644
index 0000000..2e4e834
--- /dev/null
+++ b/chrome/browser/ui/webui/internals/notifications/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/notifications/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/internals/query_tiles/DIR_METADATA b/chrome/browser/ui/webui/internals/query_tiles/DIR_METADATA
new file mode 100644
index 0000000..98d4b501
--- /dev/null
+++ b/chrome/browser/ui/webui/internals/query_tiles/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/query_tiles/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/internals/user_education/DIR_METADATA b/chrome/browser/ui/webui/internals/user_education/DIR_METADATA
new file mode 100644
index 0000000..8a9dcf64
--- /dev/null
+++ b/chrome/browser/ui/webui/internals/user_education/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ui/user_education/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/interstitials/DIR_METADATA b/chrome/browser/ui/webui/interstitials/DIR_METADATA
new file mode 100644
index 0000000..f2acd85
--- /dev/null
+++ b/chrome/browser/ui/webui/interstitials/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/interstitials/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/omnibox/DIR_METADATA b/chrome/browser/ui/webui/omnibox/DIR_METADATA
new file mode 100644
index 0000000..7a9dec1
--- /dev/null
+++ b/chrome/browser/ui/webui/omnibox/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/omnibox/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/predictors/DIR_METADATA b/chrome/browser/ui/webui/predictors/DIR_METADATA
new file mode 100644
index 0000000..79bed43
--- /dev/null
+++ b/chrome/browser/ui/webui/predictors/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/predictors/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/sandbox/DIR_METADATA b/chrome/browser/ui/webui/sandbox/DIR_METADATA
index be22226..9ca68bc 100644
--- a/chrome/browser/ui/webui/sandbox/DIR_METADATA
+++ b/chrome/browser/ui/webui/sandbox/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Sandbox"
-}
-team_email: "security-dev@chromium.org"
+mixins: "//sandbox/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/settings/DIR_METADATA b/chrome/browser/ui/webui/settings/DIR_METADATA
index f4b2e0ae..fc61f1b9 100644
--- a/chrome/browser/ui/webui/settings/DIR_METADATA
+++ b/chrome/browser/ui/webui/settings/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Settings"
-}
+mixins: "//chrome/browser/resources/settings/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/settings/chromeos/DIR_METADATA b/chrome/browser/ui/webui/settings/chromeos/DIR_METADATA
index 2d34b2f4..e84643a 100644
--- a/chrome/browser/ui/webui/settings/chromeos/DIR_METADATA
+++ b/chrome/browser/ui/webui/settings/chromeos/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Systems>Settings"
-}
+mixins: "//chrome/browser/resources/settings/chromeos/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/signin/DIR_METADATA b/chrome/browser/ui/webui/signin/DIR_METADATA
index 5fad689..95ad5b6 100644
--- a/chrome/browser/ui/webui/signin/DIR_METADATA
+++ b/chrome/browser/ui/webui/signin/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Services>SignIn"
-}
+mixins: "//components/signin/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/video_tutorials/DIR_METADATA b/chrome/browser/ui/webui/video_tutorials/DIR_METADATA
index 966408a..00888370 100644
--- a/chrome/browser/ui/webui/video_tutorials/DIR_METADATA
+++ b/chrome/browser/ui/webui/video_tutorials/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Upboarding>VideoTutorials"
-}
-team_email: "chrome-upboarding-eng@google.com"
+mixins: "//chrome/browser/video_tutorials/COMMON_METADATA"
diff --git a/chrome/browser/unified_consent/DIR_METADATA b/chrome/browser/unified_consent/DIR_METADATA
index b368f1d..453a6731 100644
--- a/chrome/browser/unified_consent/DIR_METADATA
+++ b/chrome/browser/unified_consent/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Services>SignIn"
-}
-team_email: "chrome-signin@chromium.org"
+mixins: "//components/unified_consent/COMMON_METADATA"
diff --git a/chrome/browser/usb/COMMON_METADATA b/chrome/browser/usb/COMMON_METADATA
new file mode 100644
index 0000000..536f4da
--- /dev/null
+++ b/chrome/browser/usb/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "Blink>USB"
+}
+team_email: "webusb@chromium.org"
diff --git a/chrome/browser/usb/DIR_METADATA b/chrome/browser/usb/DIR_METADATA
index 536f4da..bbe28ff 100644
--- a/chrome/browser/usb/DIR_METADATA
+++ b/chrome/browser/usb/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>USB"
-}
-team_email: "webusb@chromium.org"
+mixins: "//chrome/browser/usb/COMMON_METADATA"
diff --git a/chrome/browser/video_tutorials/COMMON_METADATA b/chrome/browser/video_tutorials/COMMON_METADATA
new file mode 100644
index 0000000..e6c59a32
--- /dev/null
+++ b/chrome/browser/video_tutorials/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail: {
+  component: "Upboarding>VideoTutorials"
+}
+team_email: "chrome-upboarding-eng@google.com"
+os: ANDROID
diff --git a/chrome/browser/video_tutorials/DIR_METADATA b/chrome/browser/video_tutorials/DIR_METADATA
index e6c59a32..00888370 100644
--- a/chrome/browser/video_tutorials/DIR_METADATA
+++ b/chrome/browser/video_tutorials/DIR_METADATA
@@ -1,5 +1 @@
-monorail: {
-  component: "Upboarding>VideoTutorials"
-}
-team_email: "chrome-upboarding-eng@google.com"
-os: ANDROID
+mixins: "//chrome/browser/video_tutorials/COMMON_METADATA"
diff --git a/chrome/browser/vr/vector_icons/DIR_METADATA b/chrome/browser/vr/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/chrome/browser/vr/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/chrome/browser/wake_lock/DIR_METADATA b/chrome/browser/wake_lock/DIR_METADATA
index 966f102..e5b41fd 100644
--- a/chrome/browser/wake_lock/DIR_METADATA
+++ b/chrome/browser/wake_lock/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>WakeLock"
-}
-team_email: "device-dev@chromium.org"
+mixins: "//third_party/blink/renderer/modules/wake_lock/COMMON_METADATA"
diff --git a/chrome/browser/web_applications/COMMON_METADATA b/chrome/browser/web_applications/COMMON_METADATA
new file mode 100644
index 0000000..c8b762a
--- /dev/null
+++ b/chrome/browser/web_applications/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org"
diff --git a/chrome/browser/web_applications/DIR_METADATA b/chrome/browser/web_applications/DIR_METADATA
index c8b762a..6f93c68 100644
--- a/chrome/browser/web_applications/DIR_METADATA
+++ b/chrome/browser/web_applications/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
+mixins: "//chrome/browser/web_applications/COMMON_METADATA"
diff --git a/chrome/browser/web_applications/app_service/DIR_METADATA b/chrome/browser/web_applications/app_service/DIR_METADATA
new file mode 100644
index 0000000..c0404074
--- /dev/null
+++ b/chrome/browser/web_applications/app_service/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/services/app_service/COMMON_METADATA"
diff --git a/chrome/browser/web_applications/preinstalled_web_app_migration_browsertest.cc b/chrome/browser/web_applications/preinstalled_web_app_migration_browsertest.cc
index 17bf0d1..b3b503c 100644
--- a/chrome/browser/web_applications/preinstalled_web_app_migration_browsertest.cc
+++ b/chrome/browser/web_applications/preinstalled_web_app_migration_browsertest.cc
@@ -268,7 +268,8 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     ChromeAppListItem* app_list_item =
         app_list_model_updater->FindItem(kExtensionId);
-    app_list_item->SetPosition(syncer::StringOrdinal("testapplistposition"));
+    ChromeAppListItem::TestApi(app_list_item)
+        .SetPosition(syncer::StringOrdinal("testapplistposition"));
     app_list_model_updater->OnItemUpdated(app_list_item->CloneMetadata());
     app_list_syncable_service->SetPinPosition(
         kExtensionId, syncer::StringOrdinal("testpinposition"));
@@ -402,7 +403,8 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     ChromeAppListItem* app_list_item =
         app_list_model_updater->FindItem(kExtensionId);
-    app_list_item->SetPosition(syncer::StringOrdinal("testapplistposition"));
+    ChromeAppListItem::TestApi(app_list_item)
+        .SetPosition(syncer::StringOrdinal("testapplistposition"));
     app_list_model_updater->OnItemUpdated(app_list_item->CloneMetadata());
     app_list_syncable_service->SetPinPosition(
         kExtensionId, syncer::StringOrdinal("testpinposition"));
diff --git a/chrome/browser/webapps/DIR_METADATA b/chrome/browser/webapps/DIR_METADATA
index 11597323..49c72b4 100644
--- a/chrome/browser/webapps/DIR_METADATA
+++ b/chrome/browser/webapps/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
+mixins: "//components/webapps/COMMON_METADATA"
diff --git a/chrome/browser/webid/DIR_METADATA b/chrome/browser/webid/DIR_METADATA
new file mode 100644
index 0000000..136e07617
--- /dev/null
+++ b/chrome/browser/webid/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/webid/COMMON_METADATA"
diff --git a/chrome/browser/win/conflicts/COMMON_METADATA b/chrome/browser/win/conflicts/COMMON_METADATA
new file mode 100644
index 0000000..643d2bac
--- /dev/null
+++ b/chrome/browser/win/conflicts/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "Internals>Core"
+}
diff --git a/chrome/browser/win/conflicts/DIR_METADATA b/chrome/browser/win/conflicts/DIR_METADATA
index 643d2bac..71d433d 100644
--- a/chrome/browser/win/conflicts/DIR_METADATA
+++ b/chrome/browser/win/conflicts/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Core"
-}
+mixins: "//chrome/browser/win/conflicts/COMMON_METADATA"
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index f6f537e..5677d8a 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1632787201-150d8401b0a375775ba0672ce29089ebfcb45ee7.profdata
+chrome-linux-main-1632829572-93a632c358259e3fc9ac3efe9f631b4392ae9bb4.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index d95239e..0301755 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1632787201-062b4f8edda99e52afc23056c5b5b5ab1bffe4c8.profdata
+chrome-mac-main-1632829572-5741a2c2a51147e86dd9d9ee9a18adf8eeceb511.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 6c34b93..b942acc 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1632787201-b961418920fd07a7918f8d33592733f4ca60faf8.profdata
+chrome-win32-main-1632816908-82c09ff12a17b4bec5d326042253d5be6f5d4ec3.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index eb11c6a2..e956c1a88 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1632797989-7ef477215b78d4bbba49478207fbe9274bb214f9.profdata
+chrome-win64-main-1632816908-0dc679de3d0e0e44be0ac8da3dfb6d3abaa4c59c.profdata
diff --git a/chrome/chrome_cleaner/COMMON_METADATA b/chrome/chrome_cleaner/COMMON_METADATA
new file mode 100644
index 0000000..5078508f
--- /dev/null
+++ b/chrome/chrome_cleaner/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "Services>Safebrowsing>ChromeCleanup"
+}
+team_email: "safebrowsing@chromium.org"
diff --git a/chrome/chrome_cleaner/DIR_METADATA b/chrome/chrome_cleaner/DIR_METADATA
index 5078508f..49a909a 100644
--- a/chrome/chrome_cleaner/DIR_METADATA
+++ b/chrome/chrome_cleaner/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Services>Safebrowsing>ChromeCleanup"
-}
-team_email: "safebrowsing@chromium.org"
+mixins: "//chrome/chrome_cleaner/COMMON_METADATA"
diff --git a/chrome/common/apps/DIR_METADATA b/chrome/common/apps/DIR_METADATA
index 9a42572..a2f0f7e 100644
--- a/chrome/common/apps/DIR_METADATA
+++ b/chrome/common/apps/DIR_METADATA
@@ -1,3 +1,4 @@
+mixins: "//apps/COMMON_METADATA"
 monorail: {
   component: "Platform>Extensions"
 }
diff --git a/chrome/common/cart/DIR_METADATA b/chrome/common/cart/DIR_METADATA
index 2cb1250..fc2f072d 100644
--- a/chrome/common/cart/DIR_METADATA
+++ b/chrome/common/cart/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Shopping"
-}
+mixins: "//chrome/browser/cart/COMMON_METADATA"
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 39777c5a..86eba436 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -55,7 +55,7 @@
 // Controls whether intent settings are available in App Management.
 // TODO(crbug/1226925): Do not enable flag unless this has been resolved.
 const base::Feature kAppManagementIntentSettings{
-    "AppManagementIntentSettings", base::FEATURE_DISABLED_BY_DEFAULT};
+    "AppManagementIntentSettings", base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/common/custom_handlers/DIR_METADATA b/chrome/common/custom_handlers/DIR_METADATA
index c8b762a..a9ebe08 100644
--- a/chrome/common/custom_handlers/DIR_METADATA
+++ b/chrome/common/custom_handlers/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
+mixins: "//chrome/browser/custom_handlers/COMMON_METADATA"
diff --git a/chrome/common/extensions/DIR_METADATA b/chrome/common/extensions/DIR_METADATA
index 1a705f4..d8d2f40 100644
--- a/chrome/common/extensions/DIR_METADATA
+++ b/chrome/common/extensions/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail: {
-  component: "Platform>Extensions"
-}
+mixins: "//extensions/COMMON_METADATA"
 team_email: "chromium-extensions@chromium.org"
diff --git a/chrome/common/media_galleries/DIR_METADATA b/chrome/common/media_galleries/DIR_METADATA
index bf48267..a9173fc 100644
--- a/chrome/common/media_galleries/DIR_METADATA
+++ b/chrome/common/media_galleries/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Platform>Apps>MediaGalleries"
-}
+mixins: "//chrome/browser/media_galleries/COMMON_METADATA"
diff --git a/chrome/common/net/DIR_METADATA b/chrome/common/net/DIR_METADATA
index 2ba70d2..09f5b5e 100644
--- a/chrome/common/net/DIR_METADATA
+++ b/chrome/common/net/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>Network"
-}
-team_email: "net-dev@chromium.org"
+mixins: "//net/COMMON_METADATA"
diff --git a/chrome/common/notifications/DIR_METADATA b/chrome/common/notifications/DIR_METADATA
index b3b636b3..2e4e834 100644
--- a/chrome/common/notifications/DIR_METADATA
+++ b/chrome/common/notifications/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Notifications"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//chrome/browser/notifications/COMMON_METADATA"
diff --git a/chrome/common/performance_manager/DIR_METADATA b/chrome/common/performance_manager/DIR_METADATA
new file mode 100644
index 0000000..e9e0173
--- /dev/null
+++ b/chrome/common/performance_manager/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/performance_manager/COMMON_METADATA"
diff --git a/chrome/common/printing/DIR_METADATA b/chrome/common/printing/DIR_METADATA
index ee7161a6..2413ed4 100644
--- a/chrome/common/printing/DIR_METADATA
+++ b/chrome/common/printing/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Printing"
-}
+mixins: "//printing/COMMON_METADATA"
diff --git a/chrome/common/privacy_budget/DIR_METADATA b/chrome/common/privacy_budget/DIR_METADATA
index fe6ef77..6d362b2 100644
--- a/chrome/common/privacy_budget/DIR_METADATA
+++ b/chrome/common/privacy_budget/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Privacy>Fingerprinting"
-}
-team_email: "privacy-sandbox-dev@chromium.org"
+mixins: "//third_party/blink/public/common/privacy_budget/COMMON_METADATA"
diff --git a/chrome/common/search/DIR_METADATA b/chrome/common/search/DIR_METADATA
index eb6250a8..10d7b81 100644
--- a/chrome/common/search/DIR_METADATA
+++ b/chrome/common/search/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>NewTabPage"
-}
+mixins: "//components/search/COMMON_METADATA"
diff --git a/chrome/common/themes/DIR_METADATA b/chrome/common/themes/DIR_METADATA
new file mode 100644
index 0000000..826932d7
--- /dev/null
+++ b/chrome/common/themes/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/themes/COMMON_METADATA"
diff --git a/chrome/renderer/autofill/DIR_METADATA b/chrome/renderer/autofill/DIR_METADATA
index ac71123..bc280336 100644
--- a/chrome/renderer/autofill/DIR_METADATA
+++ b/chrome/renderer/autofill/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Autofill"
-}
+mixins: "//components/autofill/COMMON_METADATA"
diff --git a/chrome/renderer/cart/DIR_METADATA b/chrome/renderer/cart/DIR_METADATA
index 2cb1250..fc2f072d 100644
--- a/chrome/renderer/cart/DIR_METADATA
+++ b/chrome/renderer/cart/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Shopping"
-}
+mixins: "//chrome/browser/cart/COMMON_METADATA"
diff --git a/chrome/renderer/extensions/DIR_METADATA b/chrome/renderer/extensions/DIR_METADATA
index 66b3a87..1d3e969d 100644
--- a/chrome/renderer/extensions/DIR_METADATA
+++ b/chrome/renderer/extensions/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail: {
-  component: "Platform>Extensions"
-}
+mixins: "//extensions/COMMON_METADATA"
 team_email: "extensions-reviews@chromium.org"
diff --git a/chrome/renderer/media/DIR_METADATA b/chrome/renderer/media/DIR_METADATA
index 342ee647..41e8f64 100644
--- a/chrome/renderer/media/DIR_METADATA
+++ b/chrome/renderer/media/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Media"
-}
+mixins: "//media/COMMON_METADATA"
diff --git a/chrome/renderer/net/DIR_METADATA b/chrome/renderer/net/DIR_METADATA
index 2ba70d2..09f5b5e 100644
--- a/chrome/renderer/net/DIR_METADATA
+++ b/chrome/renderer/net/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>Network"
-}
-team_email: "net-dev@chromium.org"
+mixins: "//net/COMMON_METADATA"
diff --git a/chrome/renderer/pdf/DIR_METADATA b/chrome/renderer/pdf/DIR_METADATA
index 11b8e5a..0563e2c 100644
--- a/chrome/renderer/pdf/DIR_METADATA
+++ b/chrome/renderer/pdf/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Plugins>PDF"
-}
+mixins: "//pdf/COMMON_METADATA"
diff --git a/chrome/renderer/performance_manager/DIR_METADATA b/chrome/renderer/performance_manager/DIR_METADATA
new file mode 100644
index 0000000..e9e0173
--- /dev/null
+++ b/chrome/renderer/performance_manager/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/performance_manager/COMMON_METADATA"
diff --git a/chrome/renderer/printing/DIR_METADATA b/chrome/renderer/printing/DIR_METADATA
index ee7161a6..2413ed4 100644
--- a/chrome/renderer/printing/DIR_METADATA
+++ b/chrome/renderer/printing/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Printing"
-}
+mixins: "//printing/COMMON_METADATA"
diff --git a/chrome/renderer/resources/cart/DIR_METADATA b/chrome/renderer/resources/cart/DIR_METADATA
new file mode 100644
index 0000000..fc2f072d
--- /dev/null
+++ b/chrome/renderer/resources/cart/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/cart/COMMON_METADATA"
diff --git a/chrome/renderer/resources/extensions/DIR_METADATA b/chrome/renderer/resources/extensions/DIR_METADATA
index 9a42572..e1d704c 100644
--- a/chrome/renderer/resources/extensions/DIR_METADATA
+++ b/chrome/renderer/resources/extensions/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Platform>Extensions"
-}
+mixins: "//extensions/COMMON_METADATA"
diff --git a/chrome/renderer/translate/DIR_METADATA b/chrome/renderer/translate/DIR_METADATA
index f13e6d64..58ea368c 100644
--- a/chrome/renderer/translate/DIR_METADATA
+++ b/chrome/renderer/translate/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Browser>Language>Translate"
-}
+mixins: "//components/translate/COMMON_METADATA"
diff --git a/chrome/services/printing/DIR_METADATA b/chrome/services/printing/DIR_METADATA
index ee7161a6..2413ed4 100644
--- a/chrome/services/printing/DIR_METADATA
+++ b/chrome/services/printing/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Printing"
-}
+mixins: "//printing/COMMON_METADATA"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index c9e692b..d385136 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4978,6 +4978,8 @@
 
   if (!is_android) {
     sources += [
+      "../browser/apps/app_discovery_service/remote_url_search/remote_url_client_unittest.cc",
+      "../browser/apps/app_discovery_service/remote_url_search/remote_url_index_unittest.cc",
       "../browser/browsing_data/chrome_browsing_data_lifetime_manager_unittest.cc",
       "../browser/component_updater/soda_component_installer_unittest.cc",
       "../browser/component_updater/soda_language_pack_component_installer_unittest.cc",
@@ -6950,7 +6952,7 @@
     if (is_chromeos_ash) {
       sources += [
         "../browser/ash/login/easy_unlock/easy_unlock_auth_attempt_unittest.cc",
-        "../browser/ash/login/easy_unlock/easy_unlock_notification_controller_chromeos_unittest.cc",
+        "../browser/ash/login/easy_unlock/easy_unlock_notification_controller_unittest.cc",
         "../browser/ash/login/easy_unlock/easy_unlock_service_regular_unittest.cc",
         "../browser/ash/login/easy_unlock/smartlock_state_handler_unittest.cc",
         "../browser/chromeos/extensions/extensions_permissions_tracker_unittest.cc",
diff --git a/chrome/test/android/COMMON_METADATA b/chrome/test/android/COMMON_METADATA
new file mode 100644
index 0000000..a0d027c
--- /dev/null
+++ b/chrome/test/android/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Test>Android"
+}
+os: ANDROID
diff --git a/chrome/test/android/DIR_METADATA b/chrome/test/android/DIR_METADATA
index a0d027c..e50c63b1 100644
--- a/chrome/test/android/DIR_METADATA
+++ b/chrome/test/android/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Test>Android"
-}
-os: ANDROID
+mixins: "//chrome/android/COMMON_METADATA"
+mixins: "//chrome/test/android/COMMON_METADATA"
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/DIR_METADATA b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/DIR_METADATA
new file mode 100644
index 0000000..087037e
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/notifications/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/notifications/COMMON_METADATA"
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/DIR_METADATA b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/DIR_METADATA
index 1a6d7ee6..4a58e65 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/DIR_METADATA
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/sync/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Services>Sync"
-}
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/DIR_METADATA b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/DIR_METADATA
index 320129e..1bfc477 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/DIR_METADATA
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/webapps/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/webapps/COMMON_METADATA"
diff --git a/chrome/test/base/android/DIR_METADATA b/chrome/test/base/android/DIR_METADATA
index a0d027c..e50c63b1 100644
--- a/chrome/test/base/android/DIR_METADATA
+++ b/chrome/test/base/android/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Test>Android"
-}
-os: ANDROID
+mixins: "//chrome/android/COMMON_METADATA"
+mixins: "//chrome/test/android/COMMON_METADATA"
diff --git a/chrome/test/data/chromeos/liblouis_wasm/manifest.json b/chrome/test/data/chromeos/liblouis_wasm/manifest.json
index 4131c44..0a0a590 100644
--- a/chrome/test/data/chromeos/liblouis_wasm/manifest.json
+++ b/chrome/test/data/chromeos/liblouis_wasm/manifest.json
@@ -6,5 +6,6 @@
   "description": "test",
   "background": {
     "scripts": [ "test.js" ]
-  }
+  },
+  "content_security_policy": "script-src 'self' 'wasm-eval'; object-src 'self'"
 }
diff --git a/chrome/test/data/dom_distiller/DIR_METADATA b/chrome/test/data/dom_distiller/DIR_METADATA
new file mode 100644
index 0000000..c9eb2576
--- /dev/null
+++ b/chrome/test/data/dom_distiller/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/COMMON_METADATA"
diff --git a/chrome/test/data/translate/DIR_METADATA b/chrome/test/data/translate/DIR_METADATA
new file mode 100644
index 0000000..58ea368c
--- /dev/null
+++ b/chrome/test/data/translate/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/translate/COMMON_METADATA"
diff --git a/chrome/test/data/webui/chromeos/diagnostics/input_list_test.js b/chrome/test/data/webui/chromeos/diagnostics/input_list_test.js
index 2cb3f91..b86efabc 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/input_list_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/input_list_test.js
@@ -34,9 +34,10 @@
     provider.reset();
   });
 
-  function initializeInputList() {
+  function initializeInputList(
+      keyboards = fakeKeyboards, touchDevices = fakeTouchDevices) {
     assertFalse(!!inputListElement);
-    provider.setFakeConnectedDevices(fakeKeyboards, fakeTouchDevices);
+    provider.setFakeConnectedDevices(keyboards, touchDevices);
 
     // Add the input list to the DOM.
     inputListElement =
@@ -99,6 +100,20 @@
         });
   });
 
+  test('KeyboardTesterShow', () => {
+    return initializeInputList([fakeKeyboards[0]], [])
+        .then(() => {
+          const testButton = getCardByDeviceType('keyboard').$$('cr-button');
+          assertTrue(!!testButton);
+          testButton.click();
+          return flushTasks();
+        })
+        .then(() => {
+          const keyboardTester = inputListElement.$$('keyboard-tester');
+          assertTrue(keyboardTester.isOpen());
+        });
+  });
+
   test('TouchpadAddAndRemove', () => {
     /** @type {!TouchDeviceInfo} */
     const fakeTouchpad = {
diff --git a/chrome/test/data/webui/chromeos/edu_coexistence/DIR_METADATA b/chrome/test/data/webui/chromeos/edu_coexistence/DIR_METADATA
new file mode 100644
index 0000000..b636a0e
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/edu_coexistence/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/browser/ui/webui/chromeos/edu_coexistence/COMMON_METADATA"
diff --git a/chrome/test/data/webui/settings/DIR_METADATA b/chrome/test/data/webui/settings/DIR_METADATA
index f4b2e0ae..fc61f1b9 100644
--- a/chrome/test/data/webui/settings/DIR_METADATA
+++ b/chrome/test/data/webui/settings/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Settings"
-}
+mixins: "//chrome/browser/resources/settings/COMMON_METADATA"
diff --git a/chrome/test/data/webui/settings/chromeos/DIR_METADATA b/chrome/test/data/webui/settings/chromeos/DIR_METADATA
index 2d34b2f4..e84643a 100644
--- a/chrome/test/data/webui/settings/chromeos/DIR_METADATA
+++ b/chrome/test/data/webui/settings/chromeos/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Systems>Settings"
-}
+mixins: "//chrome/browser/resources/settings/chromeos/COMMON_METADATA"
diff --git a/chrome/test/origin_policy/DIR_METADATA b/chrome/test/origin_policy/DIR_METADATA
index 8674903..6833f6b 100644
--- a/chrome/test/origin_policy/DIR_METADATA
+++ b/chrome/test/origin_policy/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>SecurityFeature"
-}
+mixins: "//services/network/origin_policy/COMMON_METADATA"
diff --git a/chrome/test/payments/DIR_METADATA b/chrome/test/payments/DIR_METADATA
new file mode 100644
index 0000000..9dddbb4
--- /dev/null
+++ b/chrome/test/payments/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/payments/COMMON_METADATA"
diff --git a/chrome/updater/COMMON_METADATA b/chrome/updater/COMMON_METADATA
new file mode 100644
index 0000000..5f42b1af
--- /dev/null
+++ b/chrome/updater/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "Internals>Updater"
+}
+team_email: "chrome-updates-dev@chromium.org"
diff --git a/chrome/updater/DIR_METADATA b/chrome/updater/DIR_METADATA
index 5f42b1af..593a8a1 100644
--- a/chrome/updater/DIR_METADATA
+++ b/chrome/updater/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>Updater"
-}
-team_email: "chrome-updates-dev@chromium.org"
+mixins: "//chrome/updater/COMMON_METADATA"
diff --git a/chromecast/browser/metrics/DIR_METADATA b/chromecast/browser/metrics/DIR_METADATA
index 540f41c..e99cb759 100644
--- a/chromecast/browser/metrics/DIR_METADATA
+++ b/chromecast/browser/metrics/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Metrics"
-}
+mixins: "//base/metrics/COMMON_METADATA"
diff --git a/chromecast/media/cma/backend/fuchsia/DIR_METADATA b/chromecast/media/cma/backend/fuchsia/DIR_METADATA
new file mode 100644
index 0000000..210aa6a
--- /dev/null
+++ b/chromecast/media/cma/backend/fuchsia/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//build/fuchsia/COMMON_METADATA"
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 8d71294..897e1d05 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-14247.0.0
\ No newline at end of file
+14248.0.0
\ No newline at end of file
diff --git a/chromeos/assistant/COMMON_METADATA b/chromeos/assistant/COMMON_METADATA
new file mode 100644
index 0000000..5cf9e51
--- /dev/null
+++ b/chromeos/assistant/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Shell>Assistant"
+}
diff --git a/chromeos/assistant/DIR_METADATA b/chromeos/assistant/DIR_METADATA
index 5cf9e51..cfb0c371 100644
--- a/chromeos/assistant/DIR_METADATA
+++ b/chromeos/assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Shell>Assistant"
-}
+mixins: "//chromeos/assistant/COMMON_METADATA"
diff --git a/chromeos/components/camera_app_ui/resources/css/css.gni b/chromeos/components/camera_app_ui/resources/css/css.gni
index 50d1d2f..3858ed1 100644
--- a/chromeos/components/camera_app_ui/resources/css/css.gni
+++ b/chromeos/components/camera_app_ui/resources/css/css.gni
@@ -14,5 +14,5 @@
   "mode/video.css",
   "new_feature_toast.css",
   "ptz_panel.css",
-  "review_document.css",
+  "review.css",
 ]
diff --git a/chromeos/components/camera_app_ui/resources/css/main.css b/chromeos/components/camera_app_ui/resources/css/main.css
index a661bcc..fb6905d 100644
--- a/chromeos/components/camera_app_ui/resources/css/main.css
+++ b/chromeos/components/camera_app_ui/resources/css/main.css
@@ -8,7 +8,8 @@
   --blue-300: rgb(var(--blue-300-rgb));
   --blue-500: rgb(66, 133, 244);
   --grey-100: rgb(241, 243, 244);
-  --grey-200: rgb(232, 234, 237);
+  --grey-200-rgb: 233, 234, 237;
+  --grey-200: rgb(var(--grey-200-rgb));
   --grey-400: rgb(189, 193, 198);
   --grey-500: rgb(154, 160, 166);
   --grey-700: rgb(95, 99, 104);
@@ -720,7 +721,7 @@
 #view-camera,
 #view-document-mode-dialog,
 #view-ptz-panel,
-#view-review-document,
+#view-review,
 #view-flash,
 #view-settings,
 #view-grid-settings,
@@ -745,7 +746,7 @@
 body.view-camera #view-camera,
 body.view-document-mode-dialog #view-document-mode-dialog,
 body.view-ptz-panel #view-ptz-panel,
-body.view-review-document #view-review-document,
+body.view-review #view-review,
 body.view-flash #view-flash,
 body.view-settings #view-settings,
 body.view-grid-settings #view-grid-settings,
diff --git a/chromeos/components/camera_app_ui/resources/css/review.css b/chromeos/components/camera_app_ui/resources/css/review.css
new file mode 100644
index 0000000..b6a1dff
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/css/review.css
@@ -0,0 +1,54 @@
+/* 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. */
+
+#view-review {
+  background: var(--grey-900);
+}
+
+#review-frame {
+  align-items: center;
+  border: 1px solid rgba(var(--grey-200-rgb), 0.38);
+  bottom: calc(var(--bottom-line) * 2);
+  display: flex;
+  justify-content: center;
+  left: calc(var(--left-line) * 2);
+  position: absolute;
+  right: calc(var(--right-line) * 2);
+  top: 0;
+}
+
+#review-image {
+  max-height: 100%;
+  max-width: 100%;
+}
+
+#view-review .button-groups {
+  align-items: center;
+  bottom: 0;
+  display: flex;
+  flex-direction: row-reverse;
+  justify-content: space-between;
+  left: calc(var(--left-line) * 2);
+  position: absolute;
+  right: calc(var(--right-line) * 2);
+  top: calc(100% - calc(var(--bottom-line) * 2));
+}
+
+#view-review .positive-button-groups {
+  display: flex;
+  flex-direction: row-reverse;
+  flex-wrap: wrap;
+}
+
+#view-review .positive-button-groups button {
+  margin: 0 8px;
+}
+
+#view-review .positive-button-groups button:first-child {
+  margin-inline-end: 0;
+}
+
+#view-review .positive-button-groups button:last-child {
+  margin-inline-start: 0;
+}
diff --git a/chromeos/components/camera_app_ui/resources/css/review_document.css b/chromeos/components/camera_app_ui/resources/css/review_document.css
deleted file mode 100644
index 91b8312..0000000
--- a/chromeos/components/camera_app_ui/resources/css/review_document.css
+++ /dev/null
@@ -1,53 +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. */
-
-#view-review-document {
-  background: var(--grey-900);
-}
-
-#document-frame {
-  align-items: center;
-  border: 1px solid rgba(232, 234, 237, 0.38);
-  bottom: calc(var(--bottom-line) * 2);
-  display: flex;
-  justify-content: center;
-  left: calc(var(--left-line) * 2);
-  position: absolute;
-  right: calc(var(--right-line) * 2);
-  top: 0;
-}
-
-#document-image {
-  max-height: 100%;
-  max-width: 100%;
-}
-
-#review-document-button-groups {
-  bottom: 0;
-  left: calc(var(--left-line) * 2);
-  position: absolute;
-  right: calc(var(--right-line) * 2);
-  top: calc(100% - calc(var(--bottom-line) * 2));
-}
-
-#review-document-button-groups button {
-  position: relative;
-  top: 50%;
-  transform: translateY(-50%);
-}
-
-/* float direction */
-
-#save-pdf-document,
-#save-photo-document {
-  float: right;
-}
-
-#retake-document {
-  float: left;
-}
-
-#save-photo-document {
-  margin-right: 8px;  /* csschecker-disable-line left-right */
-}
diff --git a/chromeos/components/camera_app_ui/resources/js/i18n_string.js b/chromeos/components/camera_app_ui/resources/js/i18n_string.js
index 41cd7dc34..f476344 100644
--- a/chromeos/components/camera_app_ui/resources/js/i18n_string.js
+++ b/chromeos/components/camera_app_ui/resources/js/i18n_string.js
@@ -70,6 +70,8 @@
   LABEL_PHOTO_RESOLUTION: 'label_photo_resolution',
   LABEL_RECORD_GIF_VIDEO_OPTION: 'label_record_gif_video_option',
   LABEL_RECORD_NORMAL_VIDEO_OPTION: 'label_record_normal_video_option',
+  LABEL_SAVE_PDF_DOCUMENT: 'label_save_pdf_document',
+  LABEL_SAVE_PHOTO_DOCUMENT: 'label_save_photo_document',
   LABEL_SCAN_DOCUMENT_OPTION: 'label_scan_document_option',
   LABEL_SCAN_QRCODE_OPTION: 'label_scan_qrcode_option',
   LABEL_SWITCH_RECORD_VIDEO_BUTTON: 'label_switch_record_video_button',
diff --git a/chromeos/components/camera_app_ui/resources/js/js.gni b/chromeos/components/camera_app_ui/resources/js/js.gni
index e3cfd2d..f2074bbb 100644
--- a/chromeos/components/camera_app_ui/resources/js/js.gni
+++ b/chromeos/components/camera_app_ui/resources/js/js.gni
@@ -88,7 +88,7 @@
   "views/camera/video_encoder_options.js",
   "views/dialog.js",
   "views/ptz_panel.js",
-  "views/review_document.js",
+  "views/review.js",
   "views/settings.js",
   "views/view.js",
   "views/warning.js",
diff --git a/chromeos/components/camera_app_ui/resources/js/type.js b/chromeos/components/camera_app_ui/resources/js/type.js
index 9665d42..f2aac14 100644
--- a/chromeos/components/camera_app_ui/resources/js/type.js
+++ b/chromeos/components/camera_app_ui/resources/js/type.js
@@ -129,7 +129,7 @@
   PHOTO_RESOLUTION_SETTINGS: 'view-photo-resolution-settings',
   PTZ_PANEL: 'view-ptz-panel',
   RESOLUTION_SETTINGS: 'view-resolution-settings',
-  REVIEW_DOCUMENT: 'view-review-document',
+  REVIEW: 'view-review',
   SETTINGS: 'view-settings',
   SPLASH: 'view-splash',
   TIMER_SETTINGS: 'view-timer-settings',
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera.js b/chromeos/components/camera_app_ui/resources/js/views/camera.js
index a47263b..5f5a8d7 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera.js
@@ -66,7 +66,7 @@
 import {VideoEncoderOptions} from './camera/video_encoder_options.js';
 import {Dialog} from './dialog.js';
 import {PTZPanel} from './ptz_panel.js';
-import {ReviewDocument} from './review_document.js';
+import * as review from './review.js';
 import {PrimarySettings} from './settings.js';
 import {PTZPanelOptions, View} from './view.js';
 import {WarningType} from './warning.js';
@@ -124,10 +124,10 @@
     this.perfLogger_ = perfLogger;
 
     /**
-     * @type {!ReviewDocument}
+     * @type {!review.Review}
      * @private
      */
-    this.reviewDocumentView_ = new ReviewDocument();
+    this.review_ = new review.Review();
 
     /**
      * @type {!Dialog}
@@ -142,7 +142,7 @@
     this.subViews_ = [
       new PrimarySettings(infoUpdater, photoPreferrer, videoPreferrer),
       new PTZPanel(),
-      this.reviewDocumentView_,
+      this.review_,
       this.docModeDialogView_,
       new View(ViewName.FLASH),
     ];
@@ -777,7 +777,7 @@
     await this.preview_.close();
     await this.scanOptions_.detachPreview();
     try {
-      await this.reviewDocumentView_.setReviewDocument(blob);
+      await this.review_.setReviewPhoto(blob);
     } catch (e) {
       await this.restorePreviewInScanMode_();
       throw e;
@@ -788,7 +788,11 @@
    * @override
    */
   async getDocumentReviewResult() {
-    const result = await this.reviewDocumentView_.startReview();
+    const primary =
+        new review.Option(I18nString.LABEL_SAVE_PDF_DOCUMENT, MimeType.PDF);
+    const others = [new review.Option(
+        I18nString.LABEL_SAVE_PHOTO_DOCUMENT, MimeType.JPEG)];
+    const result = await this.review_.startReview({primary, others});
     await this.restorePreviewInScanMode_();
     return result;
   }
diff --git a/chromeos/components/camera_app_ui/resources/js/views/review.js b/chromeos/components/camera_app_ui/resources/js/views/review.js
new file mode 100644
index 0000000..62fafb2
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/js/views/review.js
@@ -0,0 +1,146 @@
+// 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 * as dom from '../dom.js';
+// eslint-disable-next-line no-unused-vars
+import {I18nString} from '../i18n_string.js';
+import * as nav from '../nav.js';
+import {ViewName} from '../type.js';
+import {instantiateTemplate, setupI18nElements} from '../util.js';
+import {WaitableEvent} from '../waitable_event.js';
+
+import {View} from './view.js';
+
+/**
+ * Available option show in this view.
+ * @template T
+ */
+export class Option {
+  /**
+   * @param {!I18nString} text Text string show on the option button.
+   * @param {!T} value Value returned if the user select this option after
+   *   review.
+   */
+  constructor(text, value) {
+    /**
+     * @const {!I18nString}
+     */
+    this.text = text;
+
+    /**
+     * @const {!T}
+     */
+    this.value = value;
+  }
+}
+
+/**
+ * View controller for review page.
+ */
+export class Review extends View {
+  /**
+   * @public
+   */
+  constructor() {
+    super(ViewName.REVIEW);
+
+    /**
+     * @private {!HTMLImageElement}
+     * @const
+     */
+    this.image_ = dom.get('#review-image', HTMLImageElement);
+
+    /**
+     * @private {!HTMLDivElement}
+     * @const
+     */
+    this.btnGroups_ =
+        dom.getFrom(this.root, '.positive-button-groups', HTMLDivElement);
+
+    /**
+     * @private {!HTMLButtonElement}
+     * @const
+     */
+    this.retakeBtn_ = dom.get('#review-retake', HTMLButtonElement);
+
+    /**
+     * @private {?HTMLButtonElement}
+     */
+    this.primaryBtn_ = null;
+  }
+
+  /**
+   * @override
+   */
+  focus() {
+    this.primaryBtn_.focus();
+  }
+
+  /**
+   * @param {!Blob} blob
+   * @return {!Promise}
+   */
+  async setReviewPhoto(blob) {
+    try {
+      await new Promise((resolve, reject) => {
+        this.image_.onload = () => resolve();
+        this.image_.onerror = (e) =>
+            reject(new Error('Failed to load review document image: ${e}'));
+        this.image_.src = URL.createObjectURL(blob);
+      });
+    } finally {
+      URL.revokeObjectURL(this.image_.src);
+    }
+  }
+
+  /**
+   * @template T
+   * @param {{
+   *   primary: !Option<!T>,
+   *   others: (!Iterable<!Option<!T>>|undefined),
+   * }} options
+   * @return {!Promise<?T>}
+   */
+  async startReview({primary, others=[]}) {
+    // Remove all existing buttons.
+    while (this.btnGroups_.firstChild) {
+      this.btnGroups_.removeChild(this.btnGroups_.lastChild);
+    }
+
+    const onSelected = new WaitableEvent();
+    /**
+     * @param {!Option<!T>} option
+     * @param {boolean} isPrimary
+     */
+    const addButton = ({text, value}, isPrimary) => {
+      const templ = instantiateTemplate('#text-button-template');
+      const btn = dom.getFrom(templ, 'button', HTMLButtonElement);
+      btn.setAttribute('i18n-text', text);
+      if (isPrimary) {
+        btn.classList.add('primary');
+        this.primaryBtn_ = btn;
+      } else {
+        btn.classList.add('secondary');
+      }
+      btn.onclick = () => {
+        onSelected.signal(value);
+      };
+      this.btnGroups_.appendChild(templ);
+    };
+    addButton(primary, true);
+    for (const opt of others) {
+      addButton(opt, false);
+    }
+    this.retakeBtn_.onclick = () => {
+      onSelected.signal(null);
+    };
+    setupI18nElements(this.btnGroups_);
+
+    nav.open(ViewName.REVIEW);
+    const result = await onSelected.wait();
+    nav.close(ViewName.REVIEW);
+    this.image_.src = '';
+    return result;
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/js/views/review_document.js b/chromeos/components/camera_app_ui/resources/js/views/review_document.js
deleted file mode 100644
index c449426..0000000
--- a/chromeos/components/camera_app_ui/resources/js/views/review_document.js
+++ /dev/null
@@ -1,84 +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 * as dom from '../dom.js';
-import * as nav from '../nav.js';
-import {MimeType, ViewName} from '../type.js';
-
-import {View} from './view.js';
-
-/**
- * View controller for PTZ panel.
- */
-export class ReviewDocument extends View {
-  /**
-   * @public
-   */
-  constructor() {
-    super(ViewName.REVIEW_DOCUMENT);
-
-    /**
-     * @private {!HTMLImageElement}
-     * @const
-     */
-    this.image_ = dom.get('#document-image', HTMLImageElement);
-
-    /**
-     * @private {!HTMLButtonElement}
-     * @const
-     */
-    this.savePdf_ = dom.get('#save-pdf-document', HTMLButtonElement);
-
-    /**
-     * @private {!HTMLButtonElement}
-     * @const
-     */
-    this.savePhoto_ = dom.get('#save-photo-document', HTMLButtonElement);
-
-    /**
-     * @private {!HTMLButtonElement}
-     * @const
-     */
-    this.retake_ = dom.get('#retake-document', HTMLButtonElement);
-  }
-
-  /**
-   * @override
-   */
-  focus() {
-    this.savePdf_.focus();
-  }
-
-  /**
-   * @param {!Blob} blob
-   * @return {!Promise}
-   */
-  async setReviewDocument(blob) {
-    try {
-      await new Promise((resolve, reject) => {
-        this.image_.onload = () => resolve();
-        this.image_.onerror = (e) =>
-            reject(new Error('Failed to load review document image: ${e}'));
-        this.image_.src = URL.createObjectURL(blob);
-      });
-    } finally {
-      URL.revokeObjectURL(this.image_.src);
-    }
-  }
-
-  /**
-   * @return {!Promise<?MimeType>}
-   */
-  async startReview() {
-    nav.open(ViewName.REVIEW_DOCUMENT);
-    const result = await new Promise((resolve) => {
-      this.savePdf_.onclick = () => resolve(MimeType.PDF);
-      this.savePhoto_.onclick = () => resolve(MimeType.JPEG);
-      this.retake_.onclick = () => resolve(null);
-    });
-    nav.close(ViewName.REVIEW_DOCUMENT);
-    this.image_.src = '';
-    return result;
-  }
-}
diff --git a/chromeos/components/camera_app_ui/resources/js/views/settings.js b/chromeos/components/camera_app_ui/resources/js/views/settings.js
index 80533229..c6eb826 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/settings.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/settings.js
@@ -77,8 +77,7 @@
      * @const {!HTMLElement}
      * @private
      */
-    this.defaultFocus_ =
-        dom.getFrom(this.rootElement_, '[tabindex]', HTMLElement);
+    this.defaultFocus_ = dom.getFrom(this.root, '[tabindex]', HTMLElement);
 
     /**
      * The DOM element to be focused when the focus on view is reset by calling
diff --git a/chromeos/components/camera_app_ui/resources/js/views/view.js b/chromeos/components/camera_app_ui/resources/js/views/view.js
index c2d6acf..92fec0f 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/view.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/view.js
@@ -82,10 +82,9 @@
     this.name = name;
 
     /**
-     * @type {!HTMLElement}
-     * @protected
+     * @const {!HTMLElement}
      */
-    this.rootElement_ = dom.get(`#${name}`, HTMLElement);
+    this.root = dom.get(`#${name}`, HTMLElement);
 
     /**
      * Signal it to ends the session.
@@ -101,22 +100,13 @@
     this.dismissByEsc_ = dismissByEsc;
 
     if (dismissByBkgndClick) {
-      this.rootElement_.addEventListener(
+      this.root.addEventListener(
           'click',
-          (event) =>
-              event.target === this.rootElement_ && this.leave({bkgnd: true}));
+          (event) => event.target === this.root && this.leave({bkgnd: true}));
     }
   }
 
   /**
-   * HTML root node of this view.
-   * @return {!HTMLElement}
-   */
-  get root() {
-    return this.rootElement_;
-  }
-
-  /**
    * Gets sub-views nested under this view.
    * @return {!Array<!View>}
    */
diff --git a/chromeos/components/camera_app_ui/resources/views/main.html b/chromeos/components/camera_app_ui/resources/views/main.html
index 46d00f2..a7df414 100644
--- a/chromeos/components/camera_app_ui/resources/views/main.html
+++ b/chromeos/components/camera_app_ui/resources/views/main.html
@@ -18,7 +18,7 @@
     <link rel="stylesheet" href="/css/mode/video.css">
     <link rel="stylesheet" href="/css/new_feature_toast.css">
     <link rel="stylesheet" href="/css/ptz_panel.css">
-    <link rel="stylesheet" href="/css/review_document.css">
+    <link rel="stylesheet" href="/css/review.css">
     <script type="module" src="/js/init.js"></script>
   </head>
   <body class="sound mirror mic grid-3x3 view-splash">
@@ -274,18 +274,13 @@
         <div id="timer-tick-msg"></div>
       </div>
     </div>
-    <div id="view-review-document">
-      <div id="document-frame">
-        <img id="document-image">
+    <div id="view-review">
+      <div id="review-frame">
+        <img id="review-image">
       </div>
-      <div id="review-document-button-groups">
-        <button id="save-pdf-document" class="text-button pill primary dark
-                inkdrop" tabindex="0" i18n-text="label_save_pdf_document">
-        </button>
-        <button id="save-photo-document" class="text-button pill secondary dark
-                inkdrop" tabindex="0" i18n-text="label_save_photo_document">
-        </button>
-        <button id="retake-document" class="text-button pill secondary dark
+      <div class="button-groups">
+        <div class="positive-button-groups"></div>
+        <button id="review-retake" class="text-button pill secondary dark
                 inkdrop" tabindex="0" i18n-text="label_retake"></button>
       </div>
     </div>
@@ -661,5 +656,8 @@
         <span class="new-feature-toast-text" aria-hidden="true"></span>
       </div>
     </template>
+    <template id="text-button-template">
+      <button class="text-button pill dark inkdrop" tabindex="0"></button>
+    </template>
   </body>
 </html>
diff --git a/chromeos/components/phonehub/COMMON_METADATA b/chromeos/components/phonehub/COMMON_METADATA
new file mode 100644
index 0000000..b8834c5
--- /dev/null
+++ b/chromeos/components/phonehub/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Systems>Multidevice>PhoneHub"
+}
diff --git a/chromeos/components/phonehub/DIR_METADATA b/chromeos/components/phonehub/DIR_METADATA
index b8834c5..fb34eb9 100644
--- a/chromeos/components/phonehub/DIR_METADATA
+++ b/chromeos/components/phonehub/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Systems>Multidevice>PhoneHub"
-}
+mixins: "//chromeos/components/phonehub/COMMON_METADATA"
diff --git a/chromeos/components/phonehub/cros_state_sender.cc b/chromeos/components/phonehub/cros_state_sender.cc
index 361a070..01786746 100644
--- a/chromeos/components/phonehub/cros_state_sender.cc
+++ b/chromeos/components/phonehub/cros_state_sender.cc
@@ -89,10 +89,16 @@
   bool are_notifications_enabled =
       multidevice_setup_client_->GetFeatureState(
           Feature::kPhoneHubNotifications) == FeatureState::kEnabledByUser;
+  bool is_camera_roll_enabled =
+      multidevice_setup_client_->GetFeatureState(
+          Feature::kPhoneHubCameraRoll) == FeatureState::kEnabledByUser;
 
   PA_LOG(INFO) << "Attempting to send cros state with notifications enabled "
-               << "state as: " << are_notifications_enabled;
-  message_sender_->SendCrosState(are_notifications_enabled);
+               << "state as: " << are_notifications_enabled
+               << " and camera roll enabled state as: "
+               << is_camera_roll_enabled;
+  message_sender_->SendCrosState(are_notifications_enabled,
+                                 is_camera_roll_enabled);
 
   retry_timer_->Start(FROM_HERE, retry_delay_,
                       base::BindOnce(&CrosStateSender::OnRetryTimerFired,
diff --git a/chromeos/components/phonehub/cros_state_sender_unittest.cc b/chromeos/components/phonehub/cros_state_sender_unittest.cc
index 58a32f5..60dbdd7 100644
--- a/chromeos/components/phonehub/cros_state_sender_unittest.cc
+++ b/chromeos/components/phonehub/cros_state_sender_unittest.cc
@@ -106,6 +106,9 @@
   // Set notification feature to be enabled.
   fake_multidevice_setup_client_->SetFeatureState(
       Feature::kPhoneHubNotifications, FeatureState::kEnabledByUser);
+  // Set camera roll feature to be enabled.
+  fake_multidevice_setup_client_->SetFeatureState(Feature::kPhoneHubCameraRoll,
+                                                  FeatureState::kEnabledByUser);
   // Expect no new messages since connection has not been established.
   EXPECT_EQ(0u, fake_message_sender_->GetCrosStateCallCount());
   EXPECT_FALSE(mock_timer_->IsRunning());
@@ -120,7 +123,8 @@
   // Simulate connected state. Expect a new message to be sent.
   fake_connection_manager_->SetStatus(
       secure_channel::ConnectionManager::Status::kConnected);
-  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState());
+  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState().first);
+  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState().second);
   EXPECT_EQ(1u, fake_message_sender_->GetCrosStateCallCount());
 
   // Phone model is populated.
@@ -131,7 +135,8 @@
   // Simulate disconnected state, this should not trigger a new request.
   fake_connection_manager_->SetStatus(
       secure_channel::ConnectionManager::Status::kDisconnected);
-  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState());
+  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState().first);
+  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState().second);
   EXPECT_EQ(1u, fake_message_sender_->GetCrosStateCallCount());
   EXPECT_FALSE(mock_timer_->IsRunning());
 }
@@ -146,7 +151,8 @@
   EXPECT_TRUE(mock_timer_->IsRunning());
 
   // Expect new messages to be sent when connection state is connected.
-  EXPECT_FALSE(fake_message_sender_->GetRecentCrosState());
+  EXPECT_FALSE(fake_message_sender_->GetRecentCrosState().first);
+  EXPECT_FALSE(fake_message_sender_->GetRecentCrosState().second);
   EXPECT_EQ(1u, fake_message_sender_->GetCrosStateCallCount());
   mock_timer_->Fire();
 
@@ -154,7 +160,7 @@
   // enabled.
   fake_multidevice_setup_client_->SetFeatureState(
       Feature::kPhoneHubNotifications, FeatureState::kEnabledByUser);
-  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState());
+  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState().first);
   EXPECT_EQ(2u, fake_message_sender_->GetCrosStateCallCount());
   mock_timer_->Fire();
 
@@ -162,7 +168,7 @@
   // cros state.
   fake_multidevice_setup_client_->SetFeatureState(
       Feature::kSmartLock, FeatureState::kDisabledByUser);
-  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState());
+  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState().first);
   EXPECT_EQ(3u, fake_message_sender_->GetCrosStateCallCount());
   mock_timer_->Fire();
 
@@ -170,12 +176,19 @@
   // disabled.
   fake_multidevice_setup_client_->SetFeatureState(
       Feature::kPhoneHubNotifications, FeatureState::kDisabledByUser);
-  EXPECT_FALSE(fake_message_sender_->GetRecentCrosState());
+  EXPECT_FALSE(fake_message_sender_->GetRecentCrosState().first);
   EXPECT_EQ(4u, fake_message_sender_->GetCrosStateCallCount());
 
+  // Simulate enabling camera roll feature state and expect cros state to be
+  // updated.
+  fake_multidevice_setup_client_->SetFeatureState(Feature::kPhoneHubCameraRoll,
+                                                  FeatureState::kEnabledByUser);
+  EXPECT_TRUE(fake_message_sender_->GetRecentCrosState().second);
+  EXPECT_EQ(5u, fake_message_sender_->GetCrosStateCallCount());
+
   // Firing the timer does not cause the cros state to be sent again.
   mock_timer_->Fire();
-  EXPECT_EQ(4u, fake_message_sender_->GetCrosStateCallCount());
+  EXPECT_EQ(5u, fake_message_sender_->GetCrosStateCallCount());
 }
 
 }  // namespace phonehub
diff --git a/chromeos/components/phonehub/fake_message_sender.cc b/chromeos/components/phonehub/fake_message_sender.cc
index 180d57a8..506fcdd 100644
--- a/chromeos/components/phonehub/fake_message_sender.cc
+++ b/chromeos/components/phonehub/fake_message_sender.cc
@@ -10,8 +10,10 @@
 FakeMessageSender::FakeMessageSender() = default;
 FakeMessageSender::~FakeMessageSender() = default;
 
-void FakeMessageSender::SendCrosState(bool notification_enabled) {
-  cros_states_.push_back(notification_enabled);
+void FakeMessageSender::SendCrosState(bool notification_enabled,
+                                      bool camera_roll_enabled) {
+  cros_states_.push_back(
+      std::make_pair(notification_enabled, camera_roll_enabled));
 }
 
 void FakeMessageSender::SendUpdateNotificationModeRequest(
@@ -77,7 +79,7 @@
   return fetch_camera_roll_items_requests_.size();
 }
 
-bool FakeMessageSender::GetRecentCrosState() const {
+std::pair<bool, bool> FakeMessageSender::GetRecentCrosState() const {
   return cros_states_.back();
 }
 
diff --git a/chromeos/components/phonehub/fake_message_sender.h b/chromeos/components/phonehub/fake_message_sender.h
index 8ac1cfaf..aeb2b82d 100644
--- a/chromeos/components/phonehub/fake_message_sender.h
+++ b/chromeos/components/phonehub/fake_message_sender.h
@@ -22,7 +22,8 @@
   ~FakeMessageSender() override;
 
   // MessageSender:
-  void SendCrosState(bool notification_enabled) override;
+  void SendCrosState(bool notification_enabled,
+                     bool camera_roll_enabled) override;
   void SendUpdateNotificationModeRequest(bool do_not_disturb_enabled) override;
   void SendUpdateBatteryModeRequest(bool battery_saver_mode_enabled) override;
   void SendDismissNotificationRequest(int64_t notification_id) override;
@@ -34,7 +35,7 @@
   void SendFetchCameraRollItemsRequest(
       const proto::FetchCameraRollItemsRequest& request) override;
 
-  bool GetRecentCrosState() const;
+  std::pair<bool, bool> GetRecentCrosState() const;
   bool GetRecentUpdateNotificationModeRequest() const;
   bool GetRecentUpdateBatteryModeRequest() const;
   int64_t GetRecentDismissNotificationRequest() const;
@@ -63,7 +64,9 @@
   size_t GetFetchCameraRollItemsRequestCallCount() const;
 
  private:
-  std::vector<bool> cros_states_;
+  std::vector<std::pair</*is_notifications_setting_enabled*/ bool,
+                        /*is_camera_roll_setting_enabled*/ bool>>
+      cros_states_;
   std::vector<bool> update_notification_mode_requests_;
   std::vector<bool> update_battery_mode_requests_;
   std::vector<int64_t> dismiss_notification_requests_;
diff --git a/chromeos/components/phonehub/message_sender.h b/chromeos/components/phonehub/message_sender.h
index 4cd09b9..a9c52999 100644
--- a/chromeos/components/phonehub/message_sender.h
+++ b/chromeos/components/phonehub/message_sender.h
@@ -22,7 +22,8 @@
   virtual ~MessageSender() = default;
 
   // Sends whether the notification setting is enabled in the Chrome OS device.
-  virtual void SendCrosState(bool notification_setting_enabled) = 0;
+  virtual void SendCrosState(bool notification_setting_enabled,
+                             bool camera_roll_setting_enabled) = 0;
 
   // Requests that the phone enables or disables Do Not Disturb mode.
   virtual void SendUpdateNotificationModeRequest(
diff --git a/chromeos/components/phonehub/message_sender_impl.cc b/chromeos/components/phonehub/message_sender_impl.cc
index d3d2cd312..d16e36d 100644
--- a/chromeos/components/phonehub/message_sender_impl.cc
+++ b/chromeos/components/phonehub/message_sender_impl.cc
@@ -38,13 +38,18 @@
 
 MessageSenderImpl::~MessageSenderImpl() = default;
 
-void MessageSenderImpl::SendCrosState(bool notification_setting_enabled) {
+void MessageSenderImpl::SendCrosState(bool notification_setting_enabled,
+                                      bool camera_roll_setting_enabled) {
   proto::NotificationSetting is_notification_enabled =
       notification_setting_enabled
           ? proto::NotificationSetting::NOTIFICATIONS_ON
           : proto::NotificationSetting::NOTIFICATIONS_OFF;
+  proto::CameraRollSetting is_camera_roll_enabled =
+      camera_roll_setting_enabled ? proto::CameraRollSetting::CAMERA_ROLL_ON
+                                  : proto::CameraRollSetting::CAMERA_ROLL_OFF;
   proto::CrosState request;
   request.set_notification_setting(is_notification_enabled);
+  request.set_camera_roll_setting(is_camera_roll_enabled);
 
   SendMessage(proto::MessageType::PROVIDE_CROS_STATE, &request);
 }
diff --git a/chromeos/components/phonehub/message_sender_impl.h b/chromeos/components/phonehub/message_sender_impl.h
index 0f19ec2..cd689b70 100644
--- a/chromeos/components/phonehub/message_sender_impl.h
+++ b/chromeos/components/phonehub/message_sender_impl.h
@@ -27,7 +27,8 @@
   ~MessageSenderImpl() override;
 
   // MessageSender:
-  void SendCrosState(bool notification_setting_enabled) override;
+  void SendCrosState(bool notification_setting_enabled,
+                     bool camera_roll_setting_enabled) override;
   void SendUpdateNotificationModeRequest(bool do_not_disturb_enabled) override;
   void SendUpdateBatteryModeRequest(bool battery_saver_mode_enabled) override;
   void SendDismissNotificationRequest(int64_t notification_id) override;
diff --git a/chromeos/components/phonehub/message_sender_unittest.cc b/chromeos/components/phonehub/message_sender_unittest.cc
index 5df0ddd..9d1d053 100644
--- a/chromeos/components/phonehub/message_sender_unittest.cc
+++ b/chromeos/components/phonehub/message_sender_unittest.cc
@@ -64,8 +64,10 @@
   proto::CrosState request;
   request.set_notification_setting(
       proto::NotificationSetting::NOTIFICATIONS_ON);
+  request.set_camera_roll_setting(proto::CameraRollSetting::CAMERA_ROLL_OFF);
 
-  message_sender_->SendCrosState(/*notification_enabled=*/true);
+  message_sender_->SendCrosState(/*notification_enabled=*/true,
+                                 /*camera_roll_enabled=*/false);
   VerifyMessage(proto::MessageType::PROVIDE_CROS_STATE, &request,
                 fake_connection_manager_->sent_messages().back());
 }
diff --git a/chromeos/components/phonehub/proto/phonehub_api.proto b/chromeos/components/phonehub/proto/phonehub_api.proto
index 527dee8b..6ff53376 100644
--- a/chromeos/components/phonehub/proto/phonehub_api.proto
+++ b/chromeos/components/phonehub/proto/phonehub_api.proto
@@ -40,6 +40,11 @@
   NOTIFICATIONS_ON = 1;
 }
 
+enum CameraRollSetting {
+  CAMERA_ROLL_OFF = 0;
+  CAMERA_ROLL_ON = 1;
+}
+
 enum ChargingState {
   NOT_CHARGING = 0;
   CHARGING_AC = 1;
@@ -162,6 +167,7 @@
 
 message CrosState {
   NotificationSetting notification_setting = 1;
+  CameraRollSetting camera_roll_setting = 2;
 }
 
 message Action {
diff --git a/chromeos/components/tether/COMMON_METADATA b/chromeos/components/tether/COMMON_METADATA
new file mode 100644
index 0000000..2d80cfc
--- /dev/null
+++ b/chromeos/components/tether/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Systems>Multidevice>Tethering"
+}
diff --git a/chromeos/components/tether/DIR_METADATA b/chromeos/components/tether/DIR_METADATA
index 2d80cfc..c34c17f 100644
--- a/chromeos/components/tether/DIR_METADATA
+++ b/chromeos/components/tether/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Systems>Multidevice>Tethering"
-}
+mixins: "//chromeos/components/tether/COMMON_METADATA"
diff --git a/chromeos/components/web_applications/DIR_METADATA b/chromeos/components/web_applications/DIR_METADATA
index e9a95e53..118e79e 100644
--- a/chromeos/components/web_applications/DIR_METADATA
+++ b/chromeos/components/web_applications/DIR_METADATA
@@ -1,3 +1,4 @@
+mixins: "//chrome/browser/web_applications/COMMON_METADATA"
 monorail {
   component: "Platform>Apps>SystemWebApps"
 }
diff --git a/chromeos/dbus/COMMON_METADATA b/chromeos/dbus/COMMON_METADATA
new file mode 100644
index 0000000..06e78af
--- /dev/null
+++ b/chromeos/dbus/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Systems"
+}
diff --git a/chromeos/dbus/DIR_METADATA b/chromeos/dbus/DIR_METADATA
index 06e78af..40779e6 100644
--- a/chromeos/dbus/DIR_METADATA
+++ b/chromeos/dbus/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Systems"
-}
+mixins: "//chromeos/dbus/COMMON_METADATA"
diff --git a/chromeos/dbus/arc/DIR_METADATA b/chromeos/dbus/arc/DIR_METADATA
new file mode 100644
index 0000000..54a0fa6
--- /dev/null
+++ b/chromeos/dbus/arc/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/arc/COMMON_METADATA"
diff --git a/chromeos/dbus/kerberos/DIR_METADATA b/chromeos/dbus/kerberos/DIR_METADATA
index 5b704348d..3f20e21c 100644
--- a/chromeos/dbus/kerberos/DIR_METADATA
+++ b/chromeos/dbus/kerberos/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Software>Enterprise>ActiveDirectory"
-}
+mixins: "//chrome/browser/ash/kerberos/COMMON_METADATA"
diff --git a/chromeos/policy/COMMON_METADATA b/chromeos/policy/COMMON_METADATA
new file mode 100644
index 0000000..07b250a
--- /dev/null
+++ b/chromeos/policy/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Software>Enterprise"
+}
diff --git a/chromeos/policy/DIR_METADATA b/chromeos/policy/DIR_METADATA
index 07b250a..50ec60f 100644
--- a/chromeos/policy/DIR_METADATA
+++ b/chromeos/policy/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Software>Enterprise"
-}
+mixins: "//chromeos/policy/COMMON_METADATA"
diff --git a/chromeos/printing/COMMON_METADATA b/chromeos/printing/COMMON_METADATA
new file mode 100644
index 0000000..a57cdffa
--- /dev/null
+++ b/chromeos/printing/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Printing>CUPS"
+}
+team_email: "cros-printing-dev@chromium.org"
diff --git a/chromeos/printing/DIR_METADATA b/chromeos/printing/DIR_METADATA
index a57cdffa..bcaf2b74 100644
--- a/chromeos/printing/DIR_METADATA
+++ b/chromeos/printing/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Printing>CUPS"
-}
-team_email: "cros-printing-dev@chromium.org"
+mixins: "//chromeos/printing/COMMON_METADATA"
diff --git a/chromeos/services/assistant/DIR_METADATA b/chromeos/services/assistant/DIR_METADATA
index 5cf9e51..cfb0c371 100644
--- a/chromeos/services/assistant/DIR_METADATA
+++ b/chromeos/services/assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Shell>Assistant"
-}
+mixins: "//chromeos/assistant/COMMON_METADATA"
diff --git a/chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client.cc b/chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client.cc
index 07a22cd..3351a62 100644
--- a/chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client.cc
+++ b/chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client.cc
@@ -28,6 +28,8 @@
       {mojom::Feature::kPhoneHub, mojom::FeatureState::kProhibitedByPolicy},
       {mojom::Feature::kPhoneHubNotifications,
        mojom::FeatureState::kProhibitedByPolicy},
+      {mojom::Feature::kPhoneHubCameraRoll,
+       mojom::FeatureState::kProhibitedByPolicy},
       {mojom::Feature::kPhoneHubTaskContinuation,
        mojom::FeatureState::kProhibitedByPolicy},
       {mojom::Feature::kWifiSync, mojom::FeatureState::kProhibitedByPolicy},
diff --git a/chromeos/services/nearby/COMMON_METADATA b/chromeos/services/nearby/COMMON_METADATA
new file mode 100644
index 0000000..76bc6b2f
--- /dev/null
+++ b/chromeos/services/nearby/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Systems>Multidevice>Nearby"
+}
diff --git a/chromeos/services/nearby/DIR_METADATA b/chromeos/services/nearby/DIR_METADATA
index 76bc6b2f..24bdd08e 100644
--- a/chromeos/services/nearby/DIR_METADATA
+++ b/chromeos/services/nearby/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Systems>Multidevice>Nearby"
-}
+mixins: "//chromeos/services/nearby/COMMON_METADATA"
diff --git a/chromeos/settings/COMMON_METADATA b/chromeos/settings/COMMON_METADATA
new file mode 100644
index 0000000..07b250a
--- /dev/null
+++ b/chromeos/settings/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Software>Enterprise"
+}
diff --git a/chromeos/settings/DIR_METADATA b/chromeos/settings/DIR_METADATA
index 07b250a..f88e446 100644
--- a/chromeos/settings/DIR_METADATA
+++ b/chromeos/settings/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Software>Enterprise"
-}
+mixins: "//chromeos/settings/COMMON_METADATA"
diff --git a/chromeos/tpm/tpm_token_loader.cc b/chromeos/tpm/tpm_token_loader.cc
index 5fc135b..ff4781183 100644
--- a/chromeos/tpm/tpm_token_loader.cc
+++ b/chromeos/tpm/tpm_token_loader.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/notreached.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "base/system/sys_info.h"
@@ -110,18 +111,6 @@
     LoginState::Get()->RemoveObserver(this);
 }
 
-TPMTokenLoader::TPMTokenStatus TPMTokenLoader::IsTPMTokenEnabled(
-    TPMReadyCallback callback) {
-  if (tpm_token_state_ == TPM_TOKEN_INITIALIZED)
-    return TPM_TOKEN_STATUS_ENABLED;
-  if (!IsTPMLoadingEnabled() || tpm_token_state_ == TPM_DISABLED)
-    return TPM_TOKEN_STATUS_DISABLED;
-  // Status is not known yet.
-  if (callback)
-    tpm_ready_callback_list_.push_back(std::move(callback));
-  return TPM_TOKEN_STATUS_UNDETERMINED;
-}
-
 bool TPMTokenLoader::IsTPMLoadingEnabled() const {
   // TPM loading is enabled on non-ChromeOS environments, e.g. when running
   // tests on Linux.
@@ -161,25 +150,13 @@
 
   switch (tpm_token_state_) {
     case TPM_STATE_UNKNOWN: {
-      crypto_task_runner_->PostTaskAndReply(
-          FROM_HERE, base::BindOnce(&crypto::EnableTPMTokenForNSS),
-          base::BindOnce(&TPMTokenLoader::OnTPMTokenEnabledForNSS,
-                         weak_factory_.GetWeakPtr()));
       tpm_token_state_ = TPM_INITIALIZATION_STARTED;
-      return;
-    }
-    case TPM_INITIALIZATION_STARTED: {
-      NOTREACHED();
-      return;
-    }
-    case TPM_TOKEN_ENABLED_FOR_NSS: {
       tpm_token_info_getter_->Start(base::BindOnce(
           &TPMTokenLoader::OnGotTpmTokenInfo, weak_factory_.GetWeakPtr()));
       return;
     }
-    case TPM_DISABLED: {
-      // TPM is disabled, so proceed with empty tpm token name.
-      NotifyTPMTokenReady();
+    case TPM_INITIALIZATION_STARTED: {
+      NOTREACHED();
       return;
     }
     case TPM_TOKEN_INFO_RECEIVED: {
@@ -193,19 +170,14 @@
                                  weak_factory_.GetWeakPtr()))));
       return;
     }
-    case TPM_TOKEN_INITIALIZED: {
+    case TPM_TOKEN_INITIALIZED:
+    case TPM_DISABLED: {
       NotifyTPMTokenReady();
       return;
     }
   }
 }
 
-void TPMTokenLoader::OnTPMTokenEnabledForNSS() {
-  VLOG(1) << "TPMTokenEnabledForNSS";
-  tpm_token_state_ = TPM_TOKEN_ENABLED_FOR_NSS;
-  ContinueTokenInitialization();
-}
-
 void TPMTokenLoader::OnGotTpmTokenInfo(
     absl::optional<user_data_auth::TpmTokenInfo> token_info) {
   if (!token_info.has_value()) {
@@ -229,12 +201,9 @@
 }
 
 void TPMTokenLoader::NotifyTPMTokenReady() {
-  DCHECK(tpm_token_state_ == TPM_DISABLED ||
-         tpm_token_state_ == TPM_TOKEN_INITIALIZED);
-  bool tpm_status = tpm_token_state_ == TPM_TOKEN_INITIALIZED;
-  for (TPMReadyCallback& callback : tpm_ready_callback_list_)
-    std::move(callback).Run(tpm_status);
-  tpm_ready_callback_list_.clear();
+  crypto_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&crypto::FinishInitializingTPMTokenAndSystemSlot));
 }
 
 void TPMTokenLoader::LoggedInStateChanged() {
diff --git a/chromeos/tpm/tpm_token_loader.h b/chromeos/tpm/tpm_token_loader.h
index d394b0a6..d7e5fe6 100644
--- a/chromeos/tpm/tpm_token_loader.h
+++ b/chromeos/tpm/tpm_token_loader.h
@@ -41,9 +41,6 @@
     TPM_TOKEN_STATUS_DISABLED
   };
 
-  using TPMReadyCallback = base::OnceCallback<void(bool)>;
-  using TPMReadyCallbackList = std::vector<TPMReadyCallback>;
-
   // Sets the global instance. Must be called before any calls to Get().
   // The global instance will immediately start observing |LoginState|.
   static void Initialize();
@@ -74,10 +71,6 @@
   // login state changes to LOGGED_IN_ACTIVE.
   void EnsureStarted();
 
-  // Checks if the TPM token is enabled. If the state is unknown, |callback|
-  // will be called back once the TPM state is known.
-  TPMTokenStatus IsTPMTokenEnabled(TPMReadyCallback callback);
-
   std::string tpm_user_pin() const { return tpm_user_pin_; }
 
   // Allows tests to enable the TPM token loading logic in this class.
@@ -112,17 +105,14 @@
 
   bool initialized_for_test_;
 
-  TPMReadyCallbackList tpm_ready_callback_list_;
-
   // The states are traversed in this order but some might get omitted or never
   // be left.
   enum TPMTokenState {
     TPM_STATE_UNKNOWN,
     TPM_INITIALIZATION_STARTED,
-    TPM_TOKEN_ENABLED_FOR_NSS,
-    TPM_DISABLED,
     TPM_TOKEN_INFO_RECEIVED,
     TPM_TOKEN_INITIALIZED,
+    TPM_DISABLED,
   };
   TPMTokenState tpm_token_state_;
 
diff --git a/chromeos/ui/vector_icons/DIR_METADATA b/chromeos/ui/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/chromeos/ui/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/cloud_print/COMMON_METADATA b/cloud_print/COMMON_METADATA
new file mode 100644
index 0000000..c3c4f77
--- /dev/null
+++ b/cloud_print/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Services>CloudPrint"
+}
\ No newline at end of file
diff --git a/cloud_print/DIR_METADATA b/cloud_print/DIR_METADATA
index 306aa5c..5a10f9d 100644
--- a/cloud_print/DIR_METADATA
+++ b/cloud_print/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Services>CloudPrint"
-}
\ No newline at end of file
+mixins: "//cloud_print/COMMON_METADATA"
diff --git a/components/accuracy_tips/COMMON_METADATA b/components/accuracy_tips/COMMON_METADATA
new file mode 100644
index 0000000..db7a5c4a
--- /dev/null
+++ b/components/accuracy_tips/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Privacy"
+}
diff --git a/components/accuracy_tips/DIR_METADATA b/components/accuracy_tips/DIR_METADATA
index db7a5c4a..1ed35b0 100644
--- a/components/accuracy_tips/DIR_METADATA
+++ b/components/accuracy_tips/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Privacy"
-}
+mixins: "//components/accuracy_tips/COMMON_METADATA"
diff --git a/components/arc/COMMON_METADATA b/components/arc/COMMON_METADATA
new file mode 100644
index 0000000..e568bf01
--- /dev/null
+++ b/components/arc/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Platform>Apps>ARC"
+}
diff --git a/components/arc/DIR_METADATA b/components/arc/DIR_METADATA
index e568bf01..54a0fa6 100644
--- a/components/arc/DIR_METADATA
+++ b/components/arc/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>ARC"
-}
+mixins: "//components/arc/COMMON_METADATA"
diff --git a/components/arc/media_session/DIR_METADATA b/components/arc/media_session/DIR_METADATA
index 49ac631..da1d684 100644
--- a/components/arc/media_session/DIR_METADATA
+++ b/components/arc/media_session/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Media>Session"
-}
+mixins: "//services/media_session/COMMON_METADATA"
diff --git a/components/arc/vector_icons/DIR_METADATA b/components/arc/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/components/arc/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/components/autofill/COMMON_METADATA b/components/autofill/COMMON_METADATA
new file mode 100644
index 0000000..3994ddc
--- /dev/null
+++ b/components/autofill/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Autofill"
+}
+team_email: "chrome-autofill@google.com"
diff --git a/components/autofill/DIR_METADATA b/components/autofill/DIR_METADATA
index 3994ddc..bc280336 100644
--- a/components/autofill/DIR_METADATA
+++ b/components/autofill/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Autofill"
-}
-team_email: "chrome-autofill@google.com"
+mixins: "//components/autofill/COMMON_METADATA"
diff --git a/components/autofill_assistant/COMMON_METADATA b/components/autofill_assistant/COMMON_METADATA
new file mode 100644
index 0000000..2c84cedc
--- /dev/null
+++ b/components/autofill_assistant/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Autofill>Assistant"
+}
diff --git a/components/autofill_assistant/DIR_METADATA b/components/autofill_assistant/DIR_METADATA
index 2c84cedc..a5aa36b6 100644
--- a/components/autofill_assistant/DIR_METADATA
+++ b/components/autofill_assistant/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Autofill>Assistant"
-}
+mixins: "//components/autofill_assistant/COMMON_METADATA"
diff --git a/components/autofill_assistant/browser/display_strings_util.cc b/components/autofill_assistant/browser/display_strings_util.cc
index 9038d40..179e953 100644
--- a/components/autofill_assistant/browser/display_strings_util.cc
+++ b/components/autofill_assistant/browser/display_strings_util.cc
@@ -12,9 +12,6 @@
 int MapDisplayStringIdToChromeMessage(
     ClientSettingsProto::DisplayStringId display_string_id) {
   switch (display_string_id) {
-    case ClientSettingsProto::UNSPECIFIED:
-      // Shouldn't happen. Returning default error.
-      return IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR;
     case ClientSettingsProto::GIVE_UP:
       return IDS_AUTOFILL_ASSISTANT_GIVE_UP;
     case ClientSettingsProto::MAYBE_GIVE_UP:
@@ -33,6 +30,11 @@
       return IDS_CLOSE;
     case ClientSettingsProto::SETTINGS:
       return IDS_SETTINGS_TITLE;
+
+    case ClientSettingsProto::UNSPECIFIED:
+    case ClientSettingsProto::UNDO:
+      // This should not happen.
+      return -1;
   }
 }
 
@@ -46,6 +48,11 @@
     // Note that we return the string even if it is empty.
     return it->second;
   }
+  if (display_string_id == ClientSettingsProto::UNSPECIFIED ||
+      display_string_id == ClientSettingsProto::UNDO) {
+    // TODO(b/201396990) Provide fallback string for UNDO.
+    return "";
+  }
   return l10n_util::GetStringUTF8(
       MapDisplayStringIdToChromeMessage(display_string_id));
 }
diff --git a/components/autofill_assistant/browser/display_strings_util_unittest.cc b/components/autofill_assistant/browser/display_strings_util_unittest.cc
index 27ce706..190c4b9 100644
--- a/components/autofill_assistant/browser/display_strings_util_unittest.cc
+++ b/components/autofill_assistant/browser/display_strings_util_unittest.cc
@@ -23,10 +23,9 @@
   for (int i = 0; i < ClientSettingsProto::DisplayStringId_MAX + 1; i++) {
     switch (static_cast<ClientSettingsProto::DisplayStringId>(i)) {
       case ClientSettingsProto::UNSPECIFIED:
-        EXPECT_EQ(
-            GetDisplayStringUTF8(ClientSettingsProto::UNSPECIFIED,
-                                 client_settings),
-            l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR));
+        EXPECT_EQ(GetDisplayStringUTF8(ClientSettingsProto::UNSPECIFIED,
+                                       client_settings),
+                  "");
         break;
       case ClientSettingsProto::GIVE_UP:
         EXPECT_EQ(
@@ -79,6 +78,11 @@
                                        client_settings),
                   l10n_util::GetStringUTF8(IDS_SETTINGS_TITLE));
         break;
+      case ClientSettingsProto::UNDO:
+        EXPECT_EQ(
+            GetDisplayStringUTF8(ClientSettingsProto::UNDO, client_settings),
+            "");
+        break;
     }
   }
 }
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 840dbfd..f82f7bd 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -70,7 +70,6 @@
     const std::string& global_payload,
     const std::string& script_payload,
     ScriptExecutor::Listener* listener,
-    std::map<std::string, ScriptStatus>* scripts_state,
     const std::vector<std::unique_ptr<Script>>* ordered_interrupts,
     ScriptExecutorDelegate* delegate)
     : script_path_(script_path),
@@ -81,7 +80,6 @@
       listener_(listener),
       delegate_(delegate),
       ordered_interrupts_(ordered_interrupts),
-      scripts_state_(scripts_state),
       element_store_(
           std::make_unique<ElementStore>(delegate->GetWebContents())) {
   DCHECK(delegate_);
@@ -103,7 +101,6 @@
 #else
   DVLOG(2) << "Starting script " << script_path_;
 #endif
-  (*scripts_state_)[script_path_] = ScriptStatus::RUNNING;
 
   DCHECK(user_data);
   user_data_ = user_data;
@@ -917,8 +914,6 @@
 
 void ScriptExecutor::RunCallbackWithResult(const Result& result) {
   DCHECK(callback_);
-  (*scripts_state_)[script_path_] =
-      result.success ? ScriptStatus::SUCCESS : ScriptStatus::FAILURE;
   std::move(callback_).Run(result);
 }
 
@@ -1266,8 +1261,7 @@
       std::make_unique<TriggerContext>(std::vector<const TriggerContext*>{
           main_script_->additional_context_.get()}),
       main_script_->last_global_payload_, main_script_->initial_script_payload_,
-      /* listener= */ this, main_script_->scripts_state_, &no_interrupts_,
-      delegate_);
+      /* listener= */ this, &no_interrupts_, delegate_);
   delegate_->EnterState(AutofillAssistantState::RUNNING);
   delegate_->SetUserActions(nullptr);
   interrupt_executor_->Run(
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index d061f734..ebc2ebd 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -42,23 +42,6 @@
                        public ScriptExecutorDelegate::NavigationListener,
                        public ScriptExecutorDelegate::Listener {
  public:
-  // States a script can end up in.
-  enum class ScriptStatus {
-    // Never explicitly set. Reading this value means the enum field is either
-    // not set or set to a value not listed here.
-    UNKNOWN,
-    // The script finished successfully.
-    SUCCESS,
-    // The script failed.
-    FAILURE,
-    // The user cancelled the script.
-    CANCELLED,
-    // The script is currently running.
-    RUNNING,
-    // The script was not run.
-    NOT_RUN,
-  };
-
   // Listens to events on ScriptExecutor.
   // TODO(b/806868): Make global_payload a part of callback instead of the
   // listener.
@@ -85,7 +68,6 @@
                  const std::string& global_payload,
                  const std::string& script_payload,
                  ScriptExecutor::Listener* listener,
-                 std::map<std::string, ScriptStatus>* scripts_state,
                  const std::vector<std::unique_ptr<Script>>* ordered_interrupts,
                  ScriptExecutorDelegate* delegate);
 
@@ -477,7 +459,6 @@
   // change while the script is running, as a result of OnScriptListChanged
   // being called.
   const std::vector<std::unique_ptr<Script>>* const ordered_interrupts_;
-  std::map<std::string, ScriptStatus>* const scripts_state_;
   std::unique_ptr<ElementStore> element_store_;
   RunScriptCallback callback_;
   std::vector<std::unique_ptr<Action>> actions_;
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc
index f8ba8205..9b12776 100644
--- a/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -68,7 +68,7 @@
             options),
         /* global_payload= */ "initial global payload",
         /* script_payload= */ "initial payload",
-        /* listener= */ this, &scripts_state_, &ordered_interrupts_,
+        /* listener= */ this, &ordered_interrupts_,
         /* delegate= */ &delegate_);
 
     test_util::MockFindAnyElement(mock_web_controller_);
@@ -159,7 +159,6 @@
   Script script_;
   StrictMock<MockService> mock_service_;
   NiceMock<MockWebController> mock_web_controller_;
-  std::map<std::string, ScriptExecutor::ScriptStatus> scripts_state_;
 
   std::vector<std::unique_ptr<Script>> ordered_interrupts_;
   std::string last_global_payload_;
@@ -885,47 +884,6 @@
   EXPECT_THAT(delegate_.GetDetails(), IsEmpty());
 }
 
-TEST_F(ScriptExecutorTest, UpdateScriptStateWhileRunning) {
-  // OnGetNextActions never calls the callback, so Run() returns immediately
-  // without doing anything.
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _));
-
-  EXPECT_THAT(scripts_state_, IsEmpty());
-  executor_->Run(&user_data_, executor_callback_.Get());
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::RUNNING)));
-}
-
-TEST_F(ScriptExecutorTest, UpdateScriptStateOnError) {
-  EXPECT_CALL(mock_service_, OnGetActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_UNAUTHORIZED, ""));
-  EXPECT_CALL(executor_callback_,
-              Run(Field(&ScriptExecutor::Result::success, false)));
-  executor_->Run(&user_data_, executor_callback_.Get());
-
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::FAILURE)));
-}
-
-TEST_F(ScriptExecutorTest, UpdateScriptStateOnSuccess) {
-  ActionsResponseProto initial_actions_response;
-  initial_actions_response.add_actions()->mutable_tell()->set_message("ok");
-  EXPECT_CALL(mock_service_, OnGetActions(StrEq(kScriptPath), _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK,
-                                   Serialize(initial_actions_response)));
-  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillOnce(RunOnceCallback<5>(net::HTTP_OK, ""));
-  EXPECT_CALL(executor_callback_,
-              Run(Field(&ScriptExecutor::Result::success, true)));
-  executor_->Run(&user_data_, executor_callback_.Get());
-
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::SUCCESS)));
-}
-
 TEST_F(ScriptExecutorTest, ForwardLastPayloadOnSuccess) {
   ActionsResponseProto actions_response;
   actions_response.set_global_payload("actions global payload");
@@ -1010,7 +968,7 @@
   SetupInterruptibleScript(kScriptPath, "element");
   SetupInterrupt("interrupt", "interrupt_trigger");
 
-  // Both scripts ends after the first set of actions. Capture the results.
+  // Both scripts end after the first set of actions. Capture the results.
   std::vector<ProcessedActionProto> processed_actions1_capture;
   std::vector<ProcessedActionProto> processed_actions2_capture;
   EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
@@ -1023,13 +981,6 @@
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(&user_data_, executor_callback_.Get());
 
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::SUCCESS)));
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair("interrupt", ScriptExecutor::ScriptStatus::SUCCESS)));
-
   // The first script to call OnGetNextActions is the interrupt, which starts
   // with a tell.
   ASSERT_THAT(processed_actions1_capture, Not(IsEmpty()));
@@ -1068,16 +1019,6 @@
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(&user_data_, executor_callback_.Get());
-
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::SUCCESS)));
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair("interrupt1", ScriptExecutor::ScriptStatus::SUCCESS)));
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair("interrupt2", ScriptExecutor::ScriptStatus::SUCCESS)));
 }
 
 TEST_F(ScriptExecutorTest, RunSameInterruptMultipleTimes) {
@@ -1178,17 +1119,21 @@
       .WillRepeatedly(
           RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
 
+  // The script ends after the first set of actions. There is only one call
+  // from the main script, running a WaitForDom - none from the interrupt.
+  std::vector<ProcessedActionProto> processed_actions_capture;
   EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
+      .WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
+                      RunOnceCallback<5>(net::HTTP_OK, "")));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(&user_data_, executor_callback_.Get());
 
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::SUCCESS)));
-  EXPECT_THAT(scripts_state_, Not(Contains(Pair(StrEq("interrupt"), _))));
+  ASSERT_THAT(processed_actions_capture, Not(IsEmpty()));
+  EXPECT_EQ(ActionProto::ActionInfoCase::kWaitForDom,
+            processed_actions_capture[0].action().action_info_case());
+  EXPECT_EQ(ACTION_APPLIED, processed_actions_capture[0].status());
 }
 
 TEST_F(ScriptExecutorTest, DoNotRunInterruptIfNotInterruptible) {
@@ -1205,17 +1150,21 @@
   // given an opportunity to.
   SetupInterrupt("interrupt", "interrupt_trigger");
 
+  // The script ends after the first set of actions. There is only one call
+  // from the main script, running a WaitForDom - none from the interrupt.
+  std::vector<ProcessedActionProto> processed_actions_capture;
   EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _))
-      .WillRepeatedly(RunOnceCallback<5>(net::HTTP_OK, ""));
+      .WillOnce(DoAll(SaveArg<3>(&processed_actions_capture),
+                      RunOnceCallback<5>(net::HTTP_OK, "")));
 
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(&user_data_, executor_callback_.Get());
 
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::SUCCESS)));
-  EXPECT_THAT(scripts_state_, Not(Contains(Pair(StrEq("interrupt"), _))));
+  ASSERT_THAT(processed_actions_capture, Not(IsEmpty()));
+  EXPECT_EQ(ActionProto::ActionInfoCase::kWaitForDom,
+            processed_actions_capture[0].action().action_info_case());
+  EXPECT_EQ(ACTION_APPLIED, processed_actions_capture[0].status());
 }
 
 TEST_F(ScriptExecutorTest, InterruptFailsMainScript) {
@@ -1242,13 +1191,6 @@
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, false)));
   executor_->Run(&user_data_, executor_callback_.Get());
-
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::FAILURE)));
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair("interrupt", ScriptExecutor::ScriptStatus::FAILURE)));
 }
 
 TEST_F(ScriptExecutorTest, InterruptReturnsShutdown) {
@@ -1276,13 +1218,6 @@
                         Field(&ScriptExecutor::Result::at_end,
                               ScriptExecutor::SHUTDOWN))));
   executor_->Run(&user_data_, executor_callback_.Get());
-
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::SUCCESS)));
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair("interrupt", ScriptExecutor::ScriptStatus::SUCCESS)));
 }
 
 TEST_F(ScriptExecutorTest, RunInterruptDuringPrompt) {
@@ -1323,13 +1258,6 @@
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(&user_data_, executor_callback_.Get());
 
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::SUCCESS)));
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair("interrupt", ScriptExecutor::ScriptStatus::SUCCESS)));
-
   // Expected scenario:
   // - show prompt (enter PROMPT state)
   // - notice interrupt_trigger element
@@ -1425,18 +1353,9 @@
   EXPECT_CALL(executor_callback_,
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(&user_data_, executor_callback_.Get());
-  for (int try_count = 0;
-       try_count < 10 &&
-       scripts_state_[kScriptPath] == ScriptExecutor::ScriptStatus::RUNNING;
-       try_count++) {
+  for (int try_count = 0; try_count < 10; try_count++) {
     task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
   }
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::SUCCESS)));
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair("interrupt", ScriptExecutor::ScriptStatus::SUCCESS)));
 
   EXPECT_THAT(
       delegate_.GetStateHistory(),
@@ -1545,13 +1464,6 @@
               Run(Field(&ScriptExecutor::Result::success, true)));
   executor_->Run(&user_data_, executor_callback_.Get());
 
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair(kScriptPath, ScriptExecutor::ScriptStatus::SUCCESS)));
-  EXPECT_THAT(
-      scripts_state_,
-      Contains(Pair("interrupt", ScriptExecutor::ScriptStatus::SUCCESS)));
-
   EXPECT_TRUE(should_update_scripts_);
   EXPECT_THAT(scripts_update_, SizeIs(1));
   EXPECT_THAT(scripts_update_count_, Eq(1));
diff --git a/components/autofill_assistant/browser/script_tracker.cc b/components/autofill_assistant/browser/script_tracker.cc
index ad13d2a..185c2c61 100644
--- a/components/autofill_assistant/browser/script_tracker.cc
+++ b/components/autofill_assistant/browser/script_tracker.cc
@@ -125,7 +125,7 @@
   executor_ = std::make_unique<ScriptExecutor>(
       script_path, std::move(context), last_global_payload_,
       last_script_payload_,
-      /* listener= */ this, &scripts_state_, &interrupts_, delegate_);
+      /* listener= */ this, &interrupts_, delegate_);
   ScriptExecutor::RunScriptCallback run_script_callback = base::BindOnce(
       &ScriptTracker::OnScriptRun, weak_ptr_factory_.GetWeakPtr(), script_path,
       std::move(callback));
diff --git a/components/autofill_assistant/browser/script_tracker.h b/components/autofill_assistant/browser/script_tracker.h
index 3033246..9257c92 100644
--- a/components/autofill_assistant/browser/script_tracker.h
+++ b/components/autofill_assistant/browser/script_tracker.h
@@ -156,13 +156,6 @@
   // SetScripts() reset this.
   std::vector<std::unique_ptr<Script>> interrupts_;
 
-  // List of scripts that have been executed and their corresponding statuses.
-  //
-  // TODO(b/192823175): Note that this map's only remaining use is in tests and
-  // can be removed once the testing code has been refactored to no longer
-  // depend on this field.
-  std::map<std::string, ScriptExecutor::ScriptStatus> scripts_state_;
-
   std::unique_ptr<BatchElementChecker> batch_element_checker_;
 
   // Path of the scripts found to be runnable so far, in the current check,
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 928319e..95d0250 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -349,6 +349,9 @@
 
     // Title for Chrome's Settings.
     SETTINGS = 9;
+
+    // Undo message for snackbar.
+    UNDO = 10;
   }
 
   // A Chrome display string along with its ID. This is used to create a map of
diff --git a/components/background_fetch/DIR_METADATA b/components/background_fetch/DIR_METADATA
index 774edd1..7a535e15 100644
--- a/components/background_fetch/DIR_METADATA
+++ b/components/background_fetch/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Blink>BackgroundFetch"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//content/browser/background_fetch/COMMON_METADATA"
diff --git a/components/background_sync/COMMON_METADATA b/components/background_sync/COMMON_METADATA
new file mode 100644
index 0000000..0cc412a5
--- /dev/null
+++ b/components/background_sync/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>BackgroundSync"
+}
+
+team_email: "platform-capabilities@chromium.org"
diff --git a/components/background_sync/DIR_METADATA b/components/background_sync/DIR_METADATA
index 0cc412a5..5a35032 100644
--- a/components/background_sync/DIR_METADATA
+++ b/components/background_sync/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>BackgroundSync"
-}
+mixins: "//components/background_sync/COMMON_METADATA"
 
-team_email: "platform-capabilities@chromium.org"
diff --git a/components/background_task_scheduler/COMMON_METADATA b/components/background_task_scheduler/COMMON_METADATA
new file mode 100644
index 0000000..dc57d9b
--- /dev/null
+++ b/components/background_task_scheduler/COMMON_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Internals>BackgroundTaskScheduler"
+}
+
+team_email: "clank-dev@google.com"
+
+os: ANDROID
diff --git a/components/background_task_scheduler/DIR_METADATA b/components/background_task_scheduler/DIR_METADATA
index dc57d9b..1072541 100644
--- a/components/background_task_scheduler/DIR_METADATA
+++ b/components/background_task_scheduler/DIR_METADATA
@@ -1,7 +1,2 @@
-monorail {
-  component: "Internals>BackgroundTaskScheduler"
-}
+mixins: "//components/background_task_scheduler/COMMON_METADATA"
 
-team_email: "clank-dev@google.com"
-
-os: ANDROID
diff --git a/components/blocked_content/COMMON_METADATA b/components/blocked_content/COMMON_METADATA
new file mode 100644
index 0000000..7353851
--- /dev/null
+++ b/components/blocked_content/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>PopupBlocker"
+}
diff --git a/components/blocked_content/DIR_METADATA b/components/blocked_content/DIR_METADATA
index 7353851..42e50743 100644
--- a/components/blocked_content/DIR_METADATA
+++ b/components/blocked_content/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>PopupBlocker"
-}
+mixins: "//components/blocked_content/COMMON_METADATA"
diff --git a/components/browser_ui/http_auth/android/DIR_METADATA b/components/browser_ui/http_auth/android/DIR_METADATA
new file mode 100644
index 0000000..c69388e
--- /dev/null
+++ b/components/browser_ui/http_auth/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/components/browser_ui/settings/DIR_METADATA b/components/browser_ui/settings/DIR_METADATA
new file mode 100644
index 0000000..971e38c
--- /dev/null
+++ b/components/browser_ui/settings/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/settings/COMMON_METADATA"
diff --git a/components/browser_ui/site_settings/COMMON_METADATA b/components/browser_ui/site_settings/COMMON_METADATA
new file mode 100644
index 0000000..4752c120
--- /dev/null
+++ b/components/browser_ui/site_settings/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Mobile>Settings"
+}
diff --git a/components/browser_ui/site_settings/DIR_METADATA b/components/browser_ui/site_settings/DIR_METADATA
index 4752c120..ea846f1 100644
--- a/components/browser_ui/site_settings/DIR_METADATA
+++ b/components/browser_ui/site_settings/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Mobile>Settings"
-}
+mixins: "//components/browser_ui/site_settings/COMMON_METADATA"
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
index 325e7b8..13754db 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -69,6 +69,9 @@
     public static final String EXTRA_SITE = "org.chromium.chrome.preferences.site";
     public static final String EXTRA_SITE_ADDRESS = "org.chromium.chrome.preferences.site_address";
 
+    // A boolean to configure whether the sound setting should be shown. Defaults to true.
+    public static final String EXTRA_SHOW_SOUND = "org.chromium.chrome.preferences.show_sound";
+
     // Used to store mPreviousNotificationPermission when the activity is paused.
     private static final String PREVIOUS_NOTIFICATION_PERMISSION_KEY =
             "previous_notification_permission";
@@ -952,6 +955,10 @@
     }
 
     private void setUpSoundPreference(Preference preference) {
+        if (!getArguments().getBoolean(EXTRA_SHOW_SOUND, true)) {
+            return;
+        }
+
         BrowserContextHandle browserContextHandle =
                 getSiteSettingsDelegate().getBrowserContextHandle();
         @ContentSettingValues
diff --git a/components/browser_ui/util/android/DIR_METADATA b/components/browser_ui/util/android/DIR_METADATA
new file mode 100644
index 0000000..c69388e
--- /dev/null
+++ b/components/browser_ui/util/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/components/browser_ui/widget/android/DIR_METADATA b/components/browser_ui/widget/android/DIR_METADATA
new file mode 100644
index 0000000..c69388e
--- /dev/null
+++ b/components/browser_ui/widget/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/components/browsing_data/DIR_METADATA b/components/browsing_data/DIR_METADATA
index db7a5c4a..ce654ba 100644
--- a/components/browsing_data/DIR_METADATA
+++ b/components/browsing_data/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Privacy"
-}
+mixins: "//content/browser/browsing_data/COMMON_METADATA"
diff --git a/components/cast_certificate/COMMON_METADATA b/components/cast_certificate/COMMON_METADATA
new file mode 100644
index 0000000..b339e61
--- /dev/null
+++ b/components/cast_certificate/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Chromecast"
+}
diff --git a/components/cast_certificate/DIR_METADATA b/components/cast_certificate/DIR_METADATA
index b339e61..25e6a775 100644
--- a/components/cast_certificate/DIR_METADATA
+++ b/components/cast_certificate/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Chromecast"
-}
+mixins: "//components/cast_certificate/COMMON_METADATA"
diff --git a/components/chrome_cleaner/DIR_METADATA b/components/chrome_cleaner/DIR_METADATA
index c5f6b73..2213f1c1 100644
--- a/components/chrome_cleaner/DIR_METADATA
+++ b/components/chrome_cleaner/DIR_METADATA
@@ -1,5 +1,3 @@
-monorail {
-  component: "Services>Safebrowsing>ChromeCleanup"
-}
+mixins: "//chrome/chrome_cleaner/COMMON_METADATA"
 
 team_email: "security-dev@chromium.org"
diff --git a/components/client_hints/COMMON_METADATA b/components/client_hints/COMMON_METADATA
new file mode 100644
index 0000000..8529bd6b
--- /dev/null
+++ b/components/client_hints/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Loader"
+}
diff --git a/components/client_hints/DIR_METADATA b/components/client_hints/DIR_METADATA
index 8529bd6b..7c929fe 100644
--- a/components/client_hints/DIR_METADATA
+++ b/components/client_hints/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Loader"
-}
+mixins: "//components/client_hints/COMMON_METADATA"
diff --git a/components/component_updater/COMMON_METADATA b/components/component_updater/COMMON_METADATA
new file mode 100644
index 0000000..f29e6cf
--- /dev/null
+++ b/components/component_updater/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>Installer>Components"
+}
+
+team_email: "chrome-updates-dev@chromium.org"
diff --git a/components/component_updater/DIR_METADATA b/components/component_updater/DIR_METADATA
index f29e6cf..887b7f5 100644
--- a/components/component_updater/DIR_METADATA
+++ b/components/component_updater/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Installer>Components"
-}
+mixins: "//components/component_updater/COMMON_METADATA"
 
-team_email: "chrome-updates-dev@chromium.org"
diff --git a/components/consent_auditor/COMMON_METADATA b/components/consent_auditor/COMMON_METADATA
new file mode 100644
index 0000000..db7a5c4a
--- /dev/null
+++ b/components/consent_auditor/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Privacy"
+}
diff --git a/components/consent_auditor/DIR_METADATA b/components/consent_auditor/DIR_METADATA
index db7a5c4a..c75f2f8 100644
--- a/components/consent_auditor/DIR_METADATA
+++ b/components/consent_auditor/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Privacy"
-}
+mixins: "//components/consent_auditor/COMMON_METADATA"
diff --git a/components/content_capture/COMMON_METADATA b/components/content_capture/COMMON_METADATA
new file mode 100644
index 0000000..2c9d7f4
--- /dev/null
+++ b/components/content_capture/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>ContentCapture"
+}
diff --git a/components/content_capture/DIR_METADATA b/components/content_capture/DIR_METADATA
index 2c9d7f4..91c786d2 100644
--- a/components/content_capture/DIR_METADATA
+++ b/components/content_capture/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>ContentCapture"
-}
+mixins: "//components/content_capture/COMMON_METADATA"
diff --git a/components/content_creation/COMMON_METADATA b/components/content_creation/COMMON_METADATA
new file mode 100644
index 0000000..41d1f6aa
--- /dev/null
+++ b/components/content_creation/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Creation"
+}
+
+team_email: "chrome-creation@google.com"
diff --git a/components/content_creation/DIR_METADATA b/components/content_creation/DIR_METADATA
index 41d1f6aa..302b1262 100644
--- a/components/content_creation/DIR_METADATA
+++ b/components/content_creation/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>Creation"
-}
+mixins: "//components/content_creation/COMMON_METADATA"
 
-team_email: "chrome-creation@google.com"
diff --git a/components/content_settings/COMMON_METADATA b/components/content_settings/COMMON_METADATA
new file mode 100644
index 0000000..9578a5d9
--- /dev/null
+++ b/components/content_settings/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Permissions>Model"
+}
+team_email: "permissions-dev@chromium.org"
diff --git a/components/content_settings/DIR_METADATA b/components/content_settings/DIR_METADATA
index 9578a5d9..7884b06a 100644
--- a/components/content_settings/DIR_METADATA
+++ b/components/content_settings/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Permissions>Model"
-}
-team_email: "permissions-dev@chromium.org"
+mixins: "//components/content_settings/COMMON_METADATA"
diff --git a/components/continuous_search/COMMON_METADATA b/components/continuous_search/COMMON_METADATA
new file mode 100644
index 0000000..83a4438
--- /dev/null
+++ b/components/continuous_search/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail:  {
+  component:  "UI>Browser>ContinuousSearch"
+}
+team_email: "csn-dev@google.com"
+os: ANDROID
diff --git a/components/continuous_search/DIR_METADATA b/components/continuous_search/DIR_METADATA
index 83a4438..78deea4 100644
--- a/components/continuous_search/DIR_METADATA
+++ b/components/continuous_search/DIR_METADATA
@@ -1,5 +1 @@
-monorail:  {
-  component:  "UI>Browser>ContinuousSearch"
-}
-team_email: "csn-dev@google.com"
-os: ANDROID
+mixins: "//components/continuous_search/COMMON_METADATA"
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index fdf4470..12e33b2 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -1055,6 +1055,7 @@
       "//base:base_java_test_support",
       "//net/android:net_java",
       "//net/android:net_java_test_support",
+      "//testing/buildbot/filters:cronet_test_instrumentation_apk_filters",
       "//third_party/android_sdk:android_test_base_java",
       "//third_party/android_sdk:android_test_mock_java",
       "//third_party/android_support_test_runner:runner_java",
diff --git a/components/data_reduction_proxy/COMMON_METADATA b/components/data_reduction_proxy/COMMON_METADATA
new file mode 100644
index 0000000..e548f97
--- /dev/null
+++ b/components/data_reduction_proxy/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Network>DataProxy"
+}
diff --git a/components/data_reduction_proxy/DIR_METADATA b/components/data_reduction_proxy/DIR_METADATA
index e548f97..eb96fa3 100644
--- a/components/data_reduction_proxy/DIR_METADATA
+++ b/components/data_reduction_proxy/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Network>DataProxy"
-}
+mixins: "//components/data_reduction_proxy/COMMON_METADATA"
diff --git a/components/dbus/DIR_METADATA b/components/dbus/DIR_METADATA
index 06e78af..a03a065 100644
--- a/components/dbus/DIR_METADATA
+++ b/components/dbus/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "OS>Systems"
-}
+mixins: "//dbus/COMMON_METADATA"
diff --git a/components/dom_distiller/COMMON_METADATA b/components/dom_distiller/COMMON_METADATA
new file mode 100644
index 0000000..e745659
--- /dev/null
+++ b/components/dom_distiller/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>ReaderMode"
+}
+
+team_email: "dom-distiller-eng@google.com"
diff --git a/components/dom_distiller/DIR_METADATA b/components/dom_distiller/DIR_METADATA
index e745659..7215023 100644
--- a/components/dom_distiller/DIR_METADATA
+++ b/components/dom_distiller/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>ReaderMode"
-}
+mixins: "//components/dom_distiller/COMMON_METADATA"
 
-team_email: "dom-distiller-eng@google.com"
diff --git a/components/domain_reliability/COMMON_METADATA b/components/domain_reliability/COMMON_METADATA
new file mode 100644
index 0000000..cb1a69b4
--- /dev/null
+++ b/components/domain_reliability/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>Network>ReportingAndNEL"
+}
+
+team_email: "net-dev@chromium.org"
diff --git a/components/domain_reliability/DIR_METADATA b/components/domain_reliability/DIR_METADATA
index cb1a69b4..9147ca6 100644
--- a/components/domain_reliability/DIR_METADATA
+++ b/components/domain_reliability/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Network>ReportingAndNEL"
-}
+mixins: "//components/domain_reliability/COMMON_METADATA"
 
-team_email: "net-dev@chromium.org"
diff --git a/components/download/COMMON_METADATA b/components/download/COMMON_METADATA
new file mode 100644
index 0000000..6bf7cbf
--- /dev/null
+++ b/components/download/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Downloads"
+}
diff --git a/components/download/DIR_METADATA b/components/download/DIR_METADATA
index 6bf7cbf..8b1c141 100644
--- a/components/download/DIR_METADATA
+++ b/components/download/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Downloads"
-}
+mixins: "//components/download/COMMON_METADATA"
diff --git a/components/drive/COMMON_METADATA b/components/drive/COMMON_METADATA
new file mode 100644
index 0000000..5b8d7cd
--- /dev/null
+++ b/components/drive/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Platform>Apps>FileManager"
+}
diff --git a/components/drive/DIR_METADATA b/components/drive/DIR_METADATA
index 5b8d7cd..780966e 100644
--- a/components/drive/DIR_METADATA
+++ b/components/drive/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>FileManager"
-}
+mixins: "//components/drive/COMMON_METADATA"
diff --git a/components/embedder_support/android/metrics/DIR_METADATA b/components/embedder_support/android/metrics/DIR_METADATA
index fbc09c2..1c83dc52 100644
--- a/components/embedder_support/android/metrics/DIR_METADATA
+++ b/components/embedder_support/android/metrics/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Internals>Metrics"
-}
+mixins: "//base/metrics/COMMON_METADATA"
 team_email: "chromium-dev@chromium.org"
diff --git a/components/embedder_support/origin_trials/DIR_METADATA b/components/embedder_support/origin_trials/DIR_METADATA
index 0032fd00..14641a38 100644
--- a/components/embedder_support/origin_trials/DIR_METADATA
+++ b/components/embedder_support/origin_trials/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>OriginTrials"
-}
-team_email: "experimentation-dev@chromium.org"
+mixins: "//third_party/blink/common/origin_trials/COMMON_METADATA"
diff --git a/components/feature_engagement/COMMON_METADATA b/components/feature_engagement/COMMON_METADATA
new file mode 100644
index 0000000..454508f
--- /dev/null
+++ b/components/feature_engagement/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>FeatureEngagement"
+}
diff --git a/components/feature_engagement/DIR_METADATA b/components/feature_engagement/DIR_METADATA
index 454508f..02a82b3 100644
--- a/components/feature_engagement/DIR_METADATA
+++ b/components/feature_engagement/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>FeatureEngagement"
-}
+mixins: "//components/feature_engagement/COMMON_METADATA"
diff --git a/components/federated_learning/COMMON_METADATA b/components/federated_learning/COMMON_METADATA
new file mode 100644
index 0000000..0e6c0305
--- /dev/null
+++ b/components/federated_learning/COMMON_METADATA
@@ -0,0 +1 @@
+team_email: "privacy-sandbox-dev@chromium.org"
diff --git a/components/federated_learning/DIR_METADATA b/components/federated_learning/DIR_METADATA
index 0e6c0305..ea6a8e2 100644
--- a/components/federated_learning/DIR_METADATA
+++ b/components/federated_learning/DIR_METADATA
@@ -1 +1 @@
-team_email: "privacy-sandbox-dev@chromium.org"
+mixins: "//components/federated_learning/COMMON_METADATA"
diff --git a/components/feed/COMMON_METADATA b/components/feed/COMMON_METADATA
new file mode 100644
index 0000000..2ecd29e
--- /dev/null
+++ b/components/feed/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>ContentSuggestions>Feed"
+}
+team_email: "feed@chromium.org"
diff --git a/components/feed/DIR_METADATA b/components/feed/DIR_METADATA
index 2ecd29e..aa7a67e 100644
--- a/components/feed/DIR_METADATA
+++ b/components/feed/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>ContentSuggestions>Feed"
-}
-team_email: "feed@chromium.org"
+mixins: "//components/feed/COMMON_METADATA"
diff --git a/components/feedback/COMMON_METADATA b/components/feedback/COMMON_METADATA
new file mode 100644
index 0000000..1b00e25cb7
--- /dev/null
+++ b/components/feedback/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Platform>Apps>Feedback"
+}
diff --git a/components/feedback/DIR_METADATA b/components/feedback/DIR_METADATA
index 1b00e25cb7..25e9f5bf 100644
--- a/components/feedback/DIR_METADATA
+++ b/components/feedback/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>Feedback"
-}
+mixins: "//components/feedback/COMMON_METADATA"
diff --git a/components/find_in_page/android/DIR_METADATA b/components/find_in_page/android/DIR_METADATA
new file mode 100644
index 0000000..c69388e
--- /dev/null
+++ b/components/find_in_page/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/components/guest_os/DIR_METADATA b/components/guest_os/DIR_METADATA
index f461eb4..06e627f 100644
--- a/components/guest_os/DIR_METADATA
+++ b/components/guest_os/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "UI>Shell>Containers"
-}
+mixins: "//chrome/browser/ash/guest_os/COMMON_METADATA"
diff --git a/components/guest_view/COMMON_METADATA b/components/guest_view/COMMON_METADATA
new file mode 100644
index 0000000..22d44120c
--- /dev/null
+++ b/components/guest_view/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Platform>Apps>BrowserTag"
+}
diff --git a/components/guest_view/DIR_METADATA b/components/guest_view/DIR_METADATA
index 22d44120c..38cda2d 100644
--- a/components/guest_view/DIR_METADATA
+++ b/components/guest_view/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>BrowserTag"
-}
+mixins: "//components/guest_view/COMMON_METADATA"
diff --git a/components/heavy_ad_intervention/COMMON_METADATA b/components/heavy_ad_intervention/COMMON_METADATA
new file mode 100644
index 0000000..352eefc
--- /dev/null
+++ b/components/heavy_ad_intervention/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>AdFilter"
+}
diff --git a/components/heavy_ad_intervention/DIR_METADATA b/components/heavy_ad_intervention/DIR_METADATA
index 352eefc..cc2c627ce 100644
--- a/components/heavy_ad_intervention/DIR_METADATA
+++ b/components/heavy_ad_intervention/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>AdFilter"
-}
+mixins: "//components/heavy_ad_intervention/COMMON_METADATA"
diff --git a/components/history/core/browser/sync/DIR_METADATA b/components/history/core/browser/sync/DIR_METADATA
index 1a6d7ee6..4a58e65 100644
--- a/components/history/core/browser/sync/DIR_METADATA
+++ b/components/history/core/browser/sync/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Services>Sync"
-}
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/components/history_clusters/COMMON_METADATA b/components/history_clusters/COMMON_METADATA
new file mode 100644
index 0000000..88f25f6
--- /dev/null
+++ b/components/history_clusters/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Memories"
+}
diff --git a/components/history_clusters/DIR_METADATA b/components/history_clusters/DIR_METADATA
index 88f25f6..694e2bf 100644
--- a/components/history_clusters/DIR_METADATA
+++ b/components/history_clusters/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Memories"
-}
+mixins: "//components/history_clusters/COMMON_METADATA"
diff --git a/components/image_fetcher/COMMON_METADATA b/components/image_fetcher/COMMON_METADATA
new file mode 100644
index 0000000..a645b47
--- /dev/null
+++ b/components/image_fetcher/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Images"
+}
diff --git a/components/image_fetcher/DIR_METADATA b/components/image_fetcher/DIR_METADATA
index a645b47..eacf064 100644
--- a/components/image_fetcher/DIR_METADATA
+++ b/components/image_fetcher/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Images"
-}
+mixins: "//components/image_fetcher/COMMON_METADATA"
diff --git a/components/invalidation/COMMON_METADATA b/components/invalidation/COMMON_METADATA
new file mode 100644
index 0000000..5b2200d
--- /dev/null
+++ b/components/invalidation/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Services>Invalidation"
+}
+
+team_email: "chromium-reviews@chromium.org"
diff --git a/components/invalidation/DIR_METADATA b/components/invalidation/DIR_METADATA
index 5b2200d..cbe04ab 100644
--- a/components/invalidation/DIR_METADATA
+++ b/components/invalidation/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Services>Invalidation"
-}
+mixins: "//components/invalidation/COMMON_METADATA"
 
-team_email: "chromium-reviews@chromium.org"
diff --git a/components/language/COMMON_METADATA b/components/language/COMMON_METADATA
new file mode 100644
index 0000000..45f3f52
--- /dev/null
+++ b/components/language/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Language"
+}
+
+team_email: "language@chromium.org"
diff --git a/components/language/DIR_METADATA b/components/language/DIR_METADATA
index 45f3f52..be22615c 100644
--- a/components/language/DIR_METADATA
+++ b/components/language/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>Language"
-}
+mixins: "//components/language/COMMON_METADATA"
 
-team_email: "language@chromium.org"
diff --git a/components/management_strings.grdp b/components/management_strings.grdp
index 04d712a..b0c2cdb 100644
--- a/components/management_strings.grdp
+++ b/components/management_strings.grdp
@@ -131,8 +131,8 @@
     </message>
     <message name="IDS_MANAGEMENT_REPORT_DLP_EVENTS" desc="Message stating that administrators can see attempts at prohibited actions on restricted data. Also shows the number of actions reported since login, and provides a 'Learn more' link.">
       {COUNT, plural,
-      =1 {Actions taken with data flagged as confidential (1 action reported since login). <ph name="BEGIN_LINK">&lt;a target="_blank" href="https://support.google.com/chromebook/?p=is_chrome_managed"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>}
-      other {Actions taken with data flagged as confidential (# actions reported since login). <ph name="BEGIN_LINK">&lt;a target="_blank" href="https://support.google.com/chromebook/?p=is_chrome_managed"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>}}
+      =1 {Actions taken with data flagged as confidential (1 action since login). <ph name="BEGIN_LINK">&lt;a target="_blank" href="https://support.google.com/chrome/a/?p=chromeos_datacontrols"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>}
+      other {Actions taken with data flagged as confidential (# actions since login). <ph name="BEGIN_LINK">&lt;a target="_blank" href="https://support.google.com/chrome/a/?p=chromeos_datacontrols"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>}}
     </message>
     <message name="IDS_MANAGEMENT_REPORT_LOGIN_LOGOUT" desc="Message stating that administrators can see device Login and Logout events.">
       Device login/logout history, including timestamps and failed attempts
diff --git a/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DLP_EVENTS.png.sha1 b/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DLP_EVENTS.png.sha1
index 5166da0..422fa85 100644
--- a/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DLP_EVENTS.png.sha1
+++ b/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DLP_EVENTS.png.sha1
@@ -1 +1 @@
-0ba343d4a5ffe397885b5790c28fb4ef343ff9d4
\ No newline at end of file
+297872854d82cfbadd0c9b2ac76566ec54f5964a
\ No newline at end of file
diff --git a/components/messages/COMMON_METADATA b/components/messages/COMMON_METADATA
new file mode 100644
index 0000000..c00659e
--- /dev/null
+++ b/components/messages/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Mobile>Messages"
+}
+
+team_email: "clank-app-team@google.com"
diff --git a/components/messages/DIR_METADATA b/components/messages/DIR_METADATA
index c00659e..4a3e06f 100644
--- a/components/messages/DIR_METADATA
+++ b/components/messages/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>Mobile>Messages"
-}
+mixins: "//components/messages/COMMON_METADATA"
 
-team_email: "clank-app-team@google.com"
diff --git a/components/metrics/DIR_METADATA b/components/metrics/DIR_METADATA
index 4cea270..f9ef9a7d 100644
--- a/components/metrics/DIR_METADATA
+++ b/components/metrics/DIR_METADATA
@@ -1,5 +1,3 @@
-monorail {
-  component: "Internals>Metrics"
-}
+mixins: "//base/metrics/COMMON_METADATA"
 
 team_email: "chromium-dev@chromium.org"
diff --git a/components/ntp_tiles/COMMON_METADATA b/components/ntp_tiles/COMMON_METADATA
new file mode 100644
index 0000000..ac4deaa
--- /dev/null
+++ b/components/ntp_tiles/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>ContentSuggestions>History"
+}
diff --git a/components/ntp_tiles/DIR_METADATA b/components/ntp_tiles/DIR_METADATA
index ac4deaa..390105a 100644
--- a/components/ntp_tiles/DIR_METADATA
+++ b/components/ntp_tiles/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>ContentSuggestions>History"
-}
+mixins: "//components/ntp_tiles/COMMON_METADATA"
diff --git a/components/offline_items_collection/COMMON_METADATA b/components/offline_items_collection/COMMON_METADATA
new file mode 100644
index 0000000..30fe702ce
--- /dev/null
+++ b/components/offline_items_collection/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Downloads"
+}
+
+team_email: "chrome-downloads@chromium.org"
diff --git a/components/offline_items_collection/DIR_METADATA b/components/offline_items_collection/DIR_METADATA
index 30fe702ce..8a35d1f 100644
--- a/components/offline_items_collection/DIR_METADATA
+++ b/components/offline_items_collection/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>Downloads"
-}
+mixins: "//components/offline_items_collection/COMMON_METADATA"
 
-team_email: "chrome-downloads@chromium.org"
diff --git a/components/offline_pages/COMMON_METADATA b/components/offline_pages/COMMON_METADATA
new file mode 100644
index 0000000..a629a88
--- /dev/null
+++ b/components/offline_pages/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Offline"
+}
+
+team_email: "offline-dev@chromium.org"
diff --git a/components/offline_pages/DIR_METADATA b/components/offline_pages/DIR_METADATA
index a629a88..e0f99fe 100644
--- a/components/offline_pages/DIR_METADATA
+++ b/components/offline_pages/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>Offline"
-}
+mixins: "//components/offline_pages/COMMON_METADATA"
 
-team_email: "offline-dev@chromium.org"
diff --git a/components/omnibox/COMMON_METADATA b/components/omnibox/COMMON_METADATA
new file mode 100644
index 0000000..07a4669
--- /dev/null
+++ b/components/omnibox/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Omnibox"
+}
diff --git a/components/omnibox/DIR_METADATA b/components/omnibox/DIR_METADATA
index 07a4669..7a9dec1 100644
--- a/components/omnibox/DIR_METADATA
+++ b/components/omnibox/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Omnibox"
-}
+mixins: "//components/omnibox/COMMON_METADATA"
diff --git a/components/omnibox/browser/vector_icons/DIR_METADATA b/components/omnibox/browser/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/components/omnibox/browser/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/components/optimization_guide/COMMON_METADATA b/components/optimization_guide/COMMON_METADATA
new file mode 100644
index 0000000..f21921424
--- /dev/null
+++ b/components/optimization_guide/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>OptimizationGuide"
+}
diff --git a/components/optimization_guide/DIR_METADATA b/components/optimization_guide/DIR_METADATA
index f21921424..0a043d53 100644
--- a/components/optimization_guide/DIR_METADATA
+++ b/components/optimization_guide/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>OptimizationGuide"
-}
+mixins: "//components/optimization_guide/COMMON_METADATA"
diff --git a/components/optimization_guide/core/BUILD.gn b/components/optimization_guide/core/BUILD.gn
index ca0ad67..48ab816a 100644
--- a/components/optimization_guide/core/BUILD.gn
+++ b/components/optimization_guide/core/BUILD.gn
@@ -182,25 +182,6 @@
   ]
 }
 
-if (is_ios) {
-  source_set("eg_test_support+eg2") {
-    testonly = true
-    sources = [
-      "optimization_guide_constants.cc",
-      "optimization_guide_constants.h",
-      "optimization_guide_enums.h",
-      "optimization_guide_switches.cc",
-      "optimization_guide_switches.h",
-      "optimization_guide_test_util.cc",
-      "optimization_guide_test_util.h",
-    ]
-    deps = [
-      "//base",
-      "//components/optimization_guide/proto:optimization_guide_proto",
-    ]
-  }
-}
-
 source_set("unit_tests") {
   testonly = true
   sources = [
diff --git a/components/optimization_guide/core/hints_fetcher.cc b/components/optimization_guide/core/hints_fetcher.cc
index ed11f25..558bebc 100644
--- a/components/optimization_guide/core/hints_fetcher.cc
+++ b/components/optimization_guide/core/hints_fetcher.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
@@ -15,7 +14,6 @@
 #include "components/optimization_guide/core/hints_processing_util.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
 #include "components/optimization_guide/core/optimization_guide_prefs.h"
-#include "components/optimization_guide/core/optimization_guide_switches.h"
 #include "components/optimization_guide/core/optimization_guide_util.h"
 #include "components/optimization_guide/proto/hints.pb.h"
 #include "components/prefs/pref_service.h"
@@ -95,13 +93,7 @@
       network_connection_tracker_(network_connection_tracker),
       time_clock_(base::DefaultClock::GetInstance()) {
   url_loader_factory_ = std::move(url_loader_factory);
-  // Allow non-https scheme only when it is overridden in command line. This is
-  // needed for iOS EG2 tests which don't support HTTPS embedded test servers
-  // due to ssl certificate validation. So, the EG2 tests use HTTP hints
-  // servers.
-  CHECK(optimization_guide_service_url_.SchemeIs(url::kHttpsScheme) ||
-        base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kOptimizationGuideServiceGetHintsURL));
+  CHECK(optimization_guide_service_url_.SchemeIs(url::kHttpsScheme));
   DCHECK(features::IsRemoteFetchingEnabled());
 }
 
diff --git a/components/optimization_guide/core/hints_fetcher_factory.cc b/components/optimization_guide/core/hints_fetcher_factory.cc
index cd63684..684b796 100644
--- a/components/optimization_guide/core/hints_fetcher_factory.cc
+++ b/components/optimization_guide/core/hints_fetcher_factory.cc
@@ -28,9 +28,4 @@
       network_connection_tracker_);
 }
 
-void HintsFetcherFactory::OverrideOptimizationGuideServiceUrlForTesting(
-    const GURL& optimization_guide_service_url) {
-  optimization_guide_service_url_ = optimization_guide_service_url;
-}
-
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/hints_fetcher_factory.h b/components/optimization_guide/core/hints_fetcher_factory.h
index a626d29..577efcd 100644
--- a/components/optimization_guide/core/hints_fetcher_factory.h
+++ b/components/optimization_guide/core/hints_fetcher_factory.h
@@ -38,17 +38,13 @@
   // testing code can override this to provide a mocked instance.
   virtual std::unique_ptr<HintsFetcher> BuildInstance();
 
-  // Override the optimization guide hints server URL. Used for testing.
-  void OverrideOptimizationGuideServiceUrlForTesting(
-      const GURL& optimization_guide_service_url);
-
  protected:
   // The URL Loader Factory that will be used by hints fetchers created by this
   // factory.
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
   // The URL for the remote Optimization Guide Service.
-  GURL optimization_guide_service_url_;
+  const GURL optimization_guide_service_url_;
 
   // A reference to the PrefService for this profile. Not owned.
   PrefService* pref_service_ = nullptr;
diff --git a/components/optimization_guide/core/hints_manager.cc b/components/optimization_guide/core/hints_manager.cc
index d5d074d..fe77141 100644
--- a/components/optimization_guide/core/hints_manager.cc
+++ b/components/optimization_guide/core/hints_manager.cc
@@ -1388,11 +1388,6 @@
   return push_notification_manager_.get();
 }
 
-optimization_guide::HintsFetcherFactory*
-HintsManager::GetHintsFetcherFactory() {
-  return hints_fetcher_factory_.get();
-}
-
 bool HintsManager::HasAllInformationForDecisionAvailable(
     const GURL& navigation_url,
     optimization_guide::proto::OptimizationType optimization_type) {
diff --git a/components/optimization_guide/core/hints_manager.h b/components/optimization_guide/core/hints_manager.h
index 842b42d3..af4c8a19 100644
--- a/components/optimization_guide/core/hints_manager.h
+++ b/components/optimization_guide/core/hints_manager.h
@@ -28,7 +28,6 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 class OptimizationGuideNavigationData;
-class OptimizationGuideTestAppInterfaceWrapper;
 class PrefService;
 
 namespace network {
@@ -187,8 +186,6 @@
       const absl::optional<optimization_guide::OptimizationMetadata>& metadata);
 
  private:
-  friend class ::OptimizationGuideTestAppInterfaceWrapper;
-
   // Processes the optimization filters contained in the hints component.
   void ProcessOptimizationFilters(
       const google::protobuf::RepeatedPtrField<
@@ -332,8 +329,6 @@
       const GURL& navigation_url,
       optimization_guide::proto::OptimizationType optimization_type);
 
-  optimization_guide::HintsFetcherFactory* GetHintsFetcherFactory();
-
   // The information of the latest component delivered by
   // |optimization_guide_service_|.
   absl::optional<optimization_guide::HintsComponentInfo> hints_component_info_;
diff --git a/components/optimization_guide/core/optimization_guide_switches.cc b/components/optimization_guide/core/optimization_guide_switches.cc
index 4725935..6253895 100644
--- a/components/optimization_guide/core/optimization_guide_switches.cc
+++ b/components/optimization_guide/core/optimization_guide_switches.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "base/strings/string_split.h"
 #include "build/build_config.h"
+#include "components/optimization_guide/core/optimization_guide_util.h"
 #include "components/optimization_guide/proto/hints.pb.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -199,7 +200,10 @@
   return command_line->HasSwitch(kModelValidate);
 }
 
-absl::optional<std::string> GetModelOverride() {
+absl::optional<
+    std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+GetModelOverrideForOptimizationTarget(
+    optimization_guide::proto::OptimizationTarget optimization_target) {
 #if defined(OS_WIN)
   // TODO(crbug/1227996): The parsing below is not supported on Windows because
   // ':' is used as a delimiter, but this must be used in the absolute file path
@@ -211,7 +215,58 @@
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(kModelOverride))
     return absl::nullopt;
-  return command_line->GetSwitchValueASCII(kModelOverride);
+
+  std::string model_override_switch_value =
+      command_line->GetSwitchValueASCII(kModelOverride);
+  std::vector<std::string> model_overrides =
+      base::SplitString(model_override_switch_value, ",", base::TRIM_WHITESPACE,
+                        base::SPLIT_WANT_NONEMPTY);
+  for (const auto& model_override : model_overrides) {
+    std::vector<std::string> override_parts = base::SplitString(
+        model_override, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+    if (override_parts.size() != 2 && override_parts.size() != 3) {
+      // Input is malformed.
+      DLOG(ERROR) << "Invalid string format provided to the Model Override";
+      return absl::nullopt;
+    }
+
+    optimization_guide::proto::OptimizationTarget recv_optimization_target;
+    if (!optimization_guide::proto::OptimizationTarget_Parse(
+            override_parts[0], &recv_optimization_target)) {
+      // Optimization target is invalid.
+      DLOG(ERROR)
+          << "Invalid optimization target provided to the Model Override";
+      return absl::nullopt;
+    }
+    if (optimization_target != recv_optimization_target)
+      continue;
+
+    std::string file_name = override_parts[1];
+    if (!base::FilePath(file_name).IsAbsolute()) {
+      DLOG(ERROR) << "Provided model file path must be absolute " << file_name;
+      return absl::nullopt;
+    }
+
+    if (override_parts.size() == 2) {
+      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>
+          file_path_and_metadata = std::make_pair(file_name, absl::nullopt);
+      return file_path_and_metadata;
+    }
+    std::string binary_pb;
+    if (!base::Base64Decode(override_parts[2], &binary_pb)) {
+      DLOG(ERROR) << "Invalid base64 encoding of the Model Override";
+      return absl::nullopt;
+    }
+    optimization_guide::proto::Any model_metadata;
+    if (!model_metadata.ParseFromString(binary_pb)) {
+      DLOG(ERROR) << "Invalid model metadata provided to the Model Override";
+      return absl::nullopt;
+    }
+    std::pair<std::string, absl::optional<optimization_guide::proto::Any>>
+        file_path_and_metadata = std::make_pair(file_name, model_metadata);
+    return file_path_and_metadata;
+  }
+  return absl::nullopt;
 #endif
 }
 
diff --git a/components/optimization_guide/core/optimization_guide_switches.h b/components/optimization_guide/core/optimization_guide_switches.h
index 56015a09..73aa2f2 100644
--- a/components/optimization_guide/core/optimization_guide_switches.h
+++ b/components/optimization_guide/core/optimization_guide_switches.h
@@ -90,8 +90,12 @@
 // Returns whether the model validation should happen.
 bool ShouldValidateModel();
 
-// Returns the model override command line switch.
-absl::optional<std::string> GetModelOverride();
+// Returns the file path string and metadata for the model provided via
+// command-line for |optimization_target|, if applicable.
+absl::optional<
+    std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+GetModelOverrideForOptimizationTarget(
+    optimization_guide::proto::OptimizationTarget optimization_target);
 
 // Returns true if debug logs are enabled for the optimization guide.
 bool IsDebugLogsEnabled();
diff --git a/components/optimization_guide/core/optimization_guide_switches_unittest.cc b/components/optimization_guide/core/optimization_guide_switches_unittest.cc
index ab40170..ee4b7652 100644
--- a/components/optimization_guide/core/optimization_guide_switches_unittest.cc
+++ b/components/optimization_guide/core/optimization_guide_switches_unittest.cc
@@ -6,7 +6,9 @@
 
 #include "base/base64.h"
 #include "base/command_line.h"
+#include "base/strings/stringprintf.h"
 #include "build/build_config.h"
+#include "components/optimization_guide/core/optimization_guide_test_util.h"
 #include "components/optimization_guide/proto/hints.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -106,6 +108,138 @@
   EXPECT_EQ(nullptr, parsed_config);
 }
 
+TEST(OptimizationGuideSwitchesTest,
+     GetModelOverrideForOptimizationTargetSwitchNotSet) {
+  absl::optional<
+      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+
+  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
+  EXPECT_FALSE(IsModelOverridePresent());
+}
+
+TEST(OptimizationGuideSwitchesTest,
+     GetModelOverrideForOptimizationTargetEmptyInput) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(kModelOverride);
+
+  absl::optional<
+      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+
+  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
+}
+
+TEST(OptimizationGuideSwitchesTest,
+     GetModelOverrideForOptimizationTargetBadInput) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kModelOverride,
+                                                            "whatever");
+
+  absl::optional<
+      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+
+  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
+}
+
+TEST(OptimizationGuideSwitchesTest,
+     GetModelOverrideForOptimizationTargetInvalidOptimizationTarget) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      kModelOverride,
+      "notanoptimizationtarget:" + std::string(kTestAbsoluteFilePath));
+
+  absl::optional<
+      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+
+  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
+}
+
+TEST(OptimizationGuideSwitchesTest,
+     GetModelOverrideForOptimizationTargetRelativeFilePath) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      kModelOverride, "OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:" +
+                          std::string(kTestRelativeFilePath));
+
+  absl::optional<
+      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+
+  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
+}
+
+TEST(OptimizationGuideSwitchesTest,
+     GetModelOverrideForOptimizationTargetRelativeFilePathWithMetadata) {
+  optimization_guide::proto::Any metadata;
+  metadata.set_type_url("sometypeurl");
+  std::string encoded_metadata;
+  metadata.SerializeToString(&encoded_metadata);
+  base::Base64Encode(encoded_metadata, &encoded_metadata);
+
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      kModelOverride,
+      base::StringPrintf("OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:%s:%s",
+                         kTestRelativeFilePath, encoded_metadata.c_str()));
+
+  absl::optional<
+      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+
+  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
+}
+
+TEST(OptimizationGuideSwitchesTest,
+     GetModelOverrideForOptimizationTargetOneFilePath) {
+  optimization_guide::proto::Any metadata;
+  metadata.set_type_url("sometypeurl");
+  std::string encoded_metadata;
+  metadata.SerializeToString(&encoded_metadata);
+  base::Base64Encode(encoded_metadata, &encoded_metadata);
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      kModelOverride,
+      base::StringPrintf("OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:%s:%s",
+                         kTestAbsoluteFilePath, encoded_metadata.c_str()));
+
+  absl::optional<
+      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+
+  EXPECT_EQ(kTestAbsoluteFilePath, file_path_and_metadata->first);
+  EXPECT_EQ("sometypeurl", file_path_and_metadata->second->type_url());
+}
+
+TEST(OptimizationGuideSwitchesTest,
+     GetModelOverrideForOptimizationTargetMultipleFilePath) {
+  const char kOtherAbsoluteFilePath[] = "/other/file/path";
+  optimization_guide::proto::Any metadata;
+  metadata.set_type_url("sometypeurl");
+  std::string encoded_metadata;
+  metadata.SerializeToString(&encoded_metadata);
+  base::Base64Encode(encoded_metadata, &encoded_metadata);
+  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+      kModelOverride,
+      base::StringPrintf("OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:%s,"
+                         "OPTIMIZATION_TARGET_PAGE_TOPICS:%s:%s",
+                         kTestAbsoluteFilePath, kOtherAbsoluteFilePath,
+                         encoded_metadata.c_str()));
+
+  absl::optional<
+      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
+      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
+          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+  EXPECT_EQ(kTestAbsoluteFilePath, file_path_and_metadata->first);
+
+  file_path_and_metadata = GetModelOverrideForOptimizationTarget(
+      optimization_guide::proto::OPTIMIZATION_TARGET_PAGE_TOPICS);
+  EXPECT_EQ(kOtherAbsoluteFilePath, file_path_and_metadata->first);
+  EXPECT_EQ("sometypeurl", file_path_and_metadata->second->type_url());
+}
 
 #endif
 
diff --git a/components/optimization_guide/core/optimization_guide_test_util.h b/components/optimization_guide/core/optimization_guide_test_util.h
index bec4727..6417face 100644
--- a/components/optimization_guide/core/optimization_guide_test_util.h
+++ b/components/optimization_guide/core/optimization_guide_test_util.h
@@ -13,13 +13,6 @@
 
 namespace optimization_guide {
 
-enum class HintsFetcherRemoteResponseType {
-  kSuccessful = 0,
-  kUnsuccessful = 1,
-  kMalformed = 2,
-  kHung = 3,
-};
-
 // File paths that can be used in testing, handling platform differences, namely
 // C:\ in Windows.
 extern const char kTestAbsoluteFilePath[];
diff --git a/components/optimization_guide/core/optimization_guide_util.cc b/components/optimization_guide/core/optimization_guide_util.cc
index 2c17cb6..abdfd623a 100644
--- a/components/optimization_guide/core/optimization_guide_util.cc
+++ b/components/optimization_guide/core/optimization_guide_util.cc
@@ -4,7 +4,6 @@
 
 #include "components/optimization_guide/core/optimization_guide_util.h"
 
-#include "base/base64.h"
 #include "base/containers/flat_set.h"
 #include "base/notreached.h"
 #include "base/strings/utf_string_conversions.h"
@@ -12,7 +11,6 @@
 #include "components/optimization_guide/core/optimization_guide_decision.h"
 #include "components/optimization_guide/core/optimization_guide_enums.h"
 #include "components/optimization_guide/core/optimization_guide_features.h"
-#include "components/optimization_guide/core/optimization_guide_switches.h"
 #include "components/variations/active_field_trials.h"
 #include "net/base/url_util.h"
 #include "url/url_canon.h"
@@ -127,72 +125,4 @@
   return std::string();
 }
 
-absl::optional<
-    std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-GetModelOverrideForOptimizationTarget(
-    optimization_guide::proto::OptimizationTarget optimization_target) {
-#if defined(OS_WIN)
-  // TODO(crbug/1227996): The parsing below is not supported on Windows because
-  // ':' is used as a delimiter, but this must be used in the absolute file path
-  // on Windows.
-  DLOG(ERROR)
-      << "--optimization-guide-model-override is not available on Windows";
-  return absl::nullopt;
-#else
-  auto model_override_switch_value = switches::GetModelOverride();
-  if (!model_override_switch_value)
-    return absl::nullopt;
-
-  std::vector<std::string> model_overrides =
-      base::SplitString(*model_override_switch_value, ",",
-                        base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-  for (const auto& model_override : model_overrides) {
-    std::vector<std::string> override_parts = base::SplitString(
-        model_override, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-    if (override_parts.size() != 2 && override_parts.size() != 3) {
-      // Input is malformed.
-      DLOG(ERROR) << "Invalid string format provided to the Model Override";
-      return absl::nullopt;
-    }
-
-    optimization_guide::proto::OptimizationTarget recv_optimization_target;
-    if (!optimization_guide::proto::OptimizationTarget_Parse(
-            override_parts[0], &recv_optimization_target)) {
-      // Optimization target is invalid.
-      DLOG(ERROR)
-          << "Invalid optimization target provided to the Model Override";
-      return absl::nullopt;
-    }
-    if (optimization_target != recv_optimization_target)
-      continue;
-
-    std::string file_name = override_parts[1];
-    if (!base::FilePath(file_name).IsAbsolute()) {
-      DLOG(ERROR) << "Provided model file path must be absolute " << file_name;
-      return absl::nullopt;
-    }
-
-    if (override_parts.size() == 2) {
-      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>
-          file_path_and_metadata = std::make_pair(file_name, absl::nullopt);
-      return file_path_and_metadata;
-    }
-    std::string binary_pb;
-    if (!base::Base64Decode(override_parts[2], &binary_pb)) {
-      DLOG(ERROR) << "Invalid base64 encoding of the Model Override";
-      return absl::nullopt;
-    }
-    optimization_guide::proto::Any model_metadata;
-    if (!model_metadata.ParseFromString(binary_pb)) {
-      DLOG(ERROR) << "Invalid model metadata provided to the Model Override";
-      return absl::nullopt;
-    }
-    std::pair<std::string, absl::optional<optimization_guide::proto::Any>>
-        file_path_and_metadata = std::make_pair(file_name, model_metadata);
-    return file_path_and_metadata;
-  }
-  return absl::nullopt;
-#endif
-}
-
 }  // namespace optimization_guide
diff --git a/components/optimization_guide/core/optimization_guide_util.h b/components/optimization_guide/core/optimization_guide_util.h
index f425dde..3b9fd0c 100644
--- a/components/optimization_guide/core/optimization_guide_util.h
+++ b/components/optimization_guide/core/optimization_guide_util.h
@@ -80,13 +80,6 @@
 std::string GetStringForOptimizationGuideDecision(
     OptimizationGuideDecision decision);
 
-// Returns the file path string and metadata for the model provided via
-// command-line for |optimization_target|, if applicable.
-absl::optional<
-    std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-GetModelOverrideForOptimizationTarget(
-    optimization_guide::proto::OptimizationTarget optimization_target);
-
 }  // namespace optimization_guide
 
 #endif  // COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_UTIL_H_
diff --git a/components/optimization_guide/core/optimization_guide_util_unittest.cc b/components/optimization_guide/core/optimization_guide_util_unittest.cc
index 1d40083..453f09b6 100644
--- a/components/optimization_guide/core/optimization_guide_util_unittest.cc
+++ b/components/optimization_guide/core/optimization_guide_util_unittest.cc
@@ -4,12 +4,6 @@
 
 #include "components/optimization_guide/core/optimization_guide_util.h"
 
-#include "base/base64.h"
-#include "base/command_line.h"
-#include "base/strings/stringprintf.h"
-#include "build/build_config.h"
-#include "components/optimization_guide/core/optimization_guide_switches.h"
-#include "components/optimization_guide/core/optimization_guide_test_util.h"
 #include "components/optimization_guide/proto/loading_predictor_metadata.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -63,141 +57,4 @@
   EXPECT_TRUE(parsed_subresource.preconnect_only());
 }
 
-#if !defined(OS_WIN)
-
-TEST(OptimizationGuideUtilTest,
-     GetModelOverrideForOptimizationTargetSwitchNotSet) {
-  absl::optional<
-      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
-          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
-
-  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
-  EXPECT_FALSE(switches::IsModelOverridePresent());
-}
-
-TEST(OptimizationGuideUtilTest,
-     GetModelOverrideForOptimizationTargetEmptyInput) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kModelOverride);
-
-  absl::optional<
-      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
-          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
-
-  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
-}
-
-TEST(OptimizationGuideUtilTest, GetModelOverrideForOptimizationTargetBadInput) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kModelOverride, "whatever");
-
-  absl::optional<
-      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
-          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
-
-  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
-}
-
-TEST(OptimizationGuideUtilTest,
-     GetModelOverrideForOptimizationTargetInvalidOptimizationTarget) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kModelOverride,
-      "notanoptimizationtarget:" + std::string(kTestAbsoluteFilePath));
-
-  absl::optional<
-      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
-          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
-
-  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
-}
-
-TEST(OptimizationGuideUtilTest,
-     GetModelOverrideForOptimizationTargetRelativeFilePath) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kModelOverride, "OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:" +
-                                    std::string(kTestRelativeFilePath));
-
-  absl::optional<
-      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
-          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
-
-  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
-}
-
-TEST(OptimizationGuideUtilTest,
-     GetModelOverrideForOptimizationTargetRelativeFilePathWithMetadata) {
-  optimization_guide::proto::Any metadata;
-  metadata.set_type_url("sometypeurl");
-  std::string encoded_metadata;
-  metadata.SerializeToString(&encoded_metadata);
-  base::Base64Encode(encoded_metadata, &encoded_metadata);
-
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kModelOverride,
-      base::StringPrintf("OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:%s:%s",
-                         kTestRelativeFilePath, encoded_metadata.c_str()));
-
-  absl::optional<
-      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
-          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
-
-  EXPECT_EQ(absl::nullopt, file_path_and_metadata);
-}
-
-TEST(OptimizationGuideUtilTest,
-     GetModelOverrideForOptimizationTargetOneFilePath) {
-  optimization_guide::proto::Any metadata;
-  metadata.set_type_url("sometypeurl");
-  std::string encoded_metadata;
-  metadata.SerializeToString(&encoded_metadata);
-  base::Base64Encode(encoded_metadata, &encoded_metadata);
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kModelOverride,
-      base::StringPrintf("OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:%s:%s",
-                         kTestAbsoluteFilePath, encoded_metadata.c_str()));
-
-  absl::optional<
-      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
-          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
-
-  EXPECT_EQ(kTestAbsoluteFilePath, file_path_and_metadata->first);
-  EXPECT_EQ("sometypeurl", file_path_and_metadata->second->type_url());
-}
-
-TEST(OptimizationGuideUtilTest,
-     GetModelOverrideForOptimizationTargetMultipleFilePath) {
-  const char kOtherAbsoluteFilePath[] = "/other/file/path";
-  optimization_guide::proto::Any metadata;
-  metadata.set_type_url("sometypeurl");
-  std::string encoded_metadata;
-  metadata.SerializeToString(&encoded_metadata);
-  base::Base64Encode(encoded_metadata, &encoded_metadata);
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kModelOverride,
-      base::StringPrintf("OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:%s,"
-                         "OPTIMIZATION_TARGET_PAGE_TOPICS:%s:%s",
-                         kTestAbsoluteFilePath, kOtherAbsoluteFilePath,
-                         encoded_metadata.c_str()));
-
-  absl::optional<
-      std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
-      file_path_and_metadata = GetModelOverrideForOptimizationTarget(
-          optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
-  EXPECT_EQ(kTestAbsoluteFilePath, file_path_and_metadata->first);
-
-  file_path_and_metadata = GetModelOverrideForOptimizationTarget(
-      optimization_guide::proto::OPTIMIZATION_TARGET_PAGE_TOPICS);
-  EXPECT_EQ(kOtherAbsoluteFilePath, file_path_and_metadata->first);
-  EXPECT_EQ("sometypeurl", file_path_and_metadata->second->type_url());
-}
-
-#endif
-
 }  // namespace optimization_guide
diff --git a/components/page_info/DIR_METADATA b/components/page_info/DIR_METADATA
index 54e4b99..3e117a4 100644
--- a/components/page_info/DIR_METADATA
+++ b/components/page_info/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>Bubbles>PageInfo"
-}
+mixins: "//chrome/browser/ui/page_info/COMMON_METADATA"
 
-team_email: "security-enamel@chromium.org"
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java
index b4936398..5ff1981 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoPermissionsController.java
@@ -34,6 +34,7 @@
         implements PageInfoSubpageController, SingleWebsiteSettings.Observer {
     /**  Parameters to represent a single permission. */
     public static class PermissionObject {
+        public @ContentSettingsType int type;
         public CharSequence name;
         public CharSequence nameMidSentence;
         public boolean allowed;
@@ -45,6 +46,7 @@
     private final PageInfoControllerDelegate mDelegate;
     private final String mTitle;
     private final String mPageUrl;
+    private boolean mHasSoundPermission;
     private boolean mDataIsStale;
     private SingleWebsiteSettings mSubPage;
     @ContentSettingsType
@@ -89,6 +91,8 @@
         if (fragmentManager.isStateSaved()) return null;
 
         Bundle fragmentArgs = SingleWebsiteSettings.createFragmentArgsForSite(mPageUrl);
+        fragmentArgs.putBoolean(SingleWebsiteSettings.EXTRA_SHOW_SOUND, mHasSoundPermission);
+
         mSubPage = (SingleWebsiteSettings) Fragment.instantiate(
                 mRowView.getContext(), SingleWebsiteSettings.class.getName(), fragmentArgs);
         mSubPage.setSiteSettingsDelegate(mDelegate.getSiteSettingsDelegate());
@@ -125,6 +129,14 @@
             rowParams.rowTint = mHighlightColor;
         }
         mRowView.setParams(rowParams);
+
+        mHasSoundPermission = false;
+        for (PermissionObject permission : permissions) {
+            if (permission.type == ContentSettingsType.SOUND) {
+                mHasSoundPermission = true;
+                break;
+            }
+        }
     }
 
     /**
@@ -207,7 +219,7 @@
             mMainController.refreshPermissions();
         }
         mDataIsStale = false;
-    };
+    }
 
     // SingleWebsiteSettings.Observer methods
 
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java b/components/page_info/android/java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java
index 6023219..7a9bdf2 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PermissionParamsListBuilder.java
@@ -63,6 +63,7 @@
     private PermissionObject createPermissionParams(
             PermissionParamsListBuilder.PageInfoPermissionEntry permission) {
         PermissionObject permissionParams = new PermissionObject();
+        permissionParams.type = permission.type;
 
         if (permission.setting == ContentSettingValues.ALLOW) {
             LocationUtils locationUtils = LocationUtils.getInstance();
diff --git a/components/paint_preview/COMMON_METADATA b/components/paint_preview/COMMON_METADATA
new file mode 100644
index 0000000..2782d66
--- /dev/null
+++ b/components/paint_preview/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>FreezeDriedTabs"
+}
diff --git a/components/paint_preview/DIR_METADATA b/components/paint_preview/DIR_METADATA
index 2782d66..1148592 100644
--- a/components/paint_preview/DIR_METADATA
+++ b/components/paint_preview/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>FreezeDriedTabs"
-}
+mixins: "//components/paint_preview/COMMON_METADATA"
diff --git a/components/password_manager/COMMON_METADATA b/components/password_manager/COMMON_METADATA
new file mode 100644
index 0000000..14f1f46
--- /dev/null
+++ b/components/password_manager/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>Passwords"
+}
+team_email: "chromium-dev@chromium.org"
diff --git a/components/password_manager/DIR_METADATA b/components/password_manager/DIR_METADATA
index 14f1f46..5b9fb11 100644
--- a/components/password_manager/DIR_METADATA
+++ b/components/password_manager/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Passwords"
-}
-team_email: "chromium-dev@chromium.org"
+mixins: "//components/password_manager/COMMON_METADATA"
diff --git a/components/password_manager/core/browser/sync/DIR_METADATA b/components/password_manager/core/browser/sync/DIR_METADATA
new file mode 100644
index 0000000..4a58e65
--- /dev/null
+++ b/components/password_manager/core/browser/sync/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/components/payments/COMMON_METADATA b/components/payments/COMMON_METADATA
new file mode 100644
index 0000000..53ab283
--- /dev/null
+++ b/components/payments/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Payments"
+}
+team_email: "payments-dev@chromium.org"
diff --git a/components/payments/DIR_METADATA b/components/payments/DIR_METADATA
index 53ab283..9dddbb4 100644
--- a/components/payments/DIR_METADATA
+++ b/components/payments/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Payments"
-}
-team_email: "payments-dev@chromium.org"
+mixins: "//components/payments/COMMON_METADATA"
diff --git a/components/pdf/DIR_METADATA b/components/pdf/DIR_METADATA
index 507a6ca..0563e2c 100644
--- a/components/pdf/DIR_METADATA
+++ b/components/pdf/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Plugins>PDF"
-}
+mixins: "//pdf/COMMON_METADATA"
diff --git a/components/performance_manager/COMMON_METADATA b/components/performance_manager/COMMON_METADATA
new file mode 100644
index 0000000..f2dfe46
--- /dev/null
+++ b/components/performance_manager/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>PerformanceManager"
+}
+
+team_email: "catan-team@chromium.org"
diff --git a/components/performance_manager/DIR_METADATA b/components/performance_manager/DIR_METADATA
index f2dfe46..d1bfea0b 100644
--- a/components/performance_manager/DIR_METADATA
+++ b/components/performance_manager/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>PerformanceManager"
-}
+mixins: "//components/performance_manager/COMMON_METADATA"
 
-team_email: "catan-team@chromium.org"
diff --git a/components/policy/COMMON_METADATA b/components/policy/COMMON_METADATA
new file mode 100644
index 0000000..04f1804
--- /dev/null
+++ b/components/policy/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Enterprise"
+}
+
+team_email: "chromium-enterprise@chromium.org"
diff --git a/components/policy/DIR_METADATA b/components/policy/DIR_METADATA
index 04f1804..b9feba2 100644
--- a/components/policy/DIR_METADATA
+++ b/components/policy/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Enterprise"
-}
+mixins: "//components/policy/COMMON_METADATA"
 
-team_email: "chromium-enterprise@chromium.org"
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index afbbb54..4f6652b 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -624,6 +624,9 @@
   <message name="IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM" desc="A toast informing the user that sharing clipboard data to VMs is blocked.">
     Sharing from <ph name="ORIGIN_NAME">$1<ex>corp.google.com</ex></ph> to <ph name="VM_NAME">$2<ex>Linux</ex></ph> has been blocked by administrator policy
   </message>
+  <message name="IDS_POLICY_DLP_CLIPBOARD_BLOCK_TOAST_BUTTON" desc="Dismiss toast button label for disabled paste notification.">
+    View details
+  </message>
   <message name="IDS_POLICY_DLP_ANDROID_APPS" desc="Name shown for ARC in data leak prevention toasts.">
     Android apps
   </message>
@@ -676,7 +679,7 @@
     Capture confidential content on your screen
   </message>
   <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_MESSAGE" desc="The message for notification informing the user that screen capture is not recommended.">
-    Administrator doesn't recommend taking screenshots or recordings due to confidential content on screen
+    Administrator doesn't recommend taking screenshots or recordings due to confidential content on screen.
   </message>
   <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_CONTINUE_BUTTON" desc="Continue dialog button label for warning before screen capture.">
     Capture anyway
@@ -684,5 +687,17 @@
   <message name="IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_CANCEL_BUTTON" desc="Cancel dialog button label for warning before screen capture.">
     Cancel
   </message>
+  <message name="IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_TITLE" desc="The title for notification informing the user that there was confidential information revealed during screen recording.">
+    Capture confidential content on your screen
+  </message>
+  <message name="IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_MESSAGE" desc="The message for notification informing the user that there was confidential information revealed during screen recording.">
+    Administrator doesn't recommend taking screenshots or recordings due to confidential content captured.
+  </message>
+  <message name="IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CONTINUE_BUTTON" desc="Continue dialog button label for warning before saving a screen recording.">
+    Save anyway
+  </message>
+  <message name="IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CANCEL_BUTTON" desc="Cancel dialog button label for warning before saving a screen recording.">
+    Delete recording
+  </message>
 
 </grit-part>
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCK_TOAST_BUTTON.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCK_TOAST_BUTTON.png.sha1
new file mode 100644
index 0000000..2628d81
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCK_TOAST_BUTTON.png.sha1
@@ -0,0 +1 @@
+ea8d0fc8a0d74bc8f4804f2a196d21a4637c4a6c
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_MESSAGE.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_MESSAGE.png.sha1
index 1100a7b..be71cd4 100644
--- a/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_MESSAGE.png.sha1
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_SCREEN_CAPTURE_WARN_MESSAGE.png.sha1
@@ -1 +1 @@
-9fee8a9985a1447260bb4c020f8c3696048d3f3f
\ No newline at end of file
+6515d69f1058cdb633f78848c386e59e02b26642
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CANCEL_BUTTON.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CANCEL_BUTTON.png.sha1
new file mode 100644
index 0000000..08158b3
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CANCEL_BUTTON.png.sha1
@@ -0,0 +1 @@
+843b4e2af808a83b5845476a1320b7d334f2e928
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CONTINUE_BUTTON.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CONTINUE_BUTTON.png.sha1
new file mode 100644
index 0000000..08158b3
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_CONTINUE_BUTTON.png.sha1
@@ -0,0 +1 @@
+843b4e2af808a83b5845476a1320b7d334f2e928
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_MESSAGE.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_MESSAGE.png.sha1
new file mode 100644
index 0000000..08158b3
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_MESSAGE.png.sha1
@@ -0,0 +1 @@
+843b4e2af808a83b5845476a1320b7d334f2e928
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_TITLE.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_TITLE.png.sha1
new file mode 100644
index 0000000..08158b3
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_VIDEO_CAPTURE_WARN_TITLE.png.sha1
@@ -0,0 +1 @@
+843b4e2af808a83b5845476a1320b7d334f2e928
\ No newline at end of file
diff --git a/components/printing/DIR_METADATA b/components/printing/DIR_METADATA
index c6bf1f0..2413ed4 100644
--- a/components/printing/DIR_METADATA
+++ b/components/printing/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Printing"
-}
+mixins: "//printing/COMMON_METADATA"
diff --git a/components/query_tiles/COMMON_METADATA b/components/query_tiles/COMMON_METADATA
new file mode 100644
index 0000000..1a778a1
--- /dev/null
+++ b/components/query_tiles/COMMON_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Upboarding>QueryTiles"
+}
+
+team_email: "chrome-upboarding-eng@google.com"
+
+os: ANDROID
diff --git a/components/query_tiles/DIR_METADATA b/components/query_tiles/DIR_METADATA
index 1a778a1..0f762fc6 100644
--- a/components/query_tiles/DIR_METADATA
+++ b/components/query_tiles/DIR_METADATA
@@ -1,7 +1,2 @@
-monorail {
-  component: "Upboarding>QueryTiles"
-}
+mixins: "//components/query_tiles/COMMON_METADATA"
 
-team_email: "chrome-upboarding-eng@google.com"
-
-os: ANDROID
diff --git a/components/search/COMMON_METADATA b/components/search/COMMON_METADATA
new file mode 100644
index 0000000..1ee6aef
--- /dev/null
+++ b/components/search/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>NewTabPage"
+}
+
+team_email: "ntp-dev@chromium.org"
diff --git a/components/search/DIR_METADATA b/components/search/DIR_METADATA
index 1ee6aef..18b53146 100644
--- a/components/search/DIR_METADATA
+++ b/components/search/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>NewTabPage"
-}
+mixins: "//components/search/COMMON_METADATA"
 
-team_email: "ntp-dev@chromium.org"
diff --git a/components/search_engines/COMMON_METADATA b/components/search_engines/COMMON_METADATA
new file mode 100644
index 0000000..4bbdcae
--- /dev/null
+++ b/components/search_engines/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Search"
+}
diff --git a/components/search_engines/DIR_METADATA b/components/search_engines/DIR_METADATA
index 4bbdcae..1249d12 100644
--- a/components/search_engines/DIR_METADATA
+++ b/components/search_engines/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Search"
-}
+mixins: "//components/search_engines/COMMON_METADATA"
diff --git a/components/search_engines/android/DIR_METADATA b/components/search_engines/android/DIR_METADATA
new file mode 100644
index 0000000..c69388e
--- /dev/null
+++ b/components/search_engines/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/components/search_provider_logos/COMMON_METADATA b/components/search_provider_logos/COMMON_METADATA
new file mode 100644
index 0000000..77ca58f
--- /dev/null
+++ b/components/search_provider_logos/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>NewTabPage"
+}
diff --git a/components/search_provider_logos/DIR_METADATA b/components/search_provider_logos/DIR_METADATA
index 77ca58f..1f479675 100644
--- a/components/search_provider_logos/DIR_METADATA
+++ b/components/search_provider_logos/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>NewTabPage"
-}
+mixins: "//components/search_provider_logos/COMMON_METADATA"
diff --git a/components/segmentation_platform/COMMON_METADATA b/components/segmentation_platform/COMMON_METADATA
new file mode 100644
index 0000000..e90fa6294
--- /dev/null
+++ b/components/segmentation_platform/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>SegmentationPlatform"
+}
+
+team_email: "chrome-segmentation-platform@google.com"
diff --git a/components/segmentation_platform/DIR_METADATA b/components/segmentation_platform/DIR_METADATA
index e90fa6294..837ac09 100644
--- a/components/segmentation_platform/DIR_METADATA
+++ b/components/segmentation_platform/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>SegmentationPlatform"
-}
+mixins: "//components/segmentation_platform/COMMON_METADATA"
 
-team_email: "chrome-segmentation-platform@google.com"
diff --git a/components/send_tab_to_self/COMMON_METADATA b/components/send_tab_to_self/COMMON_METADATA
new file mode 100644
index 0000000..167ca6e
--- /dev/null
+++ b/components/send_tab_to_self/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Sharing"
+}
diff --git a/components/send_tab_to_self/DIR_METADATA b/components/send_tab_to_self/DIR_METADATA
index 167ca6e..024779e 100644
--- a/components/send_tab_to_self/DIR_METADATA
+++ b/components/send_tab_to_self/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Sharing"
-}
+mixins: "//components/send_tab_to_self/COMMON_METADATA"
diff --git a/components/services/DIR_METADATA b/components/services/DIR_METADATA
index 07ff2e9..e1ce67e 100644
--- a/components/services/DIR_METADATA
+++ b/components/services/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Services"
-}
+mixins: "//services/COMMON_METADATA"
diff --git a/components/services/app_service/COMMON_METADATA b/components/services/app_service/COMMON_METADATA
new file mode 100644
index 0000000..21dfabe8
--- /dev/null
+++ b/components/services/app_service/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "Platform>Apps>Foundation>AppService"
+}
+team_email: "chromeos-apps-foundation-team@google.com"
diff --git a/components/services/app_service/DIR_METADATA b/components/services/app_service/DIR_METADATA
index 21dfabe8..c0404074 100644
--- a/components/services/app_service/DIR_METADATA
+++ b/components/services/app_service/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Platform>Apps>Foundation>AppService"
-}
-team_email: "chromeos-apps-foundation-team@google.com"
+mixins: "//components/services/app_service/COMMON_METADATA"
diff --git a/components/services/storage/dom_storage/DIR_METADATA b/components/services/storage/dom_storage/DIR_METADATA
index 69f4bfe..9f9b3e4 100644
--- a/components/services/storage/dom_storage/DIR_METADATA
+++ b/components/services/storage/dom_storage/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>Storage>DOMStorage"
-}
+mixins: "//content/browser/dom_storage/COMMON_METADATA"
 
diff --git a/components/services/storage/indexed_db/DIR_METADATA b/components/services/storage/indexed_db/DIR_METADATA
index 0d8be5e..7a835e3 100644
--- a/components/services/storage/indexed_db/DIR_METADATA
+++ b/components/services/storage/indexed_db/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>Storage>IndexedDB"
-}
+mixins: "//content/browser/indexed_db/COMMON_METADATA"
 
diff --git a/components/services/storage/service_worker/DIR_METADATA b/components/services/storage/service_worker/DIR_METADATA
new file mode 100644
index 0000000..e253a13
--- /dev/null
+++ b/components/services/storage/service_worker/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/service_worker/COMMON_METADATA"
diff --git a/components/signin/COMMON_METADATA b/components/signin/COMMON_METADATA
new file mode 100644
index 0000000..4735e25f
--- /dev/null
+++ b/components/signin/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Services>SignIn"
+}
+
+team_email: "chrome-signin@chromium.org"
diff --git a/components/signin/DIR_METADATA b/components/signin/DIR_METADATA
index 4735e25f..4162bb3 100644
--- a/components/signin/DIR_METADATA
+++ b/components/signin/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Services>SignIn"
-}
+mixins: "//components/signin/COMMON_METADATA"
 
-team_email: "chrome-signin@chromium.org"
diff --git a/components/subresource_filter/COMMON_METADATA b/components/subresource_filter/COMMON_METADATA
new file mode 100644
index 0000000..352eefc
--- /dev/null
+++ b/components/subresource_filter/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>AdFilter"
+}
diff --git a/components/subresource_filter/DIR_METADATA b/components/subresource_filter/DIR_METADATA
index 352eefc..2ada13c 100644
--- a/components/subresource_filter/DIR_METADATA
+++ b/components/subresource_filter/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>AdFilter"
-}
+mixins: "//components/subresource_filter/COMMON_METADATA"
diff --git a/components/sync/COMMON_METADATA b/components/sync/COMMON_METADATA
new file mode 100644
index 0000000..1a6d7ee6
--- /dev/null
+++ b/components/sync/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Services>Sync"
+}
diff --git a/components/sync/DIR_METADATA b/components/sync/DIR_METADATA
index 1a6d7ee6..4a58e65 100644
--- a/components/sync/DIR_METADATA
+++ b/components/sync/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Services>Sync"
-}
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/components/test/data/autofill/DIR_METADATA b/components/test/data/autofill/DIR_METADATA
index b597ffd..bc280336 100644
--- a/components/test/data/autofill/DIR_METADATA
+++ b/components/test/data/autofill/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Autofill"
-}
+mixins: "//components/autofill/COMMON_METADATA"
diff --git a/components/test/data/cast_certificate/DIR_METADATA b/components/test/data/cast_certificate/DIR_METADATA
new file mode 100644
index 0000000..25e6a775
--- /dev/null
+++ b/components/test/data/cast_certificate/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/cast_certificate/COMMON_METADATA"
diff --git a/components/test/data/data_reduction_proxy/DIR_METADATA b/components/test/data/data_reduction_proxy/DIR_METADATA
new file mode 100644
index 0000000..eb96fa3
--- /dev/null
+++ b/components/test/data/data_reduction_proxy/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/data_reduction_proxy/COMMON_METADATA"
diff --git a/components/test/data/dom_distiller/DIR_METADATA b/components/test/data/dom_distiller/DIR_METADATA
new file mode 100644
index 0000000..ca7bc37
--- /dev/null
+++ b/components/test/data/dom_distiller/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/dom_distiller/COMMON_METADATA"
diff --git a/components/test/data/password_manager/DIR_METADATA b/components/test/data/password_manager/DIR_METADATA
index 43d76b8..5b9fb11 100644
--- a/components/test/data/password_manager/DIR_METADATA
+++ b/components/test/data/password_manager/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Passwords"
-}
+mixins: "//components/password_manager/COMMON_METADATA"
diff --git a/components/test/data/performance_manager/DIR_METADATA b/components/test/data/performance_manager/DIR_METADATA
index e190e20..e9e0173 100644
--- a/components/test/data/performance_manager/DIR_METADATA
+++ b/components/test/data/performance_manager/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>PerformanceManager"
-}
+mixins: "//components/performance_manager/COMMON_METADATA"
diff --git a/components/test/data/update_client/DIR_METADATA b/components/test/data/update_client/DIR_METADATA
index f29e6cf..960396cb 100644
--- a/components/test/data/update_client/DIR_METADATA
+++ b/components/test/data/update_client/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Installer>Components"
-}
+mixins: "//components/update_client/COMMON_METADATA"
 
-team_email: "chrome-updates-dev@chromium.org"
diff --git a/components/test/data/webcrypto/DIR_METADATA b/components/test/data/webcrypto/DIR_METADATA
new file mode 100644
index 0000000..624c9db
--- /dev/null
+++ b/components/test/data/webcrypto/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/webcrypto/COMMON_METADATA"
diff --git a/components/translate/COMMON_METADATA b/components/translate/COMMON_METADATA
new file mode 100644
index 0000000..f750899
--- /dev/null
+++ b/components/translate/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Language>Translate"
+}
diff --git a/components/translate/DIR_METADATA b/components/translate/DIR_METADATA
index f750899..58ea368c 100644
--- a/components/translate/DIR_METADATA
+++ b/components/translate/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>Language>Translate"
-}
+mixins: "//components/translate/COMMON_METADATA"
diff --git a/components/unified_consent/COMMON_METADATA b/components/unified_consent/COMMON_METADATA
new file mode 100644
index 0000000..4735e25f
--- /dev/null
+++ b/components/unified_consent/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Services>SignIn"
+}
+
+team_email: "chrome-signin@chromium.org"
diff --git a/components/unified_consent/DIR_METADATA b/components/unified_consent/DIR_METADATA
index 4735e25f..1e976573 100644
--- a/components/unified_consent/DIR_METADATA
+++ b/components/unified_consent/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Services>SignIn"
-}
+mixins: "//components/unified_consent/COMMON_METADATA"
 
-team_email: "chrome-signin@chromium.org"
diff --git a/components/update_client/COMMON_METADATA b/components/update_client/COMMON_METADATA
new file mode 100644
index 0000000..f29e6cf
--- /dev/null
+++ b/components/update_client/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>Installer>Components"
+}
+
+team_email: "chrome-updates-dev@chromium.org"
diff --git a/components/update_client/DIR_METADATA b/components/update_client/DIR_METADATA
index f29e6cf..960396cb 100644
--- a/components/update_client/DIR_METADATA
+++ b/components/update_client/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Installer>Components"
-}
+mixins: "//components/update_client/COMMON_METADATA"
 
-team_email: "chrome-updates-dev@chromium.org"
diff --git a/components/vector_icons/COMMON_METADATA b/components/vector_icons/COMMON_METADATA
new file mode 100644
index 0000000..ba32dd7
--- /dev/null
+++ b/components/vector_icons/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Assets>Images"
+}
diff --git a/components/vector_icons/DIR_METADATA b/components/vector_icons/DIR_METADATA
index ba32dd7..54e77e3 100644
--- a/components/vector_icons/DIR_METADATA
+++ b/components/vector_icons/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Assets>Images"
-}
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/components/viz/COMMON_METADATA b/components/viz/COMMON_METADATA
new file mode 100644
index 0000000..f7e4412
--- /dev/null
+++ b/components/viz/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>Compositing"
+}
+
+team_email: "graphics-dev@chromium.org"
diff --git a/components/viz/DIR_METADATA b/components/viz/DIR_METADATA
index f7e4412..b3ba172 100644
--- a/components/viz/DIR_METADATA
+++ b/components/viz/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Compositing"
-}
+mixins: "//components/viz/COMMON_METADATA"
 
-team_email: "graphics-dev@chromium.org"
diff --git a/components/webapk/COMMON_METADATA b/components/webapk/COMMON_METADATA
new file mode 100644
index 0000000..1a508bb4
--- /dev/null
+++ b/components/webapk/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Mobile>WebAPKs"
+}
+
+team_email: "webapk-team@chromium.org"
diff --git a/components/webapk/DIR_METADATA b/components/webapk/DIR_METADATA
index 1a508bb4..58862a8 100644
--- a/components/webapk/DIR_METADATA
+++ b/components/webapk/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Mobile>WebAPKs"
-}
+mixins: "//components/webapk/COMMON_METADATA"
 
-team_email: "webapk-team@chromium.org"
diff --git a/components/webapps/COMMON_METADATA b/components/webapps/COMMON_METADATA
new file mode 100644
index 0000000..11597323
--- /dev/null
+++ b/components/webapps/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org"
diff --git a/components/webapps/DIR_METADATA b/components/webapps/DIR_METADATA
index 11597323..49c72b4 100644
--- a/components/webapps/DIR_METADATA
+++ b/components/webapps/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
+mixins: "//components/webapps/COMMON_METADATA"
diff --git a/components/webcrypto/COMMON_METADATA b/components/webcrypto/COMMON_METADATA
new file mode 100644
index 0000000..86d9592
--- /dev/null
+++ b/components/webcrypto/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebCrypto"
+}
diff --git a/components/webcrypto/DIR_METADATA b/components/webcrypto/DIR_METADATA
index 86d9592..624c9db 100644
--- a/components/webcrypto/DIR_METADATA
+++ b/components/webcrypto/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebCrypto"
-}
+mixins: "//components/webcrypto/COMMON_METADATA"
diff --git a/components/webrtc/DIR_METADATA b/components/webrtc/DIR_METADATA
index 66cc019..58da5fd 100644
--- a/components/webrtc/DIR_METADATA
+++ b/components/webrtc/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebRTC"
-}
+mixins: "//third_party/blink/public/platform/modules/webrtc/COMMON_METADATA"
diff --git a/components/webrtc_logging/OWNERS b/components/webrtc_logging/OWNERS
index b88212c..ed7c54a 100644
--- a/components/webrtc_logging/OWNERS
+++ b/components/webrtc_logging/OWNERS
@@ -1,2 +1,2 @@
-grunell@chromium.org
+eladalon@chromium.org
 tommi@chromium.org
diff --git a/content/app/android/DIR_METADATA b/content/app/android/DIR_METADATA
new file mode 100644
index 0000000..c69388e
--- /dev/null
+++ b/content/app/android/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/COMMON_METADATA"
diff --git a/content/browser/accessibility/DIR_METADATA b/content/browser/accessibility/DIR_METADATA
index 299fade..c775858 100644
--- a/content/browser/accessibility/DIR_METADATA
+++ b/content/browser/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail {
   component: "UI>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index cb9b8807..e6fb12f 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -317,6 +317,11 @@
   return HasState(ax::mojom::State::kMultiselectable);
 }
 
+bool BrowserAccessibilityAndroid::IsRangeControlWithoutAriaValueText() const {
+  return GetData().IsRangeValueSupported() &&
+         !HasStringAttribute(ax::mojom::StringAttribute::kValue);
+}
+
 bool BrowserAccessibilityAndroid::IsReportingCheckable() const {
   // To communicate kMixed state Checkboxes, we will rely on state description,
   // so we will not report node as checkable to avoid duplicate utterances.
@@ -604,8 +609,15 @@
   }
 
   std::u16string text = GetNameAsString16();
-  if (text.empty())
+  if (text.empty()) {
+    // When a node does not have a name (e.g. a label), use its value instead.
     text = value;
+  } else if (ui::IsRangeValueSupported(GetRole()) && !value.empty()) {
+    // For controls that support range values such as sliders, when a non-empty
+    // name is present (e.g. a label), append this to the value so both the
+    // valuetext and label are included, rather than replacing the value.
+    text = value + u", " + text;
+  }
 
   // For almost all focusable nodes we try to get text from contents, but for
   // the root node that's redundant and often way too verbose.
@@ -1660,9 +1672,10 @@
 
 int BrowserAccessibilityAndroid::GetItemIndex() const {
   int index = 0;
-  if (GetData().IsRangeValueSupported()) {
+  if (IsRangeControlWithoutAriaValueText()) {
     // Return a percentage here for live feedback in an AccessibilityEvent.
-    // The exact value is returned in RangeCurrentValue.
+    // The exact value is returned in RangeCurrentValue. Exclude sliders with
+    // an aria-valuetext set, as a percentage is not meaningful in those cases.
     float min = GetFloatAttribute(ax::mojom::FloatAttribute::kMinValueForRange);
     float max = GetFloatAttribute(ax::mojom::FloatAttribute::kMaxValueForRange);
     float value = GetFloatAttribute(ax::mojom::FloatAttribute::kValueForRange);
@@ -1678,10 +1691,11 @@
 
 int BrowserAccessibilityAndroid::GetItemCount() const {
   int count = 0;
-  if (GetData().IsRangeValueSupported()) {
+  if (IsRangeControlWithoutAriaValueText()) {
     // An AccessibilityEvent can only return integer information about a
     // seek control, so we return a percentage. The real range is returned
-    // in RangeMin and RangeMax.
+    // in RangeMin and RangeMax. Exclude sliders with an aria-valuetext set,
+    // as a percentage is not meaningful in those cases.
     count = 100;
   } else {
     if (IsCollection() && node()->GetSetSize())
diff --git a/content/browser/accessibility/browser_accessibility_android.h b/content/browser/accessibility/browser_accessibility_android.h
index c93934e..032f4f9 100644
--- a/content/browser/accessibility/browser_accessibility_android.h
+++ b/content/browser/accessibility/browser_accessibility_android.h
@@ -49,6 +49,7 @@
   bool IsLink() const;
   bool IsMultiLine() const;
   bool IsMultiselectable() const;
+  bool IsRangeControlWithoutAriaValueText() const;
   bool IsReportingCheckable() const;
   bool IsScrollable() const;
   bool IsSeekControl() const;
diff --git a/content/browser/accessibility/web_contents_accessibility_android.cc b/content/browser/accessibility/web_contents_accessibility_android.cc
index bf795df..016e10e 100644
--- a/content/browser/accessibility/web_contents_accessibility_android.cc
+++ b/content/browser/accessibility/web_contents_accessibility_android.cc
@@ -776,7 +776,7 @@
   // update the cached node to work around this. This is not necessary on newer
   // versions of Android that contain the fix, see: ag/930331
   // TODO(mschillaci): Remove this when Android M is no longer supported.
-  if (node->GetData().IsRangeValueSupported()) {
+  if (node->IsRangeControlWithoutAriaValueText()) {
     Java_WebContentsAccessibilityImpl_setAccessibilityNodeInfoRangeInfo(
         env, obj, info, node->AndroidRangeType(), node->RangeMin(),
         node->RangeMax(), node->RangeCurrentValue());
@@ -896,7 +896,12 @@
         env, obj, info, node->RowIndex(), node->RowSpan(), node->ColumnIndex(),
         node->ColumnSpan(), node->IsHeading());
   }
-  if (node->GetData().IsRangeValueSupported()) {
+
+  // For sliders that are numeric, use the AccessibilityNodeInfo.RangeInfo
+  // object as expected. But for non-numeric ranges (e.g. "small", "medium",
+  // "large"), do not set the RangeInfo object and instead rely on announcing
+  // the aria-valuetext value, which will be included in the node's text value.
+  if (node->IsRangeControlWithoutAriaValueText()) {
     Java_WebContentsAccessibilityImpl_setAccessibilityNodeInfoRangeInfo(
         env, obj, info, node->AndroidRangeType(), node->RangeMin(),
         node->RangeMax(), node->RangeCurrentValue());
diff --git a/content/browser/aggregation_service/COMMON_METADATA b/content/browser/aggregation_service/COMMON_METADATA
new file mode 100644
index 0000000..4f8aa58
--- /dev/null
+++ b/content/browser/aggregation_service/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>ConversionMeasurement"
+}
+team_email: "privacy-sandbox-dev@chromium.org"
diff --git a/content/browser/aggregation_service/DIR_METADATA b/content/browser/aggregation_service/DIR_METADATA
index 4f8aa58..e5ef722 100644
--- a/content/browser/aggregation_service/DIR_METADATA
+++ b/content/browser/aggregation_service/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>ConversionMeasurement"
-}
-team_email: "privacy-sandbox-dev@chromium.org"
+mixins: "//content/browser/aggregation_service/COMMON_METADATA"
diff --git a/content/browser/appcache/COMMON_METADATA b/content/browser/appcache/COMMON_METADATA
new file mode 100644
index 0000000..22c0ad12
--- /dev/null
+++ b/content/browser/appcache/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>AppCache"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/appcache/DIR_METADATA b/content/browser/appcache/DIR_METADATA
index 22c0ad12..1a26389 100644
--- a/content/browser/appcache/DIR_METADATA
+++ b/content/browser/appcache/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>AppCache"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/appcache/COMMON_METADATA"
diff --git a/content/browser/attribution_reporting/COMMON_METADATA b/content/browser/attribution_reporting/COMMON_METADATA
new file mode 100644
index 0000000..4f8aa58
--- /dev/null
+++ b/content/browser/attribution_reporting/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>ConversionMeasurement"
+}
+team_email: "privacy-sandbox-dev@chromium.org"
diff --git a/content/browser/attribution_reporting/DIR_METADATA b/content/browser/attribution_reporting/DIR_METADATA
index 4f8aa58..0598e0e 100644
--- a/content/browser/attribution_reporting/DIR_METADATA
+++ b/content/browser/attribution_reporting/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>ConversionMeasurement"
-}
-team_email: "privacy-sandbox-dev@chromium.org"
+mixins: "//content/browser/attribution_reporting/COMMON_METADATA"
diff --git a/content/browser/audio/DIR_METADATA b/content/browser/audio/DIR_METADATA
new file mode 100644
index 0000000..aac36aa
--- /dev/null
+++ b/content/browser/audio/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//services/audio/COMMON_METADATA"
diff --git a/content/browser/background_fetch/COMMON_METADATA b/content/browser/background_fetch/COMMON_METADATA
new file mode 100644
index 0000000..1e7d798
--- /dev/null
+++ b/content/browser/background_fetch/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>BackgroundFetch"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/content/browser/background_fetch/DIR_METADATA b/content/browser/background_fetch/DIR_METADATA
index 1e7d798..7a535e15 100644
--- a/content/browser/background_fetch/DIR_METADATA
+++ b/content/browser/background_fetch/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>BackgroundFetch"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//content/browser/background_fetch/COMMON_METADATA"
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index aa47f94..14f0d60 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -248,7 +248,7 @@
 }
 
 base::WeakPtr<BackgroundFetchContext> BackgroundFetchContext::GetWeakPtr() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return weak_factory_.GetWeakPtr();
 }
 
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
index 7d738aa..2b1ab78e 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
@@ -67,12 +67,10 @@
                                                         std::move(response));
     if (complete_downloads_) {
       // Post a task so that Abort() can cancel this download before completing.
-      BrowserThread::GetTaskRunnerForThread(
-          ServiceWorkerContext::GetCoreThreadId())
-          ->PostTask(
-              FROM_HERE,
-              base::BindOnce(&FakeBackgroundFetchDelegate::CompleteDownload,
-                             base::Unretained(this), job_unique_id, guid));
+      GetUIThreadTaskRunner({})->PostTask(
+          FROM_HERE,
+          base::BindOnce(&FakeBackgroundFetchDelegate::CompleteDownload,
+                         base::Unretained(this), job_unique_id, guid));
     }
   }
 
diff --git a/content/browser/background_fetch/background_fetch_event_dispatcher.cc b/content/browser/background_fetch/background_fetch_event_dispatcher.cc
index b5202e0..d0ff385 100644
--- a/content/browser/background_fetch/background_fetch_event_dispatcher.cc
+++ b/content/browser/background_fetch/background_fetch_event_dispatcher.cc
@@ -102,7 +102,7 @@
 }
 
 BackgroundFetchEventDispatcher::~BackgroundFetchEventDispatcher() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void BackgroundFetchEventDispatcher::DispatchBackgroundFetchCompletionEvent(
@@ -150,7 +150,7 @@
     const BackgroundFetchRegistrationId& registration_id,
     blink::mojom::BackgroundFetchRegistrationPtr registration,
     base::OnceClosure finished_closure) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   LogBackgroundFetchCompletionForDevTools(
       registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_ABORT,
@@ -179,7 +179,7 @@
     const BackgroundFetchRegistrationId& registration_id,
     blink::mojom::BackgroundFetchRegistrationDataPtr registration_data,
     base::OnceClosure finished_closure) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(registration_data);
 
   auto registration = blink::mojom::BackgroundFetchRegistration::New(
@@ -210,7 +210,7 @@
     const BackgroundFetchRegistrationId& registration_id,
     blink::mojom::BackgroundFetchRegistrationPtr registration,
     base::OnceClosure finished_closure) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   LogBackgroundFetchCompletionForDevTools(
       registration_id, ServiceWorkerMetrics::EventType::BACKGROUND_FETCH_FAIL,
@@ -239,7 +239,7 @@
     const BackgroundFetchRegistrationId& registration_id,
     blink::mojom::BackgroundFetchRegistrationPtr registration,
     base::OnceClosure finished_closure) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   LogBackgroundFetchCompletionForDevTools(
       registration_id,
@@ -353,7 +353,7 @@
     const BackgroundFetchRegistrationId& registration_id,
     ServiceWorkerMetrics::EventType event_type,
     blink::mojom::BackgroundFetchFailureReason failure_reason) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (!devtools_context_->IsRecording(
           DevToolsBackgroundService::kBackgroundFetch)) {
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc
index 4cd4ca9..176d079 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -88,7 +88,7 @@
       upload_total_(upload_total),
       progress_callback_(std::move(progress_callback)),
       finished_callback_(std::move(finished_callback)) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void BackgroundFetchJobController::InitializeRequestStatus(
@@ -97,7 +97,7 @@
     std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
         active_fetch_requests,
     bool start_paused) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Don't allow double initialization.
   DCHECK_GT(total_downloads, 0);
@@ -129,7 +129,7 @@
 }
 
 BackgroundFetchJobController::~BackgroundFetchJobController() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 bool BackgroundFetchJobController::HasMoreRequests() {
@@ -139,7 +139,7 @@
 void BackgroundFetchJobController::StartRequest(
     scoped_refptr<BackgroundFetchRequestInfo> request,
     RequestFinishedCallback request_finished_callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_LT(completed_downloads_, total_downloads_);
   DCHECK(request_finished_callback);
   DCHECK(request);
@@ -166,7 +166,7 @@
 void BackgroundFetchJobController::DidStartRequest(
     const std::string& guid,
     std::unique_ptr<BackgroundFetchResponse> response) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   DCHECK(active_request_map_.count(guid));
   const auto& request = active_request_map_[guid];
@@ -185,7 +185,7 @@
 void BackgroundFetchJobController::DidUpdateRequest(const std::string& guid,
                                                     uint64_t bytes_uploaded,
                                                     uint64_t bytes_downloaded) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   DCHECK(active_request_map_.count(guid));
   const auto& request = active_request_map_[guid];
@@ -214,7 +214,7 @@
 void BackgroundFetchJobController::DidCompleteRequest(
     const std::string& guid,
     std::unique_ptr<BackgroundFetchResult> result) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   DCHECK(active_request_map_.count(guid));
   const auto& request = active_request_map_[guid];
diff --git a/content/browser/background_fetch/background_fetch_registration_service_impl.cc b/content/browser/background_fetch/background_fetch_registration_service_impl.cc
index 325f3bc..0d6f009 100644
--- a/content/browser/background_fetch/background_fetch_registration_service_impl.cc
+++ b/content/browser/background_fetch/background_fetch_registration_service_impl.cc
@@ -69,7 +69,7 @@
     blink::mojom::CacheQueryOptionsPtr cache_query_options,
     bool match_all,
     MatchRequestsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!background_fetch_context_) {
     // Return without running the callback because this case happens only when
     // the browser is shutting down.
@@ -88,7 +88,7 @@
     const absl::optional<std::string>& title,
     const SkBitmap& icon,
     UpdateUICallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!background_fetch_context_) {
     // Return without running the callback because this case happens only when
     // the browser is shutting down.
@@ -110,7 +110,7 @@
 }
 
 void BackgroundFetchRegistrationServiceImpl::Abort(AbortCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!background_fetch_context_) {
     // Return without running the callback because this case happens only when
     // the browser is shutting down.
@@ -122,7 +122,7 @@
 void BackgroundFetchRegistrationServiceImpl::AddRegistrationObserver(
     mojo::PendingRemote<blink::mojom::BackgroundFetchRegistrationObserver>
         observer) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!background_fetch_context_)
     return;
   background_fetch_context_->AddRegistrationObserver(
diff --git a/content/browser/background_fetch/background_fetch_request_info.cc b/content/browser/background_fetch/background_fetch_request_info.cc
index 04ef94c..4c82c77 100644
--- a/content/browser/background_fetch/background_fetch_request_info.cc
+++ b/content/browser/background_fetch/background_fetch_request_info.cc
@@ -119,7 +119,7 @@
 
 void BackgroundFetchRequestInfo::SetEmptyResultWithFailureReason(
     BackgroundFetchResult::FailureReason failure_reason) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   result_ = std::make_unique<BackgroundFetchResult>(
       /* response= */ nullptr, base::Time::Now(), failure_reason);
@@ -127,7 +127,7 @@
 
 void BackgroundFetchRequestInfo::PopulateWithResponse(
     std::unique_ptr<BackgroundFetchResponse> response) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(response);
 
   url_chain_ = response->url_chain;
diff --git a/content/browser/background_fetch/background_fetch_scheduler.cc b/content/browser/background_fetch/background_fetch_scheduler.cc
index c1137cea..905427f 100644
--- a/content/browser/background_fetch/background_fetch_scheduler.cc
+++ b/content/browser/background_fetch/background_fetch_scheduler.cc
@@ -284,7 +284,7 @@
 
 void BackgroundFetchScheduler::CleanupRegistration(
     const BackgroundFetchRegistrationId& registration_id) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Indicate to the renderer that the records for this fetch are no longer
   // available.
   registration_notifier_->NotifyRecordsUnavailable(registration_id.unique_id());
@@ -359,7 +359,7 @@
     const SkBitmap& icon,
     int num_requests,
     bool start_paused) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   LogBackgroundFetchEventForDevTools(
       Event::kFetchRegistered, registration_id,
@@ -395,7 +395,7 @@
     int num_requests,
     std::vector<scoped_refptr<BackgroundFetchRequestInfo>>
         active_fetch_requests) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   LogBackgroundFetchEventForDevTools(
       Event::kFetchResumedOnStartup, registration_id,
@@ -494,12 +494,12 @@
     int64_t registration_id,
     const GURL& pattern,
     const blink::StorageKey& key) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   AbortFetches(registration_id);
 }
 
 void BackgroundFetchScheduler::OnStorageWiped() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   AbortFetches(blink::mojom::kInvalidServiceWorkerRegistrationId);
 }
 
diff --git a/content/browser/background_fetch/storage/database_task.cc b/content/browser/background_fetch/storage/database_task.cc
index a69128f..c947bf6 100644
--- a/content/browser/background_fetch/storage/database_task.cc
+++ b/content/browser/background_fetch/storage/database_task.cc
@@ -52,7 +52,7 @@
 }
 
 void DatabaseTask::Finished() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Post the OnTaskFinished callback to the same thread, to allow the the
   // DatabaseTask to finish execution before deallocating it.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/content/browser/background_sync/DIR_METADATA b/content/browser/background_sync/DIR_METADATA
index 6bafd754..8a6d80f 100644
--- a/content/browser/background_sync/DIR_METADATA
+++ b/content/browser/background_sync/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>BackgroundSync"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//components/background_sync/COMMON_METADATA"
diff --git a/content/browser/background_sync/background_sync_registration_helper.cc b/content/browser/background_sync/background_sync_registration_helper.cc
index 654aea9..e3738dbd 100644
--- a/content/browser/background_sync/background_sync_registration_helper.cc
+++ b/content/browser/background_sync/background_sync_registration_helper.cc
@@ -25,7 +25,7 @@
 bool BackgroundSyncRegistrationHelper::ValidateSWRegistrationID(
     int64_t sw_registration_id,
     const url::Origin& origin) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   BackgroundSyncManager* background_sync_manager =
       background_sync_context_->background_sync_manager();
@@ -42,7 +42,7 @@
     blink::mojom::SyncRegistrationOptionsPtr options,
     int64_t sw_registration_id,
     RegisterCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   BackgroundSyncManager* background_sync_manager =
       background_sync_context_->background_sync_manager();
@@ -56,7 +56,7 @@
 
 void BackgroundSyncRegistrationHelper::DidResolveRegistration(
     blink::mojom::BackgroundSyncRegistrationInfoPtr registration_info) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   BackgroundSyncManager* background_sync_manager =
       background_sync_context_->background_sync_manager();
@@ -69,7 +69,7 @@
     RegisterCallback callback,
     BackgroundSyncStatus status,
     std::unique_ptr<BackgroundSyncRegistration> result) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/932591): Use blink::mojom::BackgroundSyncError
   // directly.
@@ -99,7 +99,7 @@
     BackgroundSyncStatus status,
     std::vector<std::unique_ptr<BackgroundSyncRegistration>>
         result_registrations) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   std::vector<blink::mojom::SyncRegistrationOptionsPtr> mojo_registrations;
   mojo_registrations.reserve(result_registrations.size());
diff --git a/content/browser/background_sync/one_shot_background_sync_service_impl.cc b/content/browser/background_sync/one_shot_background_sync_service_impl.cc
index fb23403..88bcbad 100644
--- a/content/browser/background_sync/one_shot_background_sync_service_impl.cc
+++ b/content/browser/background_sync/one_shot_background_sync_service_impl.cc
@@ -21,7 +21,7 @@
     : background_sync_context_(background_sync_context),
       origin_(origin),
       receiver_(this, std::move(receiver)) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(background_sync_context_);
 
   registration_helper_ = std::make_unique<BackgroundSyncRegistrationHelper>(
@@ -33,7 +33,7 @@
 }
 
 OneShotBackgroundSyncServiceImpl::~OneShotBackgroundSyncServiceImpl() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void OneShotBackgroundSyncServiceImpl::OnMojoDisconnect() {
@@ -45,7 +45,7 @@
     blink::mojom::SyncRegistrationOptionsPtr options,
     int64_t sw_registration_id,
     RegisterCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(options);
 
   if (options->min_interval != -1) {
@@ -66,7 +66,7 @@
 
 void OneShotBackgroundSyncServiceImpl::DidResolveRegistration(
     blink::mojom::BackgroundSyncRegistrationInfoPtr registration_info) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   registration_helper_->DidResolveRegistration(std::move(registration_info));
 }
@@ -74,7 +74,7 @@
 void OneShotBackgroundSyncServiceImpl::GetRegistrations(
     int64_t sw_registration_id,
     GetRegistrationsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (!registration_helper_->ValidateSWRegistrationID(sw_registration_id,
                                                       origin_)) {
diff --git a/content/browser/background_sync/periodic_background_sync_service_impl.cc b/content/browser/background_sync/periodic_background_sync_service_impl.cc
index 2a619d569..64f48c7 100644
--- a/content/browser/background_sync/periodic_background_sync_service_impl.cc
+++ b/content/browser/background_sync/periodic_background_sync_service_impl.cc
@@ -21,7 +21,7 @@
     : background_sync_context_(background_sync_context),
       origin_(origin),
       receiver_(this, std::move(receiver)) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(background_sync_context_);
 
   registration_helper_ = std::make_unique<BackgroundSyncRegistrationHelper>(
@@ -34,7 +34,7 @@
 }
 
 PeriodicBackgroundSyncServiceImpl::~PeriodicBackgroundSyncServiceImpl() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void PeriodicBackgroundSyncServiceImpl::OnMojoDisconnect() {
@@ -46,7 +46,7 @@
     blink::mojom::SyncRegistrationOptionsPtr options,
     int64_t sw_registration_id,
     RegisterCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(options);
 
   if (options->min_interval < 0) {
@@ -69,7 +69,7 @@
     int64_t sw_registration_id,
     const std::string& tag,
     UnregisterCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (!registration_helper_->ValidateSWRegistrationID(sw_registration_id,
                                                       origin_)) {
@@ -89,7 +89,7 @@
 void PeriodicBackgroundSyncServiceImpl::GetRegistrations(
     int64_t sw_registration_id,
     GetRegistrationsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (!registration_helper_->ValidateSWRegistrationID(sw_registration_id,
                                                       origin_)) {
@@ -115,7 +115,7 @@
 void PeriodicBackgroundSyncServiceImpl::OnUnregisterResult(
     UnregisterCallback callback,
     BackgroundSyncStatus status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   std::move(callback).Run(
       static_cast<blink::mojom::BackgroundSyncError>(status));
diff --git a/content/browser/bluetooth/COMMON_METADATA b/content/browser/bluetooth/COMMON_METADATA
new file mode 100644
index 0000000..488eb98
--- /dev/null
+++ b/content/browser/bluetooth/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Bluetooth"
+}
+team_email: "web-bluetooth@chromium.org"
diff --git a/content/browser/bluetooth/DIR_METADATA b/content/browser/bluetooth/DIR_METADATA
index 488eb98..cd51015 100644
--- a/content/browser/bluetooth/DIR_METADATA
+++ b/content/browser/bluetooth/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Bluetooth"
-}
-team_email: "web-bluetooth@chromium.org"
+mixins: "//content/browser/bluetooth/COMMON_METADATA"
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index e35fa843..30072444 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -1236,13 +1236,13 @@
 
 // Service workers
 ServiceWorkerVersionInfo GetContextForHost(ServiceWorkerHost* host) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return host->version()->GetInfo();
 }
 
 void PopulateServiceWorkerBinders(ServiceWorkerHost* host,
                                   mojo::BinderMap* map) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Do nothing for interfaces that the renderer might request, but doesn't
   // always expect to be bound.
@@ -1288,7 +1288,7 @@
 void PopulateBinderMapWithContext(
     ServiceWorkerHost* host,
     mojo::BinderMapWithContext<const ServiceWorkerVersionBaseInfo&>* map) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // static binders
   // Use a task runner if ServiceWorkerHost lives on the IO thread, as
@@ -1348,7 +1348,7 @@
 }
 
 void PopulateBinderMap(ServiceWorkerHost* host, mojo::BinderMap* map) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   PopulateServiceWorkerBinders(host, map);
 }
 
diff --git a/content/browser/browsing_data/COMMON_METADATA b/content/browser/browsing_data/COMMON_METADATA
new file mode 100644
index 0000000..db7a5c4a
--- /dev/null
+++ b/content/browser/browsing_data/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Privacy"
+}
diff --git a/content/browser/browsing_data/DIR_METADATA b/content/browser/browsing_data/DIR_METADATA
index db7a5c4a..ce654ba 100644
--- a/content/browser/browsing_data/DIR_METADATA
+++ b/content/browser/browsing_data/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Privacy"
-}
+mixins: "//content/browser/browsing_data/COMMON_METADATA"
diff --git a/content/browser/buckets/COMMON_METADATA b/content/browser/buckets/COMMON_METADATA
new file mode 100644
index 0000000..804eab5
--- /dev/null
+++ b/content/browser/buckets/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>Buckets"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/buckets/DIR_METADATA b/content/browser/buckets/DIR_METADATA
index 8baa213..45dedecf8 100644
--- a/content/browser/buckets/DIR_METADATA
+++ b/content/browser/buckets/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Blink>Storage>Buckets"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/buckets/COMMON_METADATA"
diff --git a/content/browser/cache_storage/COMMON_METADATA b/content/browser/cache_storage/COMMON_METADATA
new file mode 100644
index 0000000..f478d0c
--- /dev/null
+++ b/content/browser/cache_storage/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>CacheStorage"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/cache_storage/DIR_METADATA b/content/browser/cache_storage/DIR_METADATA
index f478d0c..306fb835 100644
--- a/content/browser/cache_storage/DIR_METADATA
+++ b/content/browser/cache_storage/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>CacheStorage"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/cache_storage/COMMON_METADATA"
diff --git a/content/browser/client_hints/DIR_METADATA b/content/browser/client_hints/DIR_METADATA
new file mode 100644
index 0000000..7c929fe
--- /dev/null
+++ b/content/browser/client_hints/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/client_hints/COMMON_METADATA"
diff --git a/content/browser/compute_pressure/COMMON_METADATA b/content/browser/compute_pressure/COMMON_METADATA
new file mode 100644
index 0000000..2a4156e
--- /dev/null
+++ b/content/browser/compute_pressure/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>PerformanceAPIs>ComputePressure"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/compute_pressure/DIR_METADATA b/content/browser/compute_pressure/DIR_METADATA
index 2a4156e..d2b9158 100644
--- a/content/browser/compute_pressure/DIR_METADATA
+++ b/content/browser/compute_pressure/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>PerformanceAPIs>ComputePressure"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/compute_pressure/COMMON_METADATA"
diff --git a/content/browser/content_index/COMMON_METADATA b/content/browser/content_index/COMMON_METADATA
new file mode 100644
index 0000000..e3d7339
--- /dev/null
+++ b/content/browser/content_index/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>ContentIndexing"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/content/browser/content_index/DIR_METADATA b/content/browser/content_index/DIR_METADATA
index e3d7339..14ec9603 100644
--- a/content/browser/content_index/DIR_METADATA
+++ b/content/browser/content_index/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>ContentIndexing"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//content/browser/content_index/COMMON_METADATA"
diff --git a/content/browser/cookie_store/COMMON_METADATA b/content/browser/cookie_store/COMMON_METADATA
new file mode 100644
index 0000000..879dc01
--- /dev/null
+++ b/content/browser/cookie_store/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>CookiesAPI"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/cookie_store/DIR_METADATA b/content/browser/cookie_store/DIR_METADATA
index 879dc01..fe26091 100644
--- a/content/browser/cookie_store/DIR_METADATA
+++ b/content/browser/cookie_store/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>CookiesAPI"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/cookie_store/COMMON_METADATA"
diff --git a/content/browser/device/DIR_METADATA b/content/browser/device/DIR_METADATA
new file mode 100644
index 0000000..6feb9e41a
--- /dev/null
+++ b/content/browser/device/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//services/device/COMMON_METADATA"
diff --git a/content/browser/direct_sockets/DIR_METADATA b/content/browser/direct_sockets/DIR_METADATA
new file mode 100644
index 0000000..07b80730
--- /dev/null
+++ b/content/browser/direct_sockets/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/direct_sockets/COMMON_METADATA"
diff --git a/content/browser/display_cutout/DIR_METADATA b/content/browser/display_cutout/DIR_METADATA
index e695066..02bfc63 100644
--- a/content/browser/display_cutout/DIR_METADATA
+++ b/content/browser/display_cutout/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>Layout"
-}
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/display_cutout/COMMON_METADATA"
 team_email: "media-dev@chromium.org"
diff --git a/content/browser/dom_storage/COMMON_METADATA b/content/browser/dom_storage/COMMON_METADATA
new file mode 100644
index 0000000..3d578da
--- /dev/null
+++ b/content/browser/dom_storage/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>DOMStorage"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/dom_storage/DIR_METADATA b/content/browser/dom_storage/DIR_METADATA
index 3d578da..99f4a77 100644
--- a/content/browser/dom_storage/DIR_METADATA
+++ b/content/browser/dom_storage/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>DOMStorage"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/dom_storage/COMMON_METADATA"
diff --git a/content/browser/federated_learning/DIR_METADATA b/content/browser/federated_learning/DIR_METADATA
new file mode 100644
index 0000000..ea6a8e2
--- /dev/null
+++ b/content/browser/federated_learning/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/federated_learning/COMMON_METADATA"
diff --git a/content/browser/file_system_access/COMMON_METADATA b/content/browser/file_system_access/COMMON_METADATA
new file mode 100644
index 0000000..0f09247
--- /dev/null
+++ b/content/browser/file_system_access/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>FileSystem"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/file_system_access/DIR_METADATA b/content/browser/file_system_access/DIR_METADATA
index 0f09247..29ed859f 100644
--- a/content/browser/file_system_access/DIR_METADATA
+++ b/content/browser/file_system_access/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>FileSystem"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/file_system_access/COMMON_METADATA"
diff --git a/content/browser/font_access/COMMON_METADATA b/content/browser/font_access/COMMON_METADATA
new file mode 100644
index 0000000..95ccf36
--- /dev/null
+++ b/content/browser/font_access/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>FontAccess"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/font_access/DIR_METADATA b/content/browser/font_access/DIR_METADATA
index 95ccf36..be579e99 100644
--- a/content/browser/font_access/DIR_METADATA
+++ b/content/browser/font_access/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>FontAccess"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/font_access/COMMON_METADATA"
diff --git a/content/browser/generic_sensor/DIR_METADATA b/content/browser/generic_sensor/DIR_METADATA
index fc620d5..af72c12 100644
--- a/content/browser/generic_sensor/DIR_METADATA
+++ b/content/browser/generic_sensor/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>Sensor"
-}
+mixins: "//services/device/generic_sensor/COMMON_METADATA"
 team_email: "device-dev@chromium.org"
diff --git a/content/browser/hid/DIR_METADATA b/content/browser/hid/DIR_METADATA
index 5ef1de28..9260825 100644
--- a/content/browser/hid/DIR_METADATA
+++ b/content/browser/hid/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>HID"
-}
-team_email: "device-dev@chromium.org"
+mixins: "//third_party/blink/renderer/modules/hid/COMMON_METADATA"
diff --git a/content/browser/idle/COMMON_METADATA b/content/browser/idle/COMMON_METADATA
new file mode 100644
index 0000000..4245efd
--- /dev/null
+++ b/content/browser/idle/COMMON_METADATA
@@ -0,0 +1 @@
+team_email: "fugu-dev@chromium.org"
diff --git a/content/browser/idle/DIR_METADATA b/content/browser/idle/DIR_METADATA
index 4245efd..7b9dd684 100644
--- a/content/browser/idle/DIR_METADATA
+++ b/content/browser/idle/DIR_METADATA
@@ -1 +1 @@
-team_email: "fugu-dev@chromium.org"
+mixins: "//content/browser/idle/COMMON_METADATA"
diff --git a/content/browser/indexed_db/COMMON_METADATA b/content/browser/indexed_db/COMMON_METADATA
new file mode 100644
index 0000000..f8d1ed1
--- /dev/null
+++ b/content/browser/indexed_db/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>IndexedDB"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/indexed_db/DIR_METADATA b/content/browser/indexed_db/DIR_METADATA
index f8d1ed1..dedeb35 100644
--- a/content/browser/indexed_db/DIR_METADATA
+++ b/content/browser/indexed_db/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>IndexedDB"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/indexed_db/COMMON_METADATA"
diff --git a/content/browser/interest_group/COMMON_METADATA b/content/browser/interest_group/COMMON_METADATA
new file mode 100644
index 0000000..5313345b
--- /dev/null
+++ b/content/browser/interest_group/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>InterestGroups"
+}
diff --git a/content/browser/interest_group/DIR_METADATA b/content/browser/interest_group/DIR_METADATA
index 5313345b..228e057 100644
--- a/content/browser/interest_group/DIR_METADATA
+++ b/content/browser/interest_group/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>InterestGroups"
-}
+mixins: "//content/browser/interest_group/COMMON_METADATA"
diff --git a/content/browser/loader/COMMON_METADATA b/content/browser/loader/COMMON_METADATA
new file mode 100644
index 0000000..7018e6c
--- /dev/null
+++ b/content/browser/loader/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Network"
+}
+team_email: "net-dev@chromium.org"
diff --git a/content/browser/loader/DIR_METADATA b/content/browser/loader/DIR_METADATA
index 7018e6c..b4c30ac 100644
--- a/content/browser/loader/DIR_METADATA
+++ b/content/browser/loader/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Network"
-}
-team_email: "net-dev@chromium.org"
+mixins: "//content/browser/loader/COMMON_METADATA"
diff --git a/content/browser/locks/COMMON_METADATA b/content/browser/locks/COMMON_METADATA
new file mode 100644
index 0000000..cc6fcfa
--- /dev/null
+++ b/content/browser/locks/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/locks/DIR_METADATA b/content/browser/locks/DIR_METADATA
index cc6fcfa..7716613 100644
--- a/content/browser/locks/DIR_METADATA
+++ b/content/browser/locks/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/locks/COMMON_METADATA"
diff --git a/content/browser/manifest/DIR_METADATA b/content/browser/manifest/DIR_METADATA
index 0ff3ed55..78b240e 100644
--- a/content/browser/manifest/DIR_METADATA
+++ b/content/browser/manifest/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>AppManifest"
-}
+mixins: "//third_party/blink/renderer/modules/manifest/COMMON_METADATA"
diff --git a/content/browser/media/DIR_METADATA b/content/browser/media/DIR_METADATA
index 6667e7f..41e8f64 100644
--- a/content/browser/media/DIR_METADATA
+++ b/content/browser/media/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Media"
-}
+mixins: "//media/COMMON_METADATA"
diff --git a/content/browser/media_session/DIR_METADATA b/content/browser/media_session/DIR_METADATA
new file mode 100644
index 0000000..da1d684
--- /dev/null
+++ b/content/browser/media_session/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//services/media_session/COMMON_METADATA"
diff --git a/content/browser/metrics/DIR_METADATA b/content/browser/metrics/DIR_METADATA
new file mode 100644
index 0000000..e99cb759
--- /dev/null
+++ b/content/browser/metrics/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//base/metrics/COMMON_METADATA"
diff --git a/content/browser/native_io/COMMON_METADATA b/content/browser/native_io/COMMON_METADATA
new file mode 100644
index 0000000..24c5f5a0
--- /dev/null
+++ b/content/browser/native_io/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>NativeIO"
+}
+team_email: "storage-dev@chromium.org"
diff --git a/content/browser/native_io/DIR_METADATA b/content/browser/native_io/DIR_METADATA
index 24c5f5a0..9873cbb 100644
--- a/content/browser/native_io/DIR_METADATA
+++ b/content/browser/native_io/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>NativeIO"
-}
-team_email: "storage-dev@chromium.org"
+mixins: "//content/browser/native_io/COMMON_METADATA"
diff --git a/content/browser/net/DIR_METADATA b/content/browser/net/DIR_METADATA
new file mode 100644
index 0000000..09f5b5e
--- /dev/null
+++ b/content/browser/net/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//net/COMMON_METADATA"
diff --git a/content/browser/notifications/COMMON_METADATA b/content/browser/notifications/COMMON_METADATA
new file mode 100644
index 0000000..a90e42f
--- /dev/null
+++ b/content/browser/notifications/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Notifications"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/content/browser/notifications/DIR_METADATA b/content/browser/notifications/DIR_METADATA
index a90e42f..e56c832 100644
--- a/content/browser/notifications/DIR_METADATA
+++ b/content/browser/notifications/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Notifications"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//content/browser/notifications/COMMON_METADATA"
diff --git a/content/browser/notifications/notification_storage.cc b/content/browser/notifications/notification_storage.cc
index d0cbf7cc..342331b 100644
--- a/content/browser/notifications/notification_storage.cc
+++ b/content/browser/notifications/notification_storage.cc
@@ -48,7 +48,7 @@
 void NotificationStorage::WriteNotificationData(
     const NotificationDatabaseData& data,
     PlatformNotificationContext::WriteResultCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   std::string serialized_data;
   if (!SerializeNotificationDatabaseData(data, &serialized_data)) {
     DLOG(ERROR) << "Unable to serialize data for a notification belonging "
@@ -85,7 +85,7 @@
     const std::string& notification_id,
     PlatformNotificationContext::Interaction interaction,
     PlatformNotificationContext::ReadResultCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   service_worker_context_->GetRegistrationUserData(
       service_worker_registration_id, {CreateDataKey(notification_id)},
       base::BindOnce(&NotificationStorage::OnReadCompleteUpdateInteraction,
diff --git a/content/browser/origin_trials/DIR_METADATA b/content/browser/origin_trials/DIR_METADATA
new file mode 100644
index 0000000..14641a38
--- /dev/null
+++ b/content/browser/origin_trials/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/common/origin_trials/COMMON_METADATA"
diff --git a/content/browser/payments/DIR_METADATA b/content/browser/payments/DIR_METADATA
new file mode 100644
index 0000000..9dddbb4
--- /dev/null
+++ b/content/browser/payments/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/payments/COMMON_METADATA"
diff --git a/content/browser/payments/payment_app_database.cc b/content/browser/payments/payment_app_database.cc
index b13aff9..ea29d0c 100644
--- a/content/browser/payments/payment_app_database.cc
+++ b/content/browser/payments/payment_app_database.cc
@@ -153,16 +153,16 @@
 PaymentAppDatabase::PaymentAppDatabase(
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context)
     : service_worker_context_(service_worker_context) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 PaymentAppDatabase::~PaymentAppDatabase() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void PaymentAppDatabase::ReadAllPaymentApps(
     ReadAllPaymentAppsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   service_worker_context_->GetUserDataForAllRegistrationsByKeyPrefix(
       kPaymentAppPrefix,
@@ -174,7 +174,7 @@
     const GURL& scope,
     const std::string& instrument_key,
     DeletePaymentInstrumentCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/1199077): Update this when PaymentManager
   // implements StorageKey.
@@ -189,7 +189,7 @@
     const GURL& scope,
     const std::string& instrument_key,
     ReadPaymentInstrumentCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/1199077): Update this when PaymentManager
   // implements StorageKey.
@@ -203,7 +203,7 @@
 void PaymentAppDatabase::KeysOfPaymentInstruments(
     const GURL& scope,
     KeysOfPaymentInstrumentsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/1199077): Update this when PaymentManager
   // implements StorageKey.
@@ -217,7 +217,7 @@
     const GURL& scope,
     const std::string& instrument_key,
     HasPaymentInstrumentCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/1199077): Update this when PaymentManager
   // implements StorageKey.
@@ -233,7 +233,7 @@
     const std::string& instrument_key,
     PaymentInstrumentPtr instrument,
     WritePaymentInstrumentCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/1199077): Update this when PaymentManager
   // implements StorageKey.
@@ -263,7 +263,7 @@
     payments::mojom::PaymentInstrumentPtr instrument,
     WritePaymentInstrumentCallback callback,
     const std::string& icon) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (icon.empty()) {
     std::move(callback).Run(PaymentHandlerStatus::FETCH_INSTRUMENT_ICON_FAILED);
@@ -284,7 +284,7 @@
     const GURL& context,
     const GURL& scope,
     FetchAndUpdatePaymentAppInfoCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   PaymentAppInfoFetcher::Start(
       context, service_worker_context_,
@@ -297,7 +297,7 @@
     const GURL& scope,
     FetchAndUpdatePaymentAppInfoCallback callback,
     std::unique_ptr<PaymentAppInfoFetcher::PaymentAppInfo> app_info) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/1199077): Update this when PaymentManager
   // implements StorageKey.
@@ -314,7 +314,7 @@
     std::unique_ptr<PaymentAppInfoFetcher::PaymentAppInfo> app_info,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER);
     return;
@@ -334,7 +334,7 @@
     scoped_refptr<ServiceWorkerRegistration> registration,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER);
     return;
@@ -380,7 +380,7 @@
     FetchAndUpdatePaymentAppInfoCallback callback,
     bool fetch_app_info_failed,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   PaymentHandlerStatus handler_status =
       fetch_app_info_failed
@@ -395,7 +395,7 @@
 void PaymentAppDatabase::ClearPaymentInstruments(
     const GURL& scope,
     ClearPaymentInstrumentsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/1199077): Update this when PaymentManager
   // implements StorageKey.
@@ -408,7 +408,7 @@
 
 void PaymentAppDatabase::SetPaymentAppUserHint(const GURL& scope,
                                                const std::string& user_hint) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/1199077): Update this when PaymentManager
   // implements StorageKey.
@@ -423,7 +423,7 @@
     const GURL& scope,
     const std::vector<PaymentDelegation>& delegations,
     EnableDelegationsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // TODO(crbug.com/1199077): Update this when PaymentManager
   // implements StorageKey.
@@ -439,7 +439,7 @@
     EnableDelegationsCallback callback,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER);
     return;
@@ -464,7 +464,7 @@
     scoped_refptr<ServiceWorkerRegistration> registration,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::NOT_FOUND);
     return;
@@ -512,7 +512,7 @@
 void PaymentAppDatabase::DidEnablePaymentAppDelegations(
     EnableDelegationsCallback callback,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return std::move(callback).Run(
       status == blink::ServiceWorkerStatusCode::kOk
           ? PaymentHandlerStatus::SUCCESS
@@ -523,7 +523,7 @@
     const std::string& user_hint,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk)
     return;
 
@@ -544,7 +544,7 @@
     scoped_refptr<ServiceWorkerRegistration> registration,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk)
     return;
 
@@ -569,7 +569,7 @@
 
 void PaymentAppDatabase::DidSetPaymentAppUserHint(
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(status == blink::ServiceWorkerStatusCode::kOk);
 }
 
@@ -581,7 +581,7 @@
     const std::string& method,
     const SupportedDelegations& supported_delegations,
     SetPaymentAppInfoCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   service_worker_context_->FindReadyRegistrationForIdOnly(
       registration_id,
@@ -599,7 +599,7 @@
     SetPaymentAppInfoCallback callback,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER);
@@ -650,7 +650,7 @@
     SetPaymentAppInfoCallback callback,
     scoped_refptr<ServiceWorkerRegistration> registration,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::STORAGE_OPERATION_FAILED);
@@ -687,7 +687,7 @@
 void PaymentAppDatabase::DidWritePaymentInstrumentForSetPaymentApp(
     SetPaymentAppInfoCallback callback,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return std::move(callback).Run(
       status == blink::ServiceWorkerStatusCode::kOk
           ? PaymentHandlerStatus::SUCCESS
@@ -698,7 +698,7 @@
     ReadAllPaymentAppsCallback callback,
     const std::vector<std::pair<int64_t, std::string>>& raw_data,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentApps());
     return;
@@ -729,7 +729,7 @@
     ReadAllPaymentAppsCallback callback,
     const std::vector<std::pair<int64_t, std::string>>& raw_data,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(std::move(apps));
     return;
@@ -762,7 +762,7 @@
     DeletePaymentInstrumentCallback callback,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER);
     return;
@@ -781,7 +781,7 @@
     DeletePaymentInstrumentCallback callback,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk || data.size() != 1) {
     std::move(callback).Run(PaymentHandlerStatus::NOT_FOUND);
     return;
@@ -798,7 +798,7 @@
 void PaymentAppDatabase::DidDeletePaymentInstrument(
     DeletePaymentInstrumentCallback callback,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return std::move(callback).Run(status == blink::ServiceWorkerStatusCode::kOk
                                      ? PaymentHandlerStatus::SUCCESS
                                      : PaymentHandlerStatus::NOT_FOUND);
@@ -809,7 +809,7 @@
     ReadPaymentInstrumentCallback callback,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentInstrument::New(),
                             PaymentHandlerStatus::NO_ACTIVE_WORKER);
@@ -826,7 +826,7 @@
     ReadPaymentInstrumentCallback callback,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk || data.size() != 1) {
     std::move(callback).Run(PaymentInstrument::New(),
                             PaymentHandlerStatus::NOT_FOUND);
@@ -847,7 +847,7 @@
     KeysOfPaymentInstrumentsCallback callback,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(std::vector<std::string>(),
                             PaymentHandlerStatus::NO_ACTIVE_WORKER);
@@ -864,7 +864,7 @@
     KeysOfPaymentInstrumentsCallback callback,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(std::vector<std::string>(),
                             PaymentHandlerStatus::NOT_FOUND);
@@ -884,7 +884,7 @@
     HasPaymentInstrumentCallback callback,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER);
     return;
@@ -900,7 +900,7 @@
     DeletePaymentInstrumentCallback callback,
     const std::vector<std::string>& data,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk || data.size() != 1) {
     std::move(callback).Run(PaymentHandlerStatus::NOT_FOUND);
     return;
@@ -916,7 +916,7 @@
     WritePaymentInstrumentCallback callback,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER);
     return;
@@ -972,7 +972,7 @@
 void PaymentAppDatabase::DidWritePaymentInstrument(
     WritePaymentInstrumentCallback callback,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return std::move(callback).Run(
       status == blink::ServiceWorkerStatusCode::kOk
           ? PaymentHandlerStatus::SUCCESS
@@ -984,7 +984,7 @@
     ClearPaymentInstrumentsCallback callback,
     blink::ServiceWorkerStatusCode status,
     scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     std::move(callback).Run(PaymentHandlerStatus::NO_ACTIVE_WORKER);
@@ -1003,7 +1003,7 @@
     ClearPaymentInstrumentsCallback callback,
     const std::vector<std::string>& keys,
     PaymentHandlerStatus status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (status != PaymentHandlerStatus::SUCCESS) {
     std::move(callback).Run(PaymentHandlerStatus::NOT_FOUND);
@@ -1028,7 +1028,7 @@
 void PaymentAppDatabase::DidClearPaymentInstruments(
     ClearPaymentInstrumentsCallback callback,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return std::move(callback).Run(status == blink::ServiceWorkerStatusCode::kOk
                                      ? PaymentHandlerStatus::SUCCESS
                                      : PaymentHandlerStatus::NOT_FOUND);
diff --git a/content/browser/payments/payment_manager.cc b/content/browser/payments/payment_manager.cc
index 9a341d52..ddd2cef 100644
--- a/content/browser/payments/payment_manager.cc
+++ b/content/browser/payments/payment_manager.cc
@@ -26,7 +26,7 @@
     : payment_app_context_(payment_app_context),
       origin_(origin),
       receiver_(this, std::move(receiver)) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(payment_app_context);
 
   receiver_.set_disconnect_handler(base::BindOnce(
@@ -34,11 +34,11 @@
 }
 
 PaymentManager::~PaymentManager() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 void PaymentManager::Init(const GURL& context_url, const std::string& scope) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   enum class ReasonCode : uint32_t {
     kInvalidContextUrl,
@@ -90,7 +90,7 @@
 void PaymentManager::DeletePaymentInstrument(
     const std::string& instrument_key,
     PaymentManager::DeletePaymentInstrumentCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   payment_app_context_->payment_app_database()->DeletePaymentInstrument(
       scope_, instrument_key, std::move(callback));
@@ -99,7 +99,7 @@
 void PaymentManager::GetPaymentInstrument(
     const std::string& instrument_key,
     PaymentManager::GetPaymentInstrumentCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   payment_app_context_->payment_app_database()->ReadPaymentInstrument(
       scope_, instrument_key, std::move(callback));
@@ -107,7 +107,7 @@
 
 void PaymentManager::KeysOfPaymentInstruments(
     PaymentManager::KeysOfPaymentInstrumentsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   payment_app_context_->payment_app_database()->KeysOfPaymentInstruments(
       scope_, std::move(callback));
@@ -116,7 +116,7 @@
 void PaymentManager::HasPaymentInstrument(
     const std::string& instrument_key,
     PaymentManager::HasPaymentInstrumentCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   payment_app_context_->payment_app_database()->HasPaymentInstrument(
       scope_, instrument_key, std::move(callback));
@@ -126,7 +126,7 @@
     const std::string& instrument_key,
     payments::mojom::PaymentInstrumentPtr details,
     PaymentManager::SetPaymentInstrumentCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (should_set_payment_app_info_) {
     payment_app_context_->payment_app_database()->WritePaymentInstrument(
@@ -143,7 +143,7 @@
 void PaymentManager::SetPaymentInstrumentIntermediateCallback(
     PaymentManager::SetPaymentInstrumentCallback callback,
     payments::mojom::PaymentHandlerStatus status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (status != payments::mojom::PaymentHandlerStatus::SUCCESS ||
       !should_set_payment_app_info_) {
@@ -158,7 +158,7 @@
 
 void PaymentManager::ClearPaymentInstruments(
     ClearPaymentInstrumentsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   payment_app_context_->payment_app_database()->ClearPaymentInstruments(
       scope_, std::move(callback));
@@ -172,14 +172,14 @@
 void PaymentManager::EnableDelegations(
     const std::vector<payments::mojom::PaymentDelegation>& delegations,
     PaymentManager::EnableDelegationsCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   payment_app_context_->payment_app_database()->EnablePaymentAppDelegations(
       scope_, delegations, std::move(callback));
 }
 
 void PaymentManager::OnConnectionError() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   payment_app_context_->PaymentManagerHadConnectionError(this);
 }
 
diff --git a/content/browser/picture_in_picture/DIR_METADATA b/content/browser/picture_in_picture/DIR_METADATA
index 1d92eaa1..4fde477 100644
--- a/content/browser/picture_in_picture/DIR_METADATA
+++ b/content/browser/picture_in_picture/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//third_party/blink/renderer/modules/picture_in_picture/COMMON_METADATA"
 monorail {
   component: "Internals>Media>UI"
 }
-team_email: "media-dev@chromium.org"
diff --git a/content/browser/portal/DIR_METADATA b/content/browser/portal/DIR_METADATA
index 1e4fe50..842d7f2 100644
--- a/content/browser/portal/DIR_METADATA
+++ b/content/browser/portal/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Portals"
-}
+mixins: "//third_party/blink/renderer/core/html/portal/COMMON_METADATA"
diff --git a/content/browser/prerender/COMMON_METADATA b/content/browser/prerender/COMMON_METADATA
new file mode 100644
index 0000000..ee8fe89
--- /dev/null
+++ b/content/browser/prerender/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Preload>Prerender"
+}
+team_email: "loading-dev@chromium.org"
diff --git a/content/browser/prerender/DIR_METADATA b/content/browser/prerender/DIR_METADATA
index ee8fe89..1881f70 100644
--- a/content/browser/prerender/DIR_METADATA
+++ b/content/browser/prerender/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Preload>Prerender"
-}
-team_email: "loading-dev@chromium.org"
+mixins: "//content/browser/prerender/COMMON_METADATA"
diff --git a/content/browser/push_messaging/COMMON_METADATA b/content/browser/push_messaging/COMMON_METADATA
new file mode 100644
index 0000000..b193ae0
--- /dev/null
+++ b/content/browser/push_messaging/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>PushAPI"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/content/browser/push_messaging/DIR_METADATA b/content/browser/push_messaging/DIR_METADATA
index b193ae0..a684b81 100644
--- a/content/browser/push_messaging/DIR_METADATA
+++ b/content/browser/push_messaging/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>PushAPI"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//content/browser/push_messaging/COMMON_METADATA"
diff --git a/content/browser/push_messaging/push_messaging_router.cc b/content/browser/push_messaging/push_messaging_router.cc
index 663861cb..4c8a249 100644
--- a/content/browser/push_messaging/push_messaging_router.cc
+++ b/content/browser/push_messaging/push_messaging_router.cc
@@ -34,7 +34,7 @@
 void RunPushEventCallback(
     PushMessagingRouter::PushEventCallback deliver_message_callback,
     blink::mojom::PushEventStatus push_event_status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // PostTask() to ensure the callback is called asynchronously.
   GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE,
@@ -50,7 +50,7 @@
     ServiceWorkerStartCallback callback,
     blink::ServiceWorkerStatusCode service_worker_status,
     scoped_refptr<ServiceWorkerRegistration> service_worker_registration) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (event_type == ServiceWorkerMetrics::EventType::PUSH) {
     UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus.FindServiceWorker",
@@ -80,7 +80,7 @@
     const url::Origin& origin,
     int64_t service_worker_registration_id,
     ServiceWorkerStartCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Try to acquire the registration from storage. If it's already live we'll
   // receive it right away. If not, it will be revived from storage.
   service_worker_context->FindReadyRegistrationForId(
@@ -140,7 +140,7 @@
     scoped_refptr<ServiceWorkerVersion> service_worker,
     scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Service worker registration was not found, run callback immediately
   if (!service_worker) {
     DCHECK_NE(blink::ServiceWorkerStatusCode::kOk, status);
@@ -190,7 +190,7 @@
     const std::string& message_id,
     PushEventCallback deliver_message_callback,
     blink::ServiceWorkerStatusCode service_worker_status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus.ServiceWorkerEvent",
                             service_worker_status);
   blink::mojom::PushEventStatus push_event_status =
@@ -276,7 +276,7 @@
     scoped_refptr<ServiceWorkerVersion> service_worker,
     scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context,
     blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(base::FeatureList::IsEnabled(features::kPushSubscriptionChangeEvent));
 
   if (!service_worker) {
@@ -313,7 +313,7 @@
     scoped_refptr<ServiceWorkerVersion> service_worker,
     PushEventCallback subscription_change_callback,
     blink::ServiceWorkerStatusCode service_worker_status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   blink::mojom::PushEventStatus push_event_status =
       blink::mojom::PushEventStatus::SERVICE_WORKER_ERROR;
   switch (service_worker_status) {
diff --git a/content/browser/quota/DIR_METADATA b/content/browser/quota/DIR_METADATA
index 4bba49e..431433c 100644
--- a/content/browser/quota/DIR_METADATA
+++ b/content/browser/quota/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>Storage>Quota"
-}
+mixins: "//storage/browser/quota/COMMON_METADATA"
 team_email: "storage-dev@chromium.org"
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 647e6c40..f538935 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -1453,9 +1453,6 @@
       base::WeakPtr<ServiceWorkerContainerHost> host);
   void RemoveServiceWorkerContainerHost(const std::string& uuid);
   // Returns the last committed ServiceWorkerContainerHost of this frame.
-  // The function is called on the UI thread, but the returned pointer can only
-  // be dereferenced on the thread identified by
-  // ServiceWorkerContext::GetCoreThreadId().
   base::WeakPtr<ServiceWorkerContainerHost> GetLastCommittedServiceWorkerHost();
 
   // Called to taint |this| so the pages which have requested MediaStream
@@ -3804,8 +3801,6 @@
 
   // Keep the list of ServiceWorkerContainerHosts so that they can observe when
   // the frame goes in/out of BackForwardCache.
-  // These pointers must be dereferenced on the
-  // |ServiceWorkerContext::GetCoreThreadId()| thread only.
   // TODO(yuzus): Make this a single pointer. A frame should only have a single
   // container host, but probably during a navigation the old container host is
   // still alive when the new container host is created and added to this
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index c6d07bd7..9e571e4a5 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2069,12 +2069,10 @@
   AddFilter(pepper_renderer_connection_.get());
 #endif
 
+  // TODO(https://crbug.com/1178670): Move this initialization out of
+  // CreateMessageFilters().
   p2p_socket_dispatcher_host_ =
       std::make_unique<P2PSocketDispatcherHost>(GetID());
-
-  scoped_refptr<ServiceWorkerContextWrapper> service_worker_context(
-      static_cast<ServiceWorkerContextWrapper*>(
-          storage_partition_impl_->GetServiceWorkerContext()));
 }
 
 void RenderProcessHostImpl::BindCacheStorage(
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 00cb460e..eb1a68a7 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1933,8 +1933,9 @@
         base::BindOnce(&RenderWidgetHostImpl::OnUpdateDragCursor,
                        base::Unretained(this), std::move(callback));
     blink_frame_widget_->DragTargetDragEnter(
-        DropMetaDataToDragData(metadata), client_pt, screen_pt,
-        operations_allowed, key_modifiers, std::move(callback_wrapper));
+        DropMetaDataToDragData(metadata),
+        ConvertWindowPointToViewport(client_pt), screen_pt, operations_allowed,
+        key_modifiers, std::move(callback_wrapper));
   }
 }
 
@@ -1959,10 +1960,8 @@
     const gfx::PointF& screen_point) {
   // TODO(https://crbug.com/1102769): Replace with a for_frame() check.
   if (blink_frame_widget_) {
-    gfx::PointF viewport_point = client_point;
-    if (ShouldUseZoomForDSF())
-      viewport_point.Scale(GetScaleFactorForView(GetView()));
-    blink_frame_widget_->DragTargetDragLeave(viewport_point, screen_point);
+    blink_frame_widget_->DragTargetDragLeave(
+        ConvertWindowPointToViewport(client_point), screen_point);
   }
 }
 
diff --git a/content/browser/resources/attribution_reporting/DIR_METADATA b/content/browser/resources/attribution_reporting/DIR_METADATA
index d6b0f2df..16517eeb 100644
--- a/content/browser/resources/attribution_reporting/DIR_METADATA
+++ b/content/browser/resources/attribution_reporting/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>ConversionMeasurement"
-}
+mixins: "//content/browser/attribution_reporting/COMMON_METADATA"
 
-team_email: "privacy-sandbox-dev@chromium.org"
diff --git a/content/browser/resources/indexed_db/DIR_METADATA b/content/browser/resources/indexed_db/DIR_METADATA
new file mode 100644
index 0000000..dedeb35
--- /dev/null
+++ b/content/browser/resources/indexed_db/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/indexed_db/COMMON_METADATA"
diff --git a/content/browser/resources/media/DIR_METADATA b/content/browser/resources/media/DIR_METADATA
index 6667e7f..41e8f64 100644
--- a/content/browser/resources/media/DIR_METADATA
+++ b/content/browser/resources/media/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Media"
-}
+mixins: "//media/COMMON_METADATA"
diff --git a/content/browser/resources/prerender/DIR_METADATA b/content/browser/resources/prerender/DIR_METADATA
index b7a1783..8ead38a 100644
--- a/content/browser/resources/prerender/DIR_METADATA
+++ b/content/browser/resources/prerender/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Preload>Prerender"
-}
+mixins: "//content/browser/prerender/COMMON_METADATA"
 
-team_email: "loading-dev@chromium.org"
diff --git a/content/browser/resources/service_worker/DIR_METADATA b/content/browser/resources/service_worker/DIR_METADATA
index 2a951d09..72616d6 100644
--- a/content/browser/resources/service_worker/DIR_METADATA
+++ b/content/browser/resources/service_worker/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
+mixins: "//content/browser/service_worker/COMMON_METADATA"
 
-team_email: "worker-dev@chromium.org"
diff --git a/content/browser/screen_orientation/DIR_METADATA b/content/browser/screen_orientation/DIR_METADATA
index 4dceb295..7939c1d 100644
--- a/content/browser/screen_orientation/DIR_METADATA
+++ b/content/browser/screen_orientation/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>ScreenOrientation"
-}
+mixins: "//third_party/blink/renderer/modules/screen_orientation/COMMON_METADATA"
 team_email: "media-dev@chromium.org"
diff --git a/content/browser/serial/COMMON_METADATA b/content/browser/serial/COMMON_METADATA
new file mode 100644
index 0000000..9d970329
--- /dev/null
+++ b/content/browser/serial/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Serial"
+}
diff --git a/content/browser/serial/DIR_METADATA b/content/browser/serial/DIR_METADATA
index 9d970329..423968b 100644
--- a/content/browser/serial/DIR_METADATA
+++ b/content/browser/serial/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Serial"
-}
+mixins: "//content/browser/serial/COMMON_METADATA"
diff --git a/content/browser/service_worker/COMMON_METADATA b/content/browser/service_worker/COMMON_METADATA
new file mode 100644
index 0000000..7d8a761e
--- /dev/null
+++ b/content/browser/service_worker/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>ServiceWorker"
+}
+team_email: "worker-dev@chromium.org"
diff --git a/content/browser/service_worker/DIR_METADATA b/content/browser/service_worker/DIR_METADATA
index 7d8a761e..e253a13 100644
--- a/content/browser/service_worker/DIR_METADATA
+++ b/content/browser/service_worker/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
-team_email: "worker-dev@chromium.org"
+mixins: "//content/browser/service_worker/COMMON_METADATA"
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index 13e85b1e..5f1bbb7 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -168,11 +168,11 @@
  public:
   explicit ClearAllServiceWorkersHelper(base::OnceClosure callback)
       : callback_(std::move(callback)) {
-    DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
   }
 
   void OnResult(blink::ServiceWorkerStatusCode) {
-    DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
     // We do nothing in this method. We use this class to wait for all callbacks
     // to be called using the refcount.
   }
@@ -205,7 +205,7 @@
  private:
   friend class base::RefCounted<ClearAllServiceWorkersHelper>;
   ~ClearAllServiceWorkersHelper() {
-    DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
     GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(callback_));
   }
 
@@ -338,7 +338,7 @@
     const blink::StorageKey& key,
     bool include_reserved_clients,
     bool include_back_forward_cached_clients) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return base::WrapUnique(new ContainerHostIterator(
       &container_host_by_uuid_,
       base::BindRepeating(IsSameOriginClientContainerHost, key,
@@ -350,7 +350,7 @@
 ServiceWorkerContextCore::GetWindowClientContainerHostIterator(
     const blink::StorageKey& key,
     bool include_reserved_clients) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return base::WrapUnique(new ContainerHostIterator(
       &container_host_by_uuid_,
       base::BindRepeating(IsSameOriginWindowClientContainerHost, key,
@@ -360,7 +360,7 @@
 void ServiceWorkerContextCore::HasMainFrameWindowClient(
     const blink::StorageKey& key,
     BoolCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   std::unique_ptr<ContainerHostIterator> container_host_iterator =
       GetWindowClientContainerHostIterator(key,
                                            /*include_reserved_clients=*/false);
@@ -499,7 +499,7 @@
         outside_fetch_client_settings_object,
     RegistrationCallback callback,
     const GlobalRenderFrameHostId& requesting_frame_id) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   std::string error_message;
   if (!IsValidRegisterRequest(script_url, options.scope, key, &error_message)) {
     std::move(callback).Run(
@@ -518,7 +518,7 @@
 void ServiceWorkerContextCore::UpdateServiceWorker(
     ServiceWorkerRegistration* registration,
     bool force_bypass_cache) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   job_coordinator_->Update(registration, force_bypass_cache);
 }
 
@@ -529,7 +529,7 @@
     blink::mojom::FetchClientSettingsObjectPtr
         outside_fetch_client_settings_object,
     UpdateCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   job_coordinator_->Update(
       registration, force_bypass_cache, skip_script_comparison,
       std::move(outside_fetch_client_settings_object),
@@ -542,7 +542,7 @@
     const blink::StorageKey& key,
     bool is_immediate,
     UnregistrationCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   job_coordinator_->Unregister(
       scope, key, is_immediate,
       base::BindOnce(&ServiceWorkerContextCore::UnregistrationComplete,
@@ -551,7 +551,7 @@
 
 void ServiceWorkerContextCore::DeleteForStorageKey(const blink::StorageKey& key,
                                                    StatusCallback callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   registry()->GetRegistrationsForStorageKey(
       key,
       base::BindOnce(
@@ -561,7 +561,7 @@
 
 void ServiceWorkerContextCore::PerformStorageCleanup(
     base::OnceClosure callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   registry()->PerformStorageCleanup(std::move(callback));
 }
 
@@ -827,7 +827,7 @@
 
 void ServiceWorkerContextCore::ClearAllServiceWorkersForTest(
     base::OnceClosure callback) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // |callback| will be called in the destructor of |helper| on the UI thread.
   auto helper =
       base::MakeRefCounted<ClearAllServiceWorkersHelper>(std::move(callback));
@@ -916,7 +916,7 @@
     int64_t registration_id,
     const GURL& scope,
     const blink::StorageKey& key) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   observer_list_->Notify(
       FROM_HERE, &ServiceWorkerContextCoreObserver::OnRegistrationStored,
       registration_id, scope, key);
@@ -924,7 +924,7 @@
 
 void ServiceWorkerContextCore::NotifyAllRegistrationsDeletedForStorageKey(
     const blink::StorageKey& key) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   observer_list_->Notify(
       FROM_HERE,
       &ServiceWorkerContextCoreObserver::OnAllRegistrationsDeletedForOrigin,
@@ -1059,7 +1059,7 @@
     const std::u16string& message,
     int line_number,
     const GURL& source_url) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_EQ(this, version->context().get());
   // NOTE: This differs slightly from
   // RenderFrameHostImpl::DidAddMessageToConsole, which also asks the
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 2e75de982..210d04d5 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -295,11 +295,6 @@
   return process_manager()->browser_context();
 }
 
-// static
-BrowserThread::ID ServiceWorkerContext::GetCoreThreadId() {
-  return BrowserThread::UI;
-}
-
 void ServiceWorkerContextWrapper::OnRegistrationCompleted(
     int64_t registration_id,
     const GURL& scope,
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.cc b/content/browser/service_worker/service_worker_main_resource_loader.cc
index 4e92c50b..110258f 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader.cc
@@ -121,7 +121,7 @@
                          "url", resource_request.url.spec());
   DCHECK(ServiceWorkerUtils::IsMainRequestDestination(
       resource_request.destination));
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   resource_request_ = resource_request;
   if (container_host_ && container_host_->fetch_request_window_id()) {
@@ -255,7 +255,7 @@
     blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream,
     blink::mojom::ServiceWorkerFetchEventTimingPtr timing,
     scoped_refptr<ServiceWorkerVersion> version) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_EQ(status_, Status::kStarted);
 
   TRACE_EVENT_WITH_FLOW2(
@@ -335,7 +335,7 @@
     blink::mojom::FetchAPIResponsePtr response,
     scoped_refptr<ServiceWorkerVersion> version,
     blink::mojom::ServiceWorkerStreamHandlePtr body_as_stream) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_EQ(status_, Status::kStarted);
 
   blink::ServiceWorkerLoaderHelpers::SaveResponseInfo(*response,
diff --git a/content/browser/service_worker/service_worker_object_host.cc b/content/browser/service_worker/service_worker_object_host.cc
index 769debe..dc9ff81 100644
--- a/content/browser/service_worker/service_worker_object_host.cc
+++ b/content/browser/service_worker/service_worker_object_host.cc
@@ -200,7 +200,7 @@
       container_host_(container_host),
       container_origin_(url::Origin::Create(container_host_->url())),
       version_(std::move(version)) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(context_ && container_host_ && version_);
   DCHECK(context_->GetLiveRegistration(version_->registration_id()));
   version_->AddObserver(this);
@@ -209,7 +209,7 @@
 }
 
 ServiceWorkerObjectHost::~ServiceWorkerObjectHost() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   version_->RemoveObserver(this);
 }
 
diff --git a/content/browser/service_worker/service_worker_offline_capability_checker.cc b/content/browser/service_worker/service_worker_offline_capability_checker.cc
index b1f22de4..956e62c 100644
--- a/content/browser/service_worker/service_worker_offline_capability_checker.cc
+++ b/content/browser/service_worker/service_worker_offline_capability_checker.cc
@@ -24,7 +24,7 @@
     const GURL& url,
     const blink::StorageKey& key)
     : url_(url), key_(key) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 ServiceWorkerOfflineCapabilityChecker::
diff --git a/content/browser/service_worker/service_worker_registration.cc b/content/browser/service_worker/service_worker_registration.cc
index 5c33e42..644668a 100644
--- a/content/browser/service_worker/service_worker_registration.cc
+++ b/content/browser/service_worker/service_worker_registration.cc
@@ -58,14 +58,14 @@
       resources_total_size_bytes_(0),
       context_(context),
       task_runner_(base::ThreadTaskRunnerHandle::Get()) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_NE(blink::mojom::kInvalidServiceWorkerRegistrationId, registration_id);
   DCHECK(context_);
   context_->AddLiveRegistration(this);
 }
 
 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(listeners_.empty());
 
   // TODO(crbug.com/1159778): Remove once the bug is fixed.
@@ -153,7 +153,7 @@
 }
 
 ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   return ServiceWorkerRegistrationInfo(
       scope(), key(), update_via_cache(), registration_id_,
       is_deleted() ? ServiceWorkerRegistrationInfo::IS_DELETED
@@ -471,7 +471,7 @@
 }
 
 void ServiceWorkerRegistration::ActivateWaitingVersion(bool delay) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(context_);
   DCHECK(IsReadyToActivate());
   should_activate_when_ready_ = false;
diff --git a/content/browser/service_worker/service_worker_registration_object_host.cc b/content/browser/service_worker/service_worker_registration_object_host.cc
index 571d08d..b1d4f08 100644
--- a/content/browser/service_worker/service_worker_registration_object_host.cc
+++ b/content/browser/service_worker/service_worker_registration_object_host.cc
@@ -47,7 +47,7 @@
                        outside_fetch_client_settings_object,
                    ServiceWorkerContextCore::UpdateCallback callback,
                    blink::ServiceWorkerStatusCode status) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     // The delay was already very long and update() is rejected immediately.
@@ -243,11 +243,11 @@
     return;
   }
 
-  BrowserThread::GetTaskRunnerForThread(ServiceWorkerContext::GetCoreThreadId())
-      ->PostDelayedTask(FROM_HERE,
-                        base::BindOnce(std::move(update_function),
-                                       blink::ServiceWorkerStatusCode::kOk),
-                        delay);
+  GetUIThreadTaskRunner({})->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(std::move(update_function),
+                     blink::ServiceWorkerStatusCode::kOk),
+      delay);
 }
 
 void ServiceWorkerRegistrationObjectHost::Unregister(
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 4111001..76132e5 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -118,7 +118,7 @@
 const int kInvalidTraceId = -1;
 
 int NextTraceId() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   static int trace_id = 0;
   if (trace_id == std::numeric_limits<int>::max())
     trace_id = 0;
@@ -150,7 +150,7 @@
     blink::mojom::ServiceWorkerHost::OpenNewTabCallback callback,
     blink::ServiceWorkerStatusCode status,
     blink::mojom::ServiceWorkerClientInfoPtr client_info) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   const bool success = (status == blink::ServiceWorkerStatusCode::kOk);
   absl::optional<std::string> error_msg;
   if (!success) {
@@ -185,7 +185,7 @@
     const GURL& url,
     blink::ServiceWorkerStatusCode status,
     blink::mojom::ServiceWorkerClientInfoPtr client) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   const bool success = (status == blink::ServiceWorkerStatusCode::kOk);
   absl::optional<std::string> error_msg;
   if (!success) {
@@ -381,7 +381,7 @@
 }
 
 ServiceWorkerVersionInfo ServiceWorkerVersion::GetInfo() {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   ServiceWorkerVersionInfo info(
       running_status(), status(), fetch_handler_existence(), script_url(),
       scope(), key(), registration_id(), version_id(),
@@ -421,7 +421,7 @@
       TRACE_EVENT_SCOPE_THREAD, "Script", script_url_.spec(), "Purpose",
       ServiceWorkerMetrics::EventTypeToString(purpose));
 
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   const bool is_browser_startup_complete =
       GetContentClient()->browser()->IsBrowserStartupComplete();
   if (!context_) {
@@ -760,7 +760,7 @@
 
 void ServiceWorkerVersion::AddControllee(
     ServiceWorkerContainerHost* container_host) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // TODO(crbug.com/1021718): Remove this CHECK once we figure out the cause of
   // crash.
   CHECK(container_host);
@@ -801,7 +801,7 @@
 }
 
 void ServiceWorkerVersion::RemoveControllee(const std::string& client_uuid) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // TODO(crbug.com/1015692): Remove this once RemoveControllee() matches with
   // AddControllee().
   if (!base::Contains(controllee_map_, client_uuid))
@@ -827,7 +827,7 @@
 void ServiceWorkerVersion::OnControlleeNavigationCommitted(
     const std::string& client_uuid,
     const GlobalRenderFrameHostId& rfh_id) {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
 #if DCHECK_IS_ON()
   // Ensures this function is only called for a known window client.
@@ -2407,7 +2407,7 @@
 
 bool ServiceWorkerVersion::ShouldRequireForegroundPriority(
     int worker_process_id) const {
-  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Currently FetchEvents are the only type of event we need to really process
   // at foreground priority.  If the service worker does not have a FetchEvent
diff --git a/content/browser/sms/COMMON_METADATA b/content/browser/sms/COMMON_METADATA
new file mode 100644
index 0000000..ac3c0481
--- /dev/null
+++ b/content/browser/sms/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>WebOTP"
+}
+team_email: "fugu-dev@chromium.org"
diff --git a/content/browser/sms/DIR_METADATA b/content/browser/sms/DIR_METADATA
index ac3c0481..52a7d1c8 100644
--- a/content/browser/sms/DIR_METADATA
+++ b/content/browser/sms/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>WebOTP"
-}
-team_email: "fugu-dev@chromium.org"
+mixins: "//content/browser/sms/COMMON_METADATA"
diff --git a/content/browser/speech/DIR_METADATA b/content/browser/speech/DIR_METADATA
index 49120a8..4b16894 100644
--- a/content/browser/speech/DIR_METADATA
+++ b/content/browser/speech/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Speech"
-}
+mixins: "//third_party/blink/renderer/modules/speech/COMMON_METADATA"
diff --git a/content/browser/web_package/COMMON_METADATA b/content/browser/web_package/COMMON_METADATA
new file mode 100644
index 0000000..16964bc
--- /dev/null
+++ b/content/browser/web_package/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Loader"
+}
+team_email: "loading-dev@chromium.org"
diff --git a/content/browser/web_package/DIR_METADATA b/content/browser/web_package/DIR_METADATA
index 16964bc..bc54ae7 100644
--- a/content/browser/web_package/DIR_METADATA
+++ b/content/browser/web_package/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Loader"
-}
-team_email: "loading-dev@chromium.org"
+mixins: "//content/browser/web_package/COMMON_METADATA"
diff --git a/content/browser/webid/COMMON_METADATA b/content/browser/webid/COMMON_METADATA
new file mode 100644
index 0000000..b36c62f
--- /dev/null
+++ b/content/browser/webid/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Identity>WebID"
+}
diff --git a/content/browser/webid/DIR_METADATA b/content/browser/webid/DIR_METADATA
index b36c62f..136e07617 100644
--- a/content/browser/webid/DIR_METADATA
+++ b/content/browser/webid/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Identity>WebID"
-}
+mixins: "//content/browser/webid/COMMON_METADATA"
diff --git a/content/browser/webui/web_ui_data_source_impl.h b/content/browser/webui/web_ui_data_source_impl.h
index 5cf9d032..ff08589 100644
--- a/content/browser/webui/web_ui_data_source_impl.h
+++ b/content/browser/webui/web_ui_data_source_impl.h
@@ -77,6 +77,9 @@
   // Protected for testing.
   virtual const base::DictionaryValue* GetLocalizedStrings() const;
 
+  // Protected for testing.
+  int PathToIdrOrDefault(const std::string& path) const;
+
  private:
   class InternalDataSource;
   friend class InternalDataSource;
@@ -90,8 +93,6 @@
                         const WebContents::Getter& wc_getter,
                         URLDataSource::GotDataCallback callback);
 
-  int PathToIdrOrDefault(const std::string& path) const;
-
   // Note: this must be called before StartDataRequest() to have an effect.
   void disable_load_time_data_defaults_for_testing() {
     add_load_time_data_defaults_ = false;
diff --git a/content/browser/worker_host/shared_worker_host_unittest.cc b/content/browser/worker_host/shared_worker_host_unittest.cc
index 700459f..fec0eca 100644
--- a/content/browser/worker_host/shared_worker_host_unittest.cc
+++ b/content/browser/worker_host/shared_worker_host_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/unguessable_token.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
 #include "content/browser/navigation_subresource_loader_params.h"
@@ -352,7 +353,19 @@
 }
 
 TEST_F(SharedWorkerHostTest, CreateNetworkFactoryParamsForSubresources) {
+  // Enable COEPForSharedWorker, since CreateNetworkFactoryParamsForSubresources
+  // does more logic in that case.
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(blink::features::kCOEPForSharedWorker);
+
   base::WeakPtr<SharedWorkerHost> host = CreateHost();
+
+  // Start the worker.
+  mojo::PendingRemote<blink::mojom::SharedWorkerFactory> factory;
+  MockSharedWorkerFactory factory_impl(
+      factory.InitWithNewPipeAndPassReceiver());
+  StartWorker(host.get(), std::move(factory));
+
   network::mojom::URLLoaderFactoryParamsPtr params =
       host->CreateNetworkFactoryParamsForSubresources();
   EXPECT_EQ(host->GetStorageKey().origin(),
@@ -362,6 +375,11 @@
 
 TEST_F(SharedWorkerHostTest,
        CreateNetworkFactoryParamsForSubresourcesWithNonce) {
+  // Enable COEPForSharedWorker, since CreateNetworkFactoryParamsForSubresources
+  // does more logic in that case.
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(blink::features::kCOEPForSharedWorker);
+
   base::UnguessableToken nonce = base::UnguessableToken::Create();
   SharedWorkerInstance instance(
       kWorkerUrl, blink::mojom::ScriptType::kClassic,
@@ -374,6 +392,13 @@
       &service_, instance, site_instance_,
       std::vector<network::mojom::ContentSecurityPolicyPtr>(),
       network::CrossOriginEmbedderPolicy());
+
+  // Start the worker.
+  mojo::PendingRemote<blink::mojom::SharedWorkerFactory> factory;
+  MockSharedWorkerFactory factory_impl(
+      factory.InitWithNewPipeAndPassReceiver());
+  StartWorker(host.get(), std::move(factory));
+
   network::mojom::URLLoaderFactoryParamsPtr params =
       host->CreateNetworkFactoryParamsForSubresources();
   EXPECT_EQ(url::Origin::Create(kWorkerUrl),
diff --git a/content/common/background_fetch/DIR_METADATA b/content/common/background_fetch/DIR_METADATA
index 8011d708..47aeb1f99 100644
--- a/content/common/background_fetch/DIR_METADATA
+++ b/content/common/background_fetch/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>BackgroundFetch"
-}
+mixins: "//content/browser/background_fetch/COMMON_METADATA"
 
-team_email: "platform-capabilities@chromium.org"
diff --git a/content/common/fetch/DIR_METADATA b/content/common/fetch/DIR_METADATA
new file mode 100644
index 0000000..0d0ce5b
--- /dev/null
+++ b/content/common/fetch/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/core/fetch/COMMON_METADATA"
diff --git a/content/common/media/DIR_METADATA b/content/common/media/DIR_METADATA
index 6667e7f..41e8f64 100644
--- a/content/common/media/DIR_METADATA
+++ b/content/common/media/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Media"
-}
+mixins: "//media/COMMON_METADATA"
diff --git a/content/common/service_worker/DIR_METADATA b/content/common/service_worker/DIR_METADATA
index 2a951d09..72616d6 100644
--- a/content/common/service_worker/DIR_METADATA
+++ b/content/common/service_worker/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
+mixins: "//content/browser/service_worker/COMMON_METADATA"
 
-team_email: "worker-dev@chromium.org"
diff --git a/content/common/web_package/DIR_METADATA b/content/common/web_package/DIR_METADATA
index 25ca5ca6..e744f56 100644
--- a/content/common/web_package/DIR_METADATA
+++ b/content/common/web_package/DIR_METADATA
@@ -1,5 +1,5 @@
+mixins: "//content/browser/web_package/COMMON_METADATA"
 monorail {
   component: "Blink>Loader>WebPackaging"
 }
 
-team_email: "loading-dev@chromium.org"
diff --git a/content/common/zygote/DIR_METADATA b/content/common/zygote/DIR_METADATA
index eba0ca0..ce020412 100644
--- a/content/common/zygote/DIR_METADATA
+++ b/content/common/zygote/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Sandbox"
-}
+mixins: "//content/zygote/COMMON_METADATA"
 
-team_email: "security-dev@chromium.org"
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/COMMON_METADATA b/content/public/android/java/src/org/chromium/content/browser/accessibility/COMMON_METADATA
new file mode 100644
index 0000000..6ad19c3
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/COMMON_METADATA
@@ -0,0 +1,6 @@
+monorail {
+  component: "UI>Accessibility>Compatibility"
+}
+
+team_email: "chromium-accessibility@chromium.org"
+
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/DIR_METADATA b/content/public/android/java/src/org/chromium/content/browser/accessibility/DIR_METADATA
index 6ad19c3..81e2dd1 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/DIR_METADATA
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/DIR_METADATA
@@ -1,6 +1,3 @@
-monorail {
-  component: "UI>Accessibility>Compatibility"
-}
-
-team_email: "chromium-accessibility@chromium.org"
+mixins: "//ui/accessibility/COMMON_METADATA"
+mixins: "//content/public/android/java/src/org/chromium/content/browser/accessibility/COMMON_METADATA"
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/font/COMMON_METADATA b/content/public/android/java/src/org/chromium/content/browser/font/COMMON_METADATA
new file mode 100644
index 0000000..d6af1cb
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/font/COMMON_METADATA
@@ -0,0 +1,6 @@
+monorail {
+  component: "UI>Browser>Mobile"
+}
+
+team_email: "clank-dev@google.com"
+
diff --git a/content/public/android/java/src/org/chromium/content/browser/font/DIR_METADATA b/content/public/android/java/src/org/chromium/content/browser/font/DIR_METADATA
index d6af1cb..909b697 100644
--- a/content/public/android/java/src/org/chromium/content/browser/font/DIR_METADATA
+++ b/content/public/android/java/src/org/chromium/content/browser/font/DIR_METADATA
@@ -1,6 +1,2 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-
-team_email: "clank-dev@google.com"
+mixins: "//content/public/android/java/src/org/chromium/content/browser/font/COMMON_METADATA"
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA
new file mode 100644
index 0000000..6e8bcf2c
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Mobile>WebView"
+}
+
+team_email: "android-webview-dev@chromium.org"
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/DIR_METADATA b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/DIR_METADATA
index 6e8bcf2c..de0888c0 100644
--- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/DIR_METADATA
+++ b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Mobile>WebView"
-}
+mixins: "//content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA"
 
-team_email: "android-webview-dev@chromium.org"
diff --git a/content/public/android/java/src/org/chromium/content/browser/sms/DIR_METADATA b/content/public/android/java/src/org/chromium/content/browser/sms/DIR_METADATA
index dfa5703..16bc5a28 100644
--- a/content/public/android/java/src/org/chromium/content/browser/sms/DIR_METADATA
+++ b/content/public/android/java/src/org/chromium/content/browser/sms/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>WebOTP"
-}
+mixins: "//content/browser/sms/COMMON_METADATA"
 team_email: "web-identity@google.com"
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/DIR_METADATA b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/DIR_METADATA
index 7a2dd4c7..5397240 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/DIR_METADATA
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/DIR_METADATA
@@ -1,6 +1,6 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
+mixins: "//content/public/android/java/src/org/chromium/content/browser/accessibility/COMMON_METADATA"
 monorail {
   component: "UI>Accessibility"
 }
 
-team_email: "chromium-accessibility@chromium.org"
-
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTest.java b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTest.java
index ea50857..95c193f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityTest.java
@@ -114,6 +114,8 @@
             "node should have a Spannable with spelling correction for given text.";
     private static final String INPUT_RANGE_VALUE_MISMATCH =
             "Value for <input type='range'> is incorrect, did you honor 'step' value?";
+    private static final String INPUT_RANGE_VALUETEXT_MISMATCH =
+            "Value for <input type='range'> text is incorrect, did you honor aria-valuetext?";
     private static final String INPUT_RANGE_EVENT_ERROR =
             "TYPE_VIEW_SCROLLED event not received before timeout.";
     private static final String CACHING_ERROR = "AccessibilityNodeInfo cache has stale data";
@@ -406,6 +408,39 @@
     }
 
     /**
+     * Test <input type="range"> nodes are properly populated when aria-valuetext is set.
+     */
+    @Test
+    @SmallTest
+    public void testAccessibilityNodeInfo_inputTypeRange_withAriaValueText() {
+        // Build a simple web page with input nodes that have aria-valuetext.
+        setupTestWithHTML(
+                "<input id='in1' type='range' value='1' min='0' max='2' aria-valuetext='medium'>"
+                + "<label for='in2'>This is a test label"
+                + "  <input id='in2' type='range' value='0' min='0' max='2' aria-valuetext='small'>"
+                + "</label>");
+
+        int vvIdInput1 = waitForNodeMatching(sViewIdResourceNameMatcher, "in1");
+        int vvIdInput2 = waitForNodeMatching(sViewIdResourceNameMatcher, "in2");
+        AccessibilityNodeInfo mNodeInfo1 = createAccessibilityNodeInfo(vvIdInput1);
+        AccessibilityNodeInfo mNodeInfo2 = createAccessibilityNodeInfo(vvIdInput2);
+        Assert.assertNotNull(NODE_TIMEOUT_ERROR, mNodeInfo1);
+        Assert.assertNotNull(NODE_TIMEOUT_ERROR, mNodeInfo2);
+
+        mActivityTestRule.sendEndOfTestSignal();
+
+        // Check the text of each element, and that RangeInfo has not been set.
+        mNodeInfo1 = createAccessibilityNodeInfo(vvIdInput1);
+        mNodeInfo2 = createAccessibilityNodeInfo(vvIdInput2);
+        Assert.assertEquals(
+                INPUT_RANGE_VALUETEXT_MISMATCH, "medium", mNodeInfo1.getText().toString());
+        Assert.assertEquals(INPUT_RANGE_VALUETEXT_MISMATCH, "small, This is a test label",
+                mNodeInfo2.getText().toString());
+        Assert.assertNull(INPUT_RANGE_VALUETEXT_MISMATCH, mNodeInfo1.getRangeInfo());
+        Assert.assertNull(INPUT_RANGE_VALUETEXT_MISMATCH, mNodeInfo2.getRangeInfo());
+    }
+
+    /**
      * Ensure we throttle TYPE_WINDOW_CONTENT_CHANGED events for large tree updates.
      */
     @Test
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/font/DIR_METADATA b/content/public/android/javatests/src/org/chromium/content/browser/font/DIR_METADATA
new file mode 100644
index 0000000..425348aa
--- /dev/null
+++ b/content/public/android/javatests/src/org/chromium/content/browser/font/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/public/android/java/src/org/chromium/content/browser/font/COMMON_METADATA"
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/DIR_METADATA b/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/DIR_METADATA
new file mode 100644
index 0000000..a1576e2b
--- /dev/null
+++ b/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA"
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/sms/DIR_METADATA b/content/public/android/javatests/src/org/chromium/content/browser/sms/DIR_METADATA
index dfa5703..16bc5a28 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/sms/DIR_METADATA
+++ b/content/public/android/javatests/src/org/chromium/content/browser/sms/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>WebOTP"
-}
+mixins: "//content/browser/sms/COMMON_METADATA"
 team_email: "web-identity@google.com"
diff --git a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/DIR_METADATA b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/DIR_METADATA
new file mode 100644
index 0000000..a1576e2b
--- /dev/null
+++ b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/public/android/java/src/org/chromium/content/browser/remoteobjects/COMMON_METADATA"
diff --git a/content/public/android/junit/src/org/chromium/content/browser/sms/DIR_METADATA b/content/public/android/junit/src/org/chromium/content/browser/sms/DIR_METADATA
index dfa5703..16bc5a28 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/sms/DIR_METADATA
+++ b/content/public/android/junit/src/org/chromium/content/browser/sms/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>WebOTP"
-}
+mixins: "//content/browser/sms/COMMON_METADATA"
 team_email: "web-identity@google.com"
diff --git a/content/public/browser/service_worker_context.h b/content/public/browser/service_worker_context.h
index d14f0eed..f60facf 100644
--- a/content/public/browser/service_worker_context.h
+++ b/content/public/browser/service_worker_context.h
@@ -96,10 +96,6 @@
   using StartWorkerCallback = base::OnceCallback<
       void(int64_t version_id, int process_id, int thread_id)>;
 
-  // Returns BrowserThread::UI always.
-  // TODO(https://crbug.com/1138155): Remove this.
-  static content::BrowserThread::ID GetCoreThreadId();
-
   // Returns true if |url| is within the service worker |scope|.
   static bool ScopeMatches(const GURL& scope, const GURL& url);
 
diff --git a/content/public/common/zygote/DIR_METADATA b/content/public/common/zygote/DIR_METADATA
index eba0ca0..ce020412 100644
--- a/content/public/common/zygote/DIR_METADATA
+++ b/content/public/common/zygote/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Sandbox"
-}
+mixins: "//content/zygote/COMMON_METADATA"
 
-team_email: "security-dev@chromium.org"
diff --git a/content/public/test/service_worker_test_helpers.cc b/content/public/test/service_worker_test_helpers.cc
index d9dadb6ef..dc1a4c2c 100644
--- a/content/public/test/service_worker_test_helpers.cc
+++ b/content/public/test/service_worker_test_helpers.cc
@@ -57,7 +57,7 @@
 
     // ServiceWorkerContextCoreObserver:
     void OnStopped(int64_t version_id) override {
-      DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+      DCHECK_CURRENTLY_ON(BrowserThread::UI);
       if (version_id != version_id_)
         return;
       std::move(stopped_callback_).Run();
@@ -90,7 +90,7 @@
     base::OnceClosure completion_callback_ui,
     blink::ServiceWorkerStatusCode service_worker_status,
     scoped_refptr<ServiceWorkerRegistration> service_worker_registration) {
-  DCHECK(BrowserThread::CurrentlyOn(ServiceWorkerContext::GetCoreThreadId()));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_EQ(blink::ServiceWorkerStatusCode::kOk, service_worker_status);
   int64_t version_id =
       service_worker_registration->active_version()->version_id();
@@ -103,7 +103,7 @@
     const blink::PlatformNotificationData& notification_data,
     blink::ServiceWorkerStatusCode service_worker_status,
     scoped_refptr<ServiceWorkerRegistration> service_worker_registration) {
-  DCHECK(BrowserThread::CurrentlyOn(ServiceWorkerContext::GetCoreThreadId()));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK_EQ(blink::ServiceWorkerStatusCode::kOk, service_worker_status);
   scoped_refptr<ServiceWorkerVersion> version =
       service_worker_registration->active_version();
@@ -118,25 +118,6 @@
       }));
 }
 
-void FindReadyRegistrationForScope(
-    scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
-    const GURL& scope,
-    base::OnceCallback<void(blink::ServiceWorkerStatusCode,
-                            scoped_refptr<ServiceWorkerRegistration>)>
-        callback) {
-  if (!BrowserThread::CurrentlyOn(ServiceWorkerContext::GetCoreThreadId())) {
-    BrowserThread::GetTaskRunnerForThread(
-        ServiceWorkerContext::GetCoreThreadId())
-        ->PostTask(FROM_HERE, base::BindOnce(&FindReadyRegistrationForScope,
-                                             std::move(context_wrapper), scope,
-                                             std::move(callback)));
-    return;
-  }
-  context_wrapper->FindReadyRegistrationForScope(
-      scope, blink::StorageKey(url::Origin::Create(scope)),
-      std::move(callback));
-}
-
 }  // namespace
 
 void StopServiceWorkerForScope(ServiceWorkerContext* context,
@@ -146,8 +127,8 @@
   scoped_refptr<ServiceWorkerContextWrapper> context_wrapper(
       static_cast<ServiceWorkerContextWrapper*>(context));
 
-  FindReadyRegistrationForScope(
-      context_wrapper, scope,
+  context_wrapper->FindReadyRegistrationForScope(
+      scope, blink::StorageKey(url::Origin::Create(scope)),
       base::BindOnce(&StopServiceWorkerForRegistration, context_wrapper,
                      std::move(completion_callback_ui)));
 }
@@ -160,8 +141,8 @@
   scoped_refptr<ServiceWorkerContextWrapper> context_wrapper(
       static_cast<ServiceWorkerContextWrapper*>(context));
 
-  FindReadyRegistrationForScope(
-      std::move(context_wrapper), scope,
+  context_wrapper->FindReadyRegistrationForScope(
+      scope, blink::StorageKey(url::Origin::Create(scope)),
       base::BindOnce(&DispatchNotificationClickForRegistration,
                      notification_data));
 }
diff --git a/content/public/test/test_web_ui_data_source.cc b/content/public/test/test_web_ui_data_source.cc
index 8d901c2..b5e1ec3b6 100644
--- a/content/public/test/test_web_ui_data_source.cc
+++ b/content/public/test/test_web_ui_data_source.cc
@@ -18,6 +18,7 @@
   }
 
   using WebUIDataSourceImpl::GetLocalizedStrings;
+  using WebUIDataSourceImpl::PathToIdrOrDefault;
 
  protected:
   explicit WebUIDataSourceImplWithPublicData(const std::string& source_name)
@@ -46,6 +47,10 @@
     return source_->source()->GetReplacements();
   }
 
+  int PathToIdrOrDefault(const std::string& path) override {
+    return source_->PathToIdrOrDefault(path);
+  }
+
   WebUIDataSource* GetWebUIDataSource() override { return source_.get(); }
 
  private:
diff --git a/content/public/test/test_web_ui_data_source.h b/content/public/test/test_web_ui_data_source.h
index 8874545..8916a5a 100644
--- a/content/public/test/test_web_ui_data_source.h
+++ b/content/public/test/test_web_ui_data_source.h
@@ -30,6 +30,8 @@
 
   virtual const ui::TemplateReplacements* GetReplacements() = 0;
 
+  virtual int PathToIdrOrDefault(const std::string& path) = 0;
+
   virtual WebUIDataSource* GetWebUIDataSource() = 0;
 };
 
diff --git a/content/renderer/accessibility/DIR_METADATA b/content/renderer/accessibility/DIR_METADATA
index 299fade..c775858 100644
--- a/content/renderer/accessibility/DIR_METADATA
+++ b/content/renderer/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail {
   component: "UI>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/content/renderer/media/DIR_METADATA b/content/renderer/media/DIR_METADATA
index 6667e7f..41e8f64 100644
--- a/content/renderer/media/DIR_METADATA
+++ b/content/renderer/media/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Media"
-}
+mixins: "//media/COMMON_METADATA"
diff --git a/content/renderer/service_worker/DIR_METADATA b/content/renderer/service_worker/DIR_METADATA
index 7d8a761e..e253a13 100644
--- a/content/renderer/service_worker/DIR_METADATA
+++ b/content/renderer/service_worker/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
-team_email: "worker-dev@chromium.org"
+mixins: "//content/browser/service_worker/COMMON_METADATA"
diff --git a/content/shell/fuchsia/DIR_METADATA b/content/shell/fuchsia/DIR_METADATA
index d537e1b..9fa1ad6 100644
--- a/content/shell/fuchsia/DIR_METADATA
+++ b/content/shell/fuchsia/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Fuchsia"
-}
-team_email: "cr-fuchsia@chromium.org"
+mixins: "//build/fuchsia/COMMON_METADATA"
 os: FUCHSIA
diff --git a/content/test/data/accessibility/DIR_METADATA b/content/test/data/accessibility/DIR_METADATA
index 32e94314..36b12b6 100644
--- a/content/test/data/accessibility/DIR_METADATA
+++ b/content/test/data/accessibility/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Accessibility"
-}
-team_email: "chromium-accessibility@chromium.org"
+mixins: "//ui/accessibility/COMMON_METADATA"
diff --git a/content/test/data/accessibility/aria/aria-meter-expected-android.txt b/content/test/data/accessibility/aria/aria-meter-expected-android.txt
index ba343bc..8fe805a 100644
--- a/content/test/data/accessibility/aria/aria-meter-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-meter-expected-android.txt
@@ -1,3 +1,3 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.ProgressBar role_description='meter' range name='funding' item_index=50 item_count=100 range_max=100 range_current_value=50
-++android.widget.ProgressBar role_description='meter' range name='funding' item_index=10 item_count=100 range_max=100 range_current_value=10
+++android.widget.ProgressBar role_description='meter' range name='half-way, funding' range_max=100 range_current_value=50
+++android.widget.ProgressBar role_description='meter' range name='10, funding' item_index=10 item_count=100 range_max=100 range_current_value=10
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-progressbar-expected-android.txt b/content/test/data/accessibility/aria/aria-progressbar-expected-android.txt
index 57a1c20..ac78eed 100644
--- a/content/test/data/accessibility/aria/aria-progressbar-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-progressbar-expected-android.txt
@@ -1,5 +1,5 @@
 android.webkit.WebView focusable focused scrollable
 ++android.widget.ProgressBar role_description='progress indicator' range name='3' item_index=5 item_count=100 range_min=1 range_max=37 range_current_value=3
-++android.widget.ProgressBar role_description='progress indicator' range name='three' item_index=2 item_count=100 range_min=1 range_max=96 range_current_value=3
+++android.widget.ProgressBar role_description='progress indicator' range name='three' range_min=1 range_max=96 range_current_value=3
 ++android.widget.ProgressBar role_description='progress indicator' range item_count=100 range_max=10
-++android.widget.ProgressBar role_description='progress indicator' range item_count=100 range_max=100
+++android.widget.ProgressBar role_description='progress indicator' range item_count=100 range_max=100
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-readonly-expected-android.txt b/content/test/data/accessibility/aria/aria-readonly-expected-android.txt
index bb014e31..e133c162 100644
--- a/content/test/data/accessibility/aria/aria-readonly-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-readonly-expected-android.txt
@@ -15,8 +15,8 @@
 ++android.widget.EditText clickable disabled editable_text focusable hint='Readonly combobox' input_type=1
 ++android.widget.ListView role_description='list box' clickable collection disabled name='Readonly listbox'
 ++android.view.View role_description='radio group' disabled name='Readonly radiogroup'
-++android.widget.SeekBar role_description='slider' clickable disabled range name='Readonly slider' item_index=50 item_count=100 range_max=100 range_current_value=50
-++android.widget.EditText role_description='spin button' clickable disabled range name='Readonly spinbutton' item_count=100
+++android.widget.SeekBar role_description='slider' clickable disabled range name='50, Readonly slider' item_index=50 item_count=100 range_max=100 range_current_value=50
+++android.widget.EditText role_description='spin button' clickable disabled range name='0, Readonly spinbutton' item_count=100
 ++android.view.MenuItem role_description='checkbox' checkable clickable disabled name='Readonly menuitemcheckbox'
 ++android.view.MenuItem role_description='radio button' checkable clickable disabled name='Readonly menuitemradio'
 ++android.widget.EditText role_description='search text field' clickable disabled editable_text hint='Readonly searchbox'
diff --git a/content/test/data/accessibility/aria/aria-valuetext-expected-android.txt b/content/test/data/accessibility/aria/aria-valuetext-expected-android.txt
index 0b67ab32..2057e3e 100644
--- a/content/test/data/accessibility/aria/aria-valuetext-expected-android.txt
+++ b/content/test/data/accessibility/aria/aria-valuetext-expected-android.txt
@@ -1,2 +1,2 @@
 android.webkit.WebView focusable focused scrollable
-++android.widget.ProgressBar role_description='progress indicator' range name='three' item_index=2 item_count=100 range_min=1 range_max=96 range_current_value=3
+++android.widget.ProgressBar role_description='progress indicator' range name='three' range_min=1 range_max=96 range_current_value=3
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-number-expected-android.txt b/content/test/data/accessibility/html/input-number-expected-android.txt
index eeff4e8..79890e98 100644
--- a/content/test/data/accessibility/html/input-number-expected-android.txt
+++ b/content/test/data/accessibility/html/input-number-expected-android.txt
@@ -1,4 +1,4 @@
 android.webkit.WebView focusable focused scrollable
 ++android.view.View
-++++android.widget.EditText role_description='spin button' clickable editable_text focusable has_non_empty_value range name='1' item_count=100 input_type=2 range_current_value=1 text_change_added_count=1
-++++android.widget.EditText role_description='spin button' clickable editable_text focusable has_non_empty_value range name='6' item_index=20 item_count=100 input_type=2 range_min=5 range_max=10 range_current_value=6 text_change_added_count=1
+++++android.widget.EditText role_description='spin button' clickable editable_text focusable has_non_empty_value range name='1' input_type=2 range_current_value=1 text_change_added_count=1
+++++android.widget.EditText role_description='spin button' clickable editable_text focusable has_non_empty_value range name='6' input_type=2 range_min=5 range_max=10 range_current_value=6 text_change_added_count=1
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-range-expected-android.txt b/content/test/data/accessibility/html/input-range-expected-android.txt
index d519342..db8a1c3 100644
--- a/content/test/data/accessibility/html/input-range-expected-android.txt
+++ b/content/test/data/accessibility/html/input-range-expected-android.txt
@@ -2,6 +2,6 @@
 ++android.view.View
 ++++android.widget.SeekBar role_description='slider' clickable focusable range name='5' item_index=44 item_count=100 range_min=1 range_max=10 range_current_value=5
 ++++android.widget.SeekBar role_description='slider' clickable focusable range name='3' item_index=22 item_count=100 range_min=1 range_max=10 range_current_value=3
-++++android.widget.SeekBar role_description='slider' clickable focusable range name='Medium' item_index=44 item_count=100 range_min=1 range_max=10 range_current_value=5
-++++android.widget.SeekBar role_description='slider' clickable focusable range name='Friday' item_count=100 range_max=5 range_current_value=6
-++++android.widget.SeekBar role_description='slider' clickable focusable range name='0.2' item_index=60 item_count=100 range_min=-1 range_max=1
+++++android.widget.SeekBar role_description='slider' clickable focusable range name='Medium' range_min=1 range_max=10 range_current_value=5
+++++android.widget.SeekBar role_description='slider' clickable focusable range name='Friday' range_max=5 range_current_value=6
+++++android.widget.SeekBar role_description='slider' clickable focusable range name='0.2' item_index=60 item_count=100 range_min=-1 range_max=1
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/input-types-expected-android.txt b/content/test/data/accessibility/html/input-types-expected-android.txt
index 7d97f1e..bd316a2 100644
--- a/content/test/data/accessibility/html/input-types-expected-android.txt
+++ b/content/test/data/accessibility/html/input-types-expected-android.txt
@@ -28,7 +28,7 @@
 ++++android.widget.RadioButton role_description='radio button' checkable clickable focusable name='Radio:'
 ++++android.view.View
 ++++++android.widget.TextView name='Range: '
-++++++android.widget.SeekBar role_description='slider' clickable focusable range name='Range:' item_index=50 item_count=100 range_max=100 range_current_value=50
+++++++android.widget.SeekBar role_description='slider' clickable focusable range name='50, Range:' item_index=50 item_count=100 range_max=100 range_current_value=50
 ++++android.view.View
 ++++++android.widget.TextView name='Reset: '
 ++++++android.widget.Button role_description='button' clickable focusable name='Reset:'
@@ -46,4 +46,4 @@
 ++++++android.widget.EditText clickable editable_text focusable hint='Text:' input_type=1
 ++++android.view.View
 ++++++android.widget.TextView name='Url: '
-++++++android.widget.EditText clickable editable_text focusable hint='Url:' input_type=17
+++++++android.widget.EditText clickable editable_text focusable hint='Url:' input_type=17
\ No newline at end of file
diff --git a/content/test/data/origin_trials/DIR_METADATA b/content/test/data/origin_trials/DIR_METADATA
new file mode 100644
index 0000000..14641a38
--- /dev/null
+++ b/content/test/data/origin_trials/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/common/origin_trials/COMMON_METADATA"
diff --git a/content/test/portal/DIR_METADATA b/content/test/portal/DIR_METADATA
index 1e4fe50..842d7f2 100644
--- a/content/test/portal/DIR_METADATA
+++ b/content/test/portal/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Portals"
-}
+mixins: "//third_party/blink/renderer/core/html/portal/COMMON_METADATA"
diff --git a/content/zygote/COMMON_METADATA b/content/zygote/COMMON_METADATA
new file mode 100644
index 0000000..be22226
--- /dev/null
+++ b/content/zygote/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Sandbox"
+}
+team_email: "security-dev@chromium.org"
diff --git a/content/zygote/DIR_METADATA b/content/zygote/DIR_METADATA
index be22226..2cf6588 100644
--- a/content/zygote/DIR_METADATA
+++ b/content/zygote/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>Sandbox"
-}
-team_email: "security-dev@chromium.org"
+mixins: "//content/zygote/COMMON_METADATA"
diff --git a/crypto/nss_util.h b/crypto/nss_util.h
index 0aace2d..b17557f 100644
--- a/crypto/nss_util.h
+++ b/crypto/nss_util.h
@@ -7,7 +7,7 @@
 
 #include <stdint.h>
 
-#include "base/callback.h"
+#include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "build/chromeos_buildflags.h"
@@ -36,32 +36,27 @@
 bool CheckNSSVersion(const char* version);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-// Indicates that NSS should use the Chaps library so that we
-// can access the TPM through NSS.  InitializeTPMTokenAndSystemSlot and
-// InitializeTPMForChromeOSUser must still be called to load the slots.
-CRYPTO_EXPORT void EnableTPMTokenForNSS();
 
-// Returns true if EnableTPMTokenForNSS has been called.
-CRYPTO_EXPORT bool IsTPMTokenEnabledForNSS();
-
-// Returns true if the TPM is owned and PKCS#11 initialized with the
-// user and security officer PINs, and has been enabled in NSS by
-// calling EnableTPMForNSS, and Chaps has been successfully
-// loaded into NSS.
-// If |callback| is non-null and the function returns false, the |callback| will
-// be run once the TPM is ready. |callback| will never be run if the function
-// returns true.
-CRYPTO_EXPORT bool IsTPMTokenReady(base::OnceClosure callback)
-    WARN_UNUSED_RESULT;
+// Returns true once the TPM is owned and PKCS#11 initialized with the
+// user and security officer PINs, and Chaps has been successfully loaded into
+// NSS. Returns false if the TPM will never be loaded.
+CRYPTO_EXPORT void IsTPMTokenEnabled(base::OnceCallback<void(bool)> callback);
 
 // Initialize the TPM token and system slot. The |callback| will run on the same
 // thread with true if the token and slot were successfully loaded or were
-// already initialized. |callback| will be passed false if loading failed.  Once
-// called, InitializeTPMTokenAndSystemSlot must not be called again until the
-// |callback| has been run.
+// already initialized. |callback| will be passed false if loading failed.
+// Should be called only once.
 CRYPTO_EXPORT void InitializeTPMTokenAndSystemSlot(
     int system_slot_id,
     base::OnceCallback<void(bool)> callback);
+
+// Notifies clients that the TPM has finished initialization (i.e. notify
+// the callbacks of `IsTPMTokenEnabled()` or `GetSystemNSSKeySlot()`).
+// If `InitializeTPMTokenAndSystemSlot()` has been called before this method,
+// this signals that the TPM is enabled, and should use the slot configured by
+// those methods. If neither of those methods have been called, this signals
+// that no TPM system slot will be available.
+CRYPTO_EXPORT void FinishInitializingTPMTokenAndSystemSlot();
 #endif
 
 // Convert a NSS PRTime value into a base::Time object.
diff --git a/crypto/nss_util_chromeos.cc b/crypto/nss_util_chromeos.cc
index f1e8312..abf8a603 100644
--- a/crypto/nss_util_chromeos.cc
+++ b/crypto/nss_util_chromeos.cc
@@ -24,6 +24,7 @@
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/no_destructor.h"
 #include "base/path_service.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
@@ -106,12 +107,46 @@
   SlotReadyCallbackList tpm_ready_callback_list_;
 };
 
+// Contains state used for the ChromeOSTokenManager. Unlike the
+// ChromeOSTokenManager, which is thread-checked, this object may live
+// and be accessed on multiple threads. While this is normally dangerous,
+// this is done to support callers initializing early in process startup,
+// where the threads using the objects may not be created yet, and the
+// thread startup may depend on these objects.
+// Put differently: They may be written to from any thread, if, and only
+// if, the thread they will be read from has not yet been created;
+// otherwise, this should be treated as thread-affine/thread-hostile.
+struct ChromeOSTokenManagerDataForTesting {
+  static ChromeOSTokenManagerDataForTesting& GetInstance() {
+    static base::NoDestructor<ChromeOSTokenManagerDataForTesting> instance;
+    return *instance;
+  }
+
+  // System slot that will be used for the system slot initialization.
+  ScopedPK11Slot test_system_slot;
+};
+
 class ChromeOSTokenManager {
  public:
+  enum class State {
+    // Initial state.
+    kInitializationNotStarted,
+    // Initialization of the TPM token was started.
+    kInitializationStarted,
+    // TPM token was successfully initialized, but not available to the class'
+    // users yet.
+    kTpmTokenInitialized,
+    // TPM token was successfully enabled. It is a final state.
+    kTpmTokenEnabled,
+    // TPM token will never be enabled. It is a final state.
+    kTpmTokenDisabled,
+  };
+
   // Used with PostTaskAndReply to pass handles to worker thread and back.
   struct TPMModuleAndSlot {
     explicit TPMModuleAndSlot(SECMODModule* init_chaps_module)
         : chaps_module(init_chaps_module) {}
+
     SECMODModule* chaps_module;
     ScopedPK11Slot tpm_slot;
   };
@@ -132,42 +167,12 @@
     return OpenSoftwareNSSDB(nssdb_path, db_name);
   }
 
-  void EnableTPMTokenForNSS() {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-    // If this gets set, then we'll use the TPM for certs with
-    // private keys, otherwise we'll fall back to the software
-    // implementation.
-    tpm_token_enabled_for_nss_ = true;
-  }
-
-  bool IsTPMTokenEnabledForNSS() {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    return tpm_token_enabled_for_nss_;
-  }
-
   void InitializeTPMTokenAndSystemSlot(
       int system_slot_id,
       base::OnceCallback<void(bool)> callback) {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    // Should not be called while there is already an initialization in
-    // progress.
-    DCHECK(!initializing_tpm_token_);
-    // If EnableTPMTokenForNSS hasn't been called, return false.
-    if (!tpm_token_enabled_for_nss_) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(std::move(callback), false));
-      return;
-    }
-
-    // If everything is already initialized, then return true.
-    // Note that only |system_slot_| is checked, since |chaps_module_| could be
-    // nullptr in tests while |system_slot_| has been set to the test DB.
-    if (system_slot_) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(std::move(callback), true));
-      return;
-    }
+    DCHECK_EQ(state_, State::kInitializationNotStarted);
+    state_ = State::kInitializationStarted;
 
     // Note that a reference is not taken to chaps_module_. This is safe since
     // ChromeOSTokenManager is Leaky, so the reference it holds is never
@@ -184,7 +189,26 @@
             &ChromeOSTokenManager::OnInitializedTPMTokenAndSystemSlot,
             base::Unretained(this),  // ChromeOSTokenManager is leaky
             std::move(callback), std::move(tpm_args)));
-    initializing_tpm_token_ = true;
+  }
+
+  void FinishInitializingTPMTokenAndSystemSlot() {
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+    DCHECK(!IsInitializationFinished());
+
+    // If `OnInitializedTPMTokenAndSystemSlot` was not called, but a test system
+    // slot is prepared, start using it now. Can happen in tests that don't fake
+    // enable TPM.
+    if (!system_slot_ &&
+        ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot) {
+      system_slot_ = ScopedPK11Slot(
+          PK11_ReferenceSlot(ChromeOSTokenManagerDataForTesting::GetInstance()
+                                 .test_system_slot.get()));
+    }
+
+    state_ = (state_ == State::kTpmTokenInitialized) ? State::kTpmTokenEnabled
+                                                     : State::kTpmTokenDisabled;
+
+    tpm_ready_callback_list_.Notify();
   }
 
   static void InitializeTPMTokenInThreadPool(CK_SLOT_ID token_slot_id,
@@ -215,31 +239,42 @@
              << ", got tpm slot: " << !!tpm_args->tpm_slot;
 
     chaps_module_ = tpm_args->chaps_module;
-    system_slot_ = std::move(tpm_args->tpm_slot);
-    if (!chaps_module_ && test_system_slot_) {
-      // chromeos_unittests try to test the TPM initialization process. If we
-      // have a test DB open, pretend that it is the TPM slot.
-      system_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
-    }
-    initializing_tpm_token_ = false;
 
-    if (system_slot_)
-      RunAndClearTPMReadyCallbackList();
+    if (ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot) {
+      // chromeos_unittests try to test the TPM initialization process. If we
+      // have a test DB open, pretend that it is the system slot.
+      system_slot_ = ScopedPK11Slot(
+          PK11_ReferenceSlot(ChromeOSTokenManagerDataForTesting::GetInstance()
+                                 .test_system_slot.get()));
+    } else {
+      system_slot_ = std::move(tpm_args->tpm_slot);
+    }
+
+    if (system_slot_) {
+      state_ = State::kTpmTokenInitialized;
+    }
 
     std::move(callback).Run(!!system_slot_);
   }
 
-  void RunAndClearTPMReadyCallbackList() { tpm_ready_callback_list_.Notify(); }
-
-  bool IsTPMTokenReady(base::OnceClosure callback) {
+  void IsTPMTokenEnabled(base::OnceCallback<void(bool)> callback) {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    if (system_slot_)
-      return true;
+    DCHECK(!callback.is_null());
 
-    if (!callback.is_null())
-      tpm_ready_callback_list_.AddUnsafe(std::move(callback));
+    if (!IsInitializationFinished()) {
+      // Call back to this method when initialization is finished.
+      tpm_ready_callback_list_.AddUnsafe(
+          base::BindOnce(&ChromeOSTokenManager::IsTPMTokenEnabled,
+                         base::Unretained(this) /* singleton is leaky */,
+                         std::move(callback)));
+      return;
+    }
 
-    return false;
+    DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(callback),
+                       /*is_tpm_enabled=*/(state_ == State::kTpmTokenEnabled)));
   }
 
   // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot
@@ -391,33 +426,27 @@
     chromeos_user_map_.erase(i);
   }
 
-  void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
+  void GetSystemNSSKeySlot(base::OnceCallback<void(ScopedPK11Slot)> callback) {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-    // Ensure that a previous value of test_system_slot_ is not overwritten.
-    // Unsetting, i.e. setting a nullptr, however is allowed.
-    DCHECK(!slot || !test_system_slot_);
-    test_system_slot_ = std::move(slot);
-    if (test_system_slot_) {
-      system_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
-      RunAndClearTPMReadyCallbackList();
-    } else {
-      system_slot_.reset();
+    if (!IsInitializationFinished()) {
+      // Call back to this method when initialization is finished.
+      tpm_ready_callback_list_.AddUnsafe(
+          base::BindOnce(&ChromeOSTokenManager::GetSystemNSSKeySlot,
+                         base::Unretained(this) /* singleton is leaky */,
+                         std::move(callback)));
+      return;
     }
+
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(callback),
+                       /*system_slot=*/ScopedPK11Slot(
+                           system_slot_ ? PK11_ReferenceSlot(system_slot_.get())
+                                        : nullptr)));
   }
 
-  void SetSystemKeySlotWithoutInitializingTPMForTesting(ScopedPK11Slot slot) {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-    // Ensure that a previous value of test_system_slot_ is not overwritten.
-    // Unsetting, i.e. setting a nullptr, however is allowed.
-    DCHECK(!slot || !test_system_slot_);
-    if (system_slot_ && system_slot_ == test_system_slot_) {
-      // Unset |system_slot_| if it was initialized from |test_system_slot_|.
-      system_slot_.reset();
-    }
-    test_system_slot_ = std::move(slot);
-  }
+  void ResetSystemSlotForTesting() { system_slot_.reset(); }
 
   void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -428,29 +457,8 @@
     prepared_test_private_slot_ = std::move(slot);
   }
 
-  void GetSystemNSSKeySlotCallback(
-      base::OnceCallback<void(ScopedPK11Slot)> callback) {
-    std::move(callback).Run(
-        ScopedPK11Slot(PK11_ReferenceSlot(system_slot_.get())));
-  }
-
-  ScopedPK11Slot GetSystemNSSKeySlot(
-      base::OnceCallback<void(ScopedPK11Slot)> callback) {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    // TODO(mattm): chromeos::TPMTokenloader always calls
-    // InitializeTPMTokenAndSystemSlot with slot 0.  If the system slot is
-    // disabled, system_slot_ will be the first user's slot instead. Can that be
-    // detected and return nullptr instead?
-
-    base::OnceClosure wrapped_callback;
-    if (!callback.is_null()) {
-      wrapped_callback = base::BindOnce(
-          &ChromeOSTokenManager::GetSystemNSSKeySlotCallback,
-          base::Unretained(this) /* singleton is leaky */, std::move(callback));
-    }
-    if (IsTPMTokenReady(std::move(wrapped_callback)))
-      return ScopedPK11Slot(PK11_ReferenceSlot(system_slot_.get()));
-    return ScopedPK11Slot();
+  bool IsInitializationStarted() {
+    return (state_ != State::kInitializationNotStarted);
   }
 
  private:
@@ -463,14 +471,24 @@
   // shut down.
   ~ChromeOSTokenManager() = delete;
 
-  bool tpm_token_enabled_for_nss_ = false;
-  bool initializing_tpm_token_ = false;
-  using TPMReadyCallbackList = base::OnceClosureList;
-  TPMReadyCallbackList tpm_ready_callback_list_;
+  bool IsInitializationFinished() {
+    switch (state_) {
+      case State::kTpmTokenEnabled:
+      case State::kTpmTokenDisabled:
+        return true;
+      case State::kInitializationNotStarted:
+      case State::kInitializationStarted:
+      case State::kTpmTokenInitialized:
+        return false;
+    }
+  }
+
+  State state_ = State::kInitializationNotStarted;
+  base::OnceClosureList tpm_ready_callback_list_;
+
   SECMODModule* chaps_module_ = nullptr;
   ScopedPK11Slot system_slot_;
   std::map<std::string, std::unique_ptr<ChromeOSUserData>> chromeos_user_map_;
-  ScopedPK11Slot test_system_slot_;
   ScopedPK11Slot prepared_test_private_slot_;
 
   THREAD_CHECKER(thread_checker_);
@@ -485,30 +503,29 @@
   return profile_directory_path.AppendASCII(".pki").AppendASCII("nssdb");
 }
 
-ScopedPK11Slot GetSystemNSSKeySlot(
-    base::OnceCallback<void(ScopedPK11Slot)> callback) {
-  return g_token_manager.Get().GetSystemNSSKeySlot(std::move(callback));
+void GetSystemNSSKeySlot(base::OnceCallback<void(ScopedPK11Slot)> callback) {
+  g_token_manager.Get().GetSystemNSSKeySlot(std::move(callback));
 }
 
-void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
-  g_token_manager.Get().SetSystemKeySlotForTesting(std::move(slot));
+void PrepareSystemSlotForTesting(ScopedPK11Slot slot) {
+  DCHECK(!ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot);
+  DCHECK(!g_token_manager.IsCreated() ||
+         !g_token_manager.Get().IsInitializationStarted())
+      << "PrepareSystemSlotForTesting is called after initialization started";
+
+  ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot =
+      std::move(slot);
 }
 
-void SetSystemKeySlotWithoutInitializingTPMForTesting(ScopedPK11Slot slot) {
-  g_token_manager.Get().SetSystemKeySlotWithoutInitializingTPMForTesting(
-      std::move(slot));
+void ResetSystemSlotForTesting() {
+  if (g_token_manager.IsCreated()) {
+    g_token_manager.Get().ResetSystemSlotForTesting();  // IN-TEST
+  }
+  ChromeOSTokenManagerDataForTesting::GetInstance().test_system_slot.reset();
 }
 
-void EnableTPMTokenForNSS() {
-  g_token_manager.Get().EnableTPMTokenForNSS();
-}
-
-bool IsTPMTokenEnabledForNSS() {
-  return g_token_manager.Get().IsTPMTokenEnabledForNSS();
-}
-
-bool IsTPMTokenReady(base::OnceClosure callback) {
-  return g_token_manager.Get().IsTPMTokenReady(std::move(callback));
+void IsTPMTokenEnabled(base::OnceCallback<void(bool)> callback) {
+  g_token_manager.Get().IsTPMTokenEnabled(std::move(callback));
 }
 
 void InitializeTPMTokenAndSystemSlot(int token_slot_id,
@@ -517,6 +534,10 @@
                                                         std::move(callback));
 }
 
+void FinishInitializingTPMTokenAndSystemSlot() {
+  g_token_manager.Get().FinishInitializingTPMTokenAndSystemSlot();
+}
+
 bool InitializeNSSForChromeOSUser(const std::string& username_hash,
                                   const base::FilePath& path) {
   return g_token_manager.Get().InitializeNSSForChromeOSUser(username_hash,
diff --git a/crypto/nss_util_internal.h b/crypto/nss_util_internal.h
index 353215c92..9e11efc 100644
--- a/crypto/nss_util_internal.h
+++ b/crypto/nss_util_internal.h
@@ -52,27 +52,23 @@
 CRYPTO_EXPORT base::FilePath GetSoftwareNSSDBPath(
     const base::FilePath& profile_directory_path);
 
-// Returns a reference to the system-wide TPM slot if it is loaded. If it is not
-// loaded and |callback| is non-null, the |callback| will be run once the slot
-// is loaded.
-CRYPTO_EXPORT ScopedPK11Slot GetSystemNSSKeySlot(
-    base::OnceCallback<void(ScopedPK11Slot)> callback) WARN_UNUSED_RESULT;
-
-// Sets the test system slot to |slot|, which means that |slot| will be exposed
-// through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will return true.
-// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization,
-// does not have to be called if the test system slot is set.
-// This must must not be called consecutively with a |slot| != nullptr. If
-// |slot| is nullptr, the test system slot is unset.
-CRYPTO_EXPORT void SetSystemKeySlotForTesting(ScopedPK11Slot slot);
+// Returns a reference to the system-wide TPM slot (or nullptr if it will never
+// be loaded).
+CRYPTO_EXPORT void GetSystemNSSKeySlot(
+    base::OnceCallback<void(ScopedPK11Slot)> callback);
 
 // Injects the given |slot| as a system slot set by the future
 // |InitializeTPMTokenAndSystemSlot| call.
-// This must must not be called consecutively with a |slot| != nullptr. If
-// |slot| is nullptr and the system slot is already initialized to the
-// previously passed test value, the system slot is unset.
-CRYPTO_EXPORT void SetSystemKeySlotWithoutInitializingTPMForTesting(
-    ScopedPK11Slot slot);
+CRYPTO_EXPORT void PrepareSystemSlotForTesting(ScopedPK11Slot slot);
+
+// Attempt to unset the testing system slot.
+// Note: After this method is called, the system is in an undefined state; it is
+// NOT possible to call `PrepareSystemSlotForTesting()` and have it return to a
+// known-good state. The primary purpose is to attempt to release system
+// resources, such as file handles, to allow the cleanup of files on disk, but
+// because of the process-wide effect, it's not possible to unwind any/all
+// initialization that depended on this previously-configured system slot.
+CRYPTO_EXPORT void ResetSystemSlotForTesting();
 
 // Prepare per-user NSS slot mapping. It is safe to call this function multiple
 // times. Returns true if the user was added, or false if it already existed.
diff --git a/crypto/scoped_test_system_nss_key_slot.cc b/crypto/scoped_test_system_nss_key_slot.cc
index 53fbbff..4bc52bb 100644
--- a/crypto/scoped_test_system_nss_key_slot.cc
+++ b/crypto/scoped_test_system_nss_key_slot.cc
@@ -4,21 +4,27 @@
 
 #include "crypto/scoped_test_system_nss_key_slot.h"
 
+#include "crypto/nss_util.h"
 #include "crypto/nss_util_internal.h"
 #include "crypto/scoped_test_nss_db.h"
 
 namespace crypto {
 
-ScopedTestSystemNSSKeySlot::ScopedTestSystemNSSKeySlot()
+ScopedTestSystemNSSKeySlot::ScopedTestSystemNSSKeySlot(
+    bool simulate_token_loader)
     : test_db_(new ScopedTestNSSDB) {
   if (!test_db_->is_open())
     return;
-  SetSystemKeySlotForTesting(
+
+  PrepareSystemSlotForTesting(  // IN-TEST
       ScopedPK11Slot(PK11_ReferenceSlot(test_db_->slot())));
+
+  if (simulate_token_loader)
+    FinishInitializingTPMTokenAndSystemSlot();
 }
 
 ScopedTestSystemNSSKeySlot::~ScopedTestSystemNSSKeySlot() {
-  SetSystemKeySlotForTesting(ScopedPK11Slot());
+  ResetSystemSlotForTesting();  // IN-TEST
 }
 
 bool ScopedTestSystemNSSKeySlot::ConstructedSuccessfully() const {
diff --git a/crypto/scoped_test_system_nss_key_slot.h b/crypto/scoped_test_system_nss_key_slot.h
index 1c8804e..d01d4da 100644
--- a/crypto/scoped_test_system_nss_key_slot.h
+++ b/crypto/scoped_test_system_nss_key_slot.h
@@ -17,17 +17,22 @@
 
 class ScopedTestNSSDB;
 
-// Opens a persistent NSS software database in a temporary directory and sets
-// the test system slot to the opened database. This helper should be created in
-// tests to fake the system token that is usually provided by the Chaps module.
-// |slot| is exposed through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will
-// return true.
-// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization,
-// does not have to be called if this helper is used.
-// At most one instance of this helper must be used at a time.
+// Helper object to override the behavior of `crypto::GetSystemNSSKeySlot()`
+// to return a slot from a temporary directory (i.e. bypassing the TPM).
+// This object MUST be created before any call to
+// `crypto::InitializeTPMTokenAndSystemSlot()`. Note: As noted in
+// `crypto::ResetSystemSlotForTesting()`, once a fake slot has been configured
+// for a process, it cannot be undone. As such, only one instance of this object
+// must be created for a process.
 class CRYPTO_EXPORT ScopedTestSystemNSSKeySlot {
  public:
-  ScopedTestSystemNSSKeySlot();
+  // If `simulate_token_loader` is false, this class only prepares a software
+  // system slot, which will be made available through `GetSystemNSSKeySlot`
+  // when something else (presumably the TpmTokenLoader) calls
+  // `crypto::FinishInitializingTPMTokenAndSystemSlot`. Setting
+  // `simulate_token_loader` to true emulates the "initialization finished"
+  // signal immediately (e.g. in unit tests).
+  ScopedTestSystemNSSKeySlot(bool simulate_token_loader);
 
   ScopedTestSystemNSSKeySlot(const ScopedTestSystemNSSKeySlot&) = delete;
   ScopedTestSystemNSSKeySlot& operator=(const ScopedTestSystemNSSKeySlot&) =
diff --git a/dbus/COMMON_METADATA b/dbus/COMMON_METADATA
new file mode 100644
index 0000000..aa4f0fd
--- /dev/null
+++ b/dbus/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Systems"
+}
\ No newline at end of file
diff --git a/dbus/DIR_METADATA b/dbus/DIR_METADATA
index 311c8f9..f4cb890 100644
--- a/dbus/DIR_METADATA
+++ b/dbus/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "OS>Systems"
-}
\ No newline at end of file
+mixins: "//dbus/COMMON_METADATA"
diff --git a/docs/privacy_budget/DIR_METADATA b/docs/privacy_budget/DIR_METADATA
index ddd78885..b3eca914 100644
--- a/docs/privacy_budget/DIR_METADATA
+++ b/docs/privacy_budget/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Privacy>Fingerprinting"
-}
-team_email: "privacy-sandbox-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/public/common/privacy_budget/COMMON_METADATA"
diff --git a/docs/updater/DIR_METADATA b/docs/updater/DIR_METADATA
new file mode 100644
index 0000000..593a8a1
--- /dev/null
+++ b/docs/updater/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/updater/COMMON_METADATA"
diff --git a/extensions/COMMON_METADATA b/extensions/COMMON_METADATA
new file mode 100644
index 0000000..81a57a13
--- /dev/null
+++ b/extensions/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Platform>Extensions"
+}
+team_email: "extensions-dev@chromium.org"
diff --git a/extensions/DIR_METADATA b/extensions/DIR_METADATA
index 81a57a13..e1d704c 100644
--- a/extensions/DIR_METADATA
+++ b/extensions/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Platform>Extensions"
-}
-team_email: "extensions-dev@chromium.org"
+mixins: "//extensions/COMMON_METADATA"
diff --git a/extensions/browser/api/guest_view/DIR_METADATA b/extensions/browser/api/guest_view/DIR_METADATA
index 22d44120c..38cda2d 100644
--- a/extensions/browser/api/guest_view/DIR_METADATA
+++ b/extensions/browser/api/guest_view/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>BrowserTag"
-}
+mixins: "//components/guest_view/COMMON_METADATA"
diff --git a/extensions/browser/api/web_request/COMMON_METADATA b/extensions/browser/api/web_request/COMMON_METADATA
new file mode 100644
index 0000000..637eb4dc
--- /dev/null
+++ b/extensions/browser/api/web_request/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Platform>Extensions>API"
+}
diff --git a/extensions/browser/api/web_request/DIR_METADATA b/extensions/browser/api/web_request/DIR_METADATA
index 637eb4dc..ab13556 100644
--- a/extensions/browser/api/web_request/DIR_METADATA
+++ b/extensions/browser/api/web_request/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Extensions>API"
-}
+mixins: "//extensions/browser/api/web_request/COMMON_METADATA"
diff --git a/extensions/browser/extension_service_worker_message_filter.cc b/extensions/browser/extension_service_worker_message_filter.cc
index 014d3c0f..bebb04f 100644
--- a/extensions/browser/extension_service_worker_message_filter.cc
+++ b/extensions/browser/extension_service_worker_message_filter.cc
@@ -143,7 +143,7 @@
 void ExtensionServiceWorkerMessageFilter::OnIncrementServiceWorkerActivity(
     int64_t service_worker_version_id,
     const std::string& request_uuid) {
-  DCHECK_CURRENTLY_ON(content::ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!browser_context_)
     return;
   active_request_uuids_.insert(request_uuid);
@@ -157,7 +157,7 @@
 void ExtensionServiceWorkerMessageFilter::OnDecrementServiceWorkerActivity(
     int64_t service_worker_version_id,
     const std::string& request_uuid) {
-  DCHECK_CURRENTLY_ON(content::ServiceWorkerContext::GetCoreThreadId());
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!browser_context_)
     return;
   content::ServiceWorkerExternalRequestResult result =
diff --git a/extensions/browser/guest_view/DIR_METADATA b/extensions/browser/guest_view/DIR_METADATA
index 22d44120c..38cda2d 100644
--- a/extensions/browser/guest_view/DIR_METADATA
+++ b/extensions/browser/guest_view/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>BrowserTag"
-}
+mixins: "//components/guest_view/COMMON_METADATA"
diff --git a/extensions/renderer/guest_view/DIR_METADATA b/extensions/renderer/guest_view/DIR_METADATA
index 22d44120c..38cda2d 100644
--- a/extensions/renderer/guest_view/DIR_METADATA
+++ b/extensions/renderer/guest_view/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>BrowserTag"
-}
+mixins: "//components/guest_view/COMMON_METADATA"
diff --git a/extensions/renderer/resources/guest_view/DIR_METADATA b/extensions/renderer/resources/guest_view/DIR_METADATA
index 22d44120c..38cda2d 100644
--- a/extensions/renderer/resources/guest_view/DIR_METADATA
+++ b/extensions/renderer/resources/guest_view/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Platform>Apps>BrowserTag"
-}
+mixins: "//components/guest_view/COMMON_METADATA"
diff --git a/fuchsia/DIR_METADATA b/fuchsia/DIR_METADATA
index 11f5ec9..5b3985ec 100644
--- a/fuchsia/DIR_METADATA
+++ b/fuchsia/DIR_METADATA
@@ -6,8 +6,5 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Fuchsia"
-}
-team_email: "cr-fuchsia@chromium.org"
+mixins: "//build/fuchsia/COMMON_METADATA"
 os: FUCHSIA
\ No newline at end of file
diff --git a/fuchsia/engine/BUILD.gn b/fuchsia/engine/BUILD.gn
index 66b51998..3f7be14 100644
--- a/fuchsia/engine/BUILD.gn
+++ b/fuchsia/engine/BUILD.gn
@@ -136,6 +136,7 @@
     "//media",
     "//media/fuchsia/cdm/service",
     "//media/fuchsia/mojom",
+    "//media/fuchsia/mojom:cdm_provider",
     "//media/mojo/common",
     "//media/mojo/services",
     "//mojo/public/cpp/bindings",
@@ -196,6 +197,8 @@
     "browser/accessibility_bridge.h",
     "browser/ax_tree_converter.cc",
     "browser/ax_tree_converter.h",
+    "browser/cdm_provider_service.cc",
+    "browser/cdm_provider_service.h",
     "browser/content_directory_loader_factory.cc",
     "browser/content_directory_loader_factory.h",
     "browser/context_impl.cc",
@@ -212,10 +215,10 @@
     "browser/frame_permission_controller.h",
     "browser/frame_window_tree_host.cc",
     "browser/frame_window_tree_host.h",
+    "browser/fuchsia_media_resource_provider_impl.cc",
+    "browser/fuchsia_media_resource_provider_impl.h",
     "browser/media_player_impl.cc",
     "browser/media_player_impl.h",
-    "browser/media_resource_provider_service.cc",
-    "browser/media_resource_provider_service.h",
     "browser/navigation_controller_impl.cc",
     "browser/navigation_controller_impl.h",
     "browser/navigation_policy_handler.cc",
diff --git a/fuchsia/engine/browser/cdm_provider_service.cc b/fuchsia/engine/browser/cdm_provider_service.cc
new file mode 100644
index 0000000..7bfe371
--- /dev/null
+++ b/fuchsia/engine/browser/cdm_provider_service.cc
@@ -0,0 +1,142 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "fuchsia/engine/browser/cdm_provider_service.h"
+
+#include <lib/fidl/cpp/interface_handle.h>
+#include <lib/sys/cpp/component_context.h>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/fuchsia/process_context.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/document_service_base.h"
+#include "content/public/browser/provision_fetcher_factory.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "fuchsia/engine/switches.h"
+#include "media/base/provision_fetcher.h"
+#include "media/fuchsia/cdm/service/fuchsia_cdm_manager.h"
+#include "third_party/widevine/cdm/widevine_cdm_common.h"
+
+namespace {
+
+class CdmProviderImpl final
+    : public content::DocumentServiceBase<media::mojom::FuchsiaCdmProvider> {
+ public:
+  CdmProviderImpl(
+      media::FuchsiaCdmManager* cdm_manager,
+      content::RenderFrameHost* render_frame_host,
+      mojo::PendingReceiver<media::mojom::FuchsiaCdmProvider> receiver);
+  ~CdmProviderImpl() override;
+
+  CdmProviderImpl(const CdmProviderImpl&) = delete;
+  CdmProviderImpl& operator=(const CdmProviderImpl&) = delete;
+
+  // media::mojom::FuchsiaCdmProvider implementation.
+  void CreateCdm(
+      const std::string& key_system,
+      fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
+          request) override;
+
+ private:
+  media::FuchsiaCdmManager* const cdm_manager_;
+};
+
+CdmProviderImpl::CdmProviderImpl(
+    media::FuchsiaCdmManager* cdm_manager,
+    content::RenderFrameHost* render_frame_host,
+    mojo::PendingReceiver<media::mojom::FuchsiaCdmProvider> receiver)
+    : DocumentServiceBase(render_frame_host, std::move(receiver)),
+      cdm_manager_(cdm_manager) {
+  DCHECK(cdm_manager_);
+}
+
+CdmProviderImpl::~CdmProviderImpl() = default;
+
+void CdmProviderImpl::CreateCdm(
+    const std::string& key_system,
+    fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
+        request) {
+  scoped_refptr<network::SharedURLLoaderFactory> loader_factory =
+      render_frame_host()
+          ->GetProcess()
+          ->GetBrowserContext()
+          ->GetDefaultStoragePartition()
+          ->GetURLLoaderFactoryForBrowserProcess();
+  media::CreateFetcherCB create_fetcher_cb = base::BindRepeating(
+      &content::CreateProvisionFetcher, std::move(loader_factory));
+  cdm_manager_->CreateAndProvision(
+      key_system, origin(), std::move(create_fetcher_cb), std::move(request));
+}
+
+template <typename KeySystemInterface>
+fidl::InterfaceHandle<fuchsia::media::drm::KeySystem> ConnectToKeySystem() {
+  static_assert(
+      (std::is_same<KeySystemInterface, fuchsia::media::drm::Widevine>::value ||
+       std::is_same<KeySystemInterface, fuchsia::media::drm::PlayReady>::value),
+      "KeySystemInterface must be either fuchsia::media::drm::Widevine or "
+      "fuchsia::media::drm::PlayReady");
+
+  // TODO(fxbug.dev/13674): Once the key system specific protocols are turned
+  // into services, we should not need to manually force the key system specific
+  // interface into the KeySystem interface.
+  fidl::InterfaceHandle<fuchsia::media::drm::KeySystem> key_system;
+  base::ComponentContextForProcess()->svc()->Connect(key_system.NewRequest(),
+                                                     KeySystemInterface::Name_);
+  return key_system;
+}
+
+std::unique_ptr<media::FuchsiaCdmManager> CreateCdmManager() {
+  media::FuchsiaCdmManager::CreateKeySystemCallbackMap
+      create_key_system_callbacks;
+
+  const auto* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableWidevine)) {
+    create_key_system_callbacks.emplace(
+        kWidevineKeySystem,
+        base::BindRepeating(
+            &ConnectToKeySystem<fuchsia::media::drm::Widevine>));
+  }
+
+  std::string playready_key_system =
+      command_line->GetSwitchValueASCII(switches::kPlayreadyKeySystem);
+  if (!playready_key_system.empty()) {
+    create_key_system_callbacks.emplace(
+        playready_key_system,
+        base::BindRepeating(
+            &ConnectToKeySystem<fuchsia::media::drm::PlayReady>));
+  }
+
+  std::string cdm_data_directory =
+      command_line->GetSwitchValueASCII(switches::kCdmDataDirectory);
+
+  absl::optional<uint64_t> cdm_data_quota_bytes;
+  if (command_line->HasSwitch(switches::kCdmDataQuotaBytes)) {
+    uint64_t value = 0;
+    CHECK(base::StringToUint64(
+        command_line->GetSwitchValueASCII(switches::kCdmDataQuotaBytes),
+        &value));
+    cdm_data_quota_bytes = value;
+  }
+
+  return std::make_unique<media::FuchsiaCdmManager>(
+      std::move(create_key_system_callbacks),
+      base::FilePath(cdm_data_directory), cdm_data_quota_bytes);
+}
+
+}  // namespace
+
+CdmProviderService::CdmProviderService() : cdm_manager_(CreateCdmManager()) {}
+
+CdmProviderService::~CdmProviderService() = default;
+
+void CdmProviderService::Bind(
+    content::RenderFrameHost* frame_host,
+    mojo::PendingReceiver<media::mojom::FuchsiaCdmProvider> receiver) {
+  // The object will delete itself when connection to the frame is broken.
+  new CdmProviderImpl(cdm_manager_.get(), frame_host, std::move(receiver));
+}
diff --git a/fuchsia/engine/browser/cdm_provider_service.h b/fuchsia/engine/browser/cdm_provider_service.h
new file mode 100644
index 0000000..103693b
--- /dev/null
+++ b/fuchsia/engine/browser/cdm_provider_service.h
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FUCHSIA_ENGINE_BROWSER_CDM_PROVIDER_SERVICE_H_
+#define FUCHSIA_ENGINE_BROWSER_CDM_PROVIDER_SERVICE_H_
+
+#include "media/fuchsia/mojom/fuchsia_cdm_provider.mojom.h"
+
+namespace content {
+class RenderFrameHost;
+}  // namespace content
+
+namespace media {
+class FuchsiaCdmManager;
+}  // namespace media
+
+class CdmProviderService {
+ public:
+  CdmProviderService();
+  ~CdmProviderService();
+
+  CdmProviderService(const CdmProviderService&) = delete;
+  CdmProviderService& operator=(const CdmProviderService&) = delete;
+
+  void Bind(content::RenderFrameHost* frame_host,
+            mojo::PendingReceiver<media::mojom::FuchsiaCdmProvider> receiver);
+
+ private:
+  std::unique_ptr<media::FuchsiaCdmManager> cdm_manager_;
+};
+
+#endif  // FUCHSIA_ENGINE_BROWSER_CDM_PROVIDER_SERVICE_H_
diff --git a/fuchsia/engine/browser/fuchsia_media_resource_provider_impl.cc b/fuchsia/engine/browser/fuchsia_media_resource_provider_impl.cc
new file mode 100644
index 0000000..17faa87
--- /dev/null
+++ b/fuchsia/engine/browser/fuchsia_media_resource_provider_impl.cc
@@ -0,0 +1,79 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "fuchsia/engine/browser/fuchsia_media_resource_provider_impl.h"
+
+#include <lib/fidl/cpp/interface_handle.h>
+#include <lib/sys/cpp/component_context.h>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/fuchsia/process_context.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/document_service_base.h"
+#include "content/public/browser/permission_controller.h"
+#include "content/public/browser/render_frame_host.h"
+#include "fuchsia/engine/browser/frame_impl.h"
+#include "media/base/media_switches.h"
+
+void FuchsiaMediaResourceProviderImpl::Bind(
+    content::RenderFrameHost* frame_host,
+    mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider>
+        receiver) {
+  // The object will delete itself when connection to the frame is broken.
+  new FuchsiaMediaResourceProviderImpl(frame_host, std::move(receiver));
+}
+
+FuchsiaMediaResourceProviderImpl::FuchsiaMediaResourceProviderImpl(
+    content::RenderFrameHost* render_frame_host,
+    mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider> receiver)
+    : DocumentServiceBase(render_frame_host, std::move(receiver)) {}
+
+FuchsiaMediaResourceProviderImpl::~FuchsiaMediaResourceProviderImpl() = default;
+
+void FuchsiaMediaResourceProviderImpl::CreateAudioConsumer(
+    fidl::InterfaceRequest<fuchsia::media::AudioConsumer> request) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableAudioOutput)) {
+    LOG(WARNING)
+        << "Could not create AudioConsumer because audio output feature flag "
+           "was not enabled.";
+    return;
+  }
+
+  auto factory = base::ComponentContextForProcess()
+                     ->svc()
+                     ->Connect<fuchsia::media::SessionAudioConsumerFactory>();
+  factory->CreateAudioConsumer(
+      FrameImpl::FromRenderFrameHost(render_frame_host())->media_session_id(),
+      std::move(request));
+}
+
+void FuchsiaMediaResourceProviderImpl::CreateAudioCapturer(
+    fidl::InterfaceRequest<fuchsia::media::AudioCapturer> request) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableAudioInput)) {
+    LOG(WARNING)
+        << "Could not create AudioCapturer because audio input feature flag "
+           "was not enabled.";
+    return;
+  }
+
+  if (render_frame_host()
+          ->GetBrowserContext()
+          ->GetPermissionController()
+          ->GetPermissionStatusForFrame(
+              content::PermissionType::AUDIO_CAPTURE, render_frame_host(),
+              origin().GetURL()) != blink::mojom::PermissionStatus::GRANTED) {
+    DLOG(WARNING)
+        << "Received CreateAudioCapturer request from an origin that doesn't "
+           "have AUDIO_CAPTURE permission.";
+    return;
+  }
+
+  auto factory = base::ComponentContextForProcess()
+                     ->svc()
+                     ->Connect<fuchsia::media::Audio>();
+  factory->CreateAudioCapturer(std::move(request), /*loopback=*/false);
+}
diff --git a/fuchsia/engine/browser/fuchsia_media_resource_provider_impl.h b/fuchsia/engine/browser/fuchsia_media_resource_provider_impl.h
new file mode 100644
index 0000000..06888028
--- /dev/null
+++ b/fuchsia/engine/browser/fuchsia_media_resource_provider_impl.h
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FUCHSIA_ENGINE_BROWSER_FUCHSIA_MEDIA_RESOURCE_PROVIDER_IMPL_H_
+#define FUCHSIA_ENGINE_BROWSER_FUCHSIA_MEDIA_RESOURCE_PROVIDER_IMPL_H_
+
+#include <lib/fidl/cpp/interface_handle.h>
+
+#include "content/public/browser/document_service_base.h"
+#include "media/fuchsia/mojom/fuchsia_media_resource_provider.mojom.h"
+
+namespace content {
+class RenderFrameHost;
+}  // namespace content
+
+class FuchsiaMediaResourceProviderImpl final
+    : public content::DocumentServiceBase<
+          media::mojom::FuchsiaMediaResourceProvider> {
+ public:
+  ~FuchsiaMediaResourceProviderImpl() override;
+
+  FuchsiaMediaResourceProviderImpl(const FuchsiaMediaResourceProviderImpl&) =
+      delete;
+  FuchsiaMediaResourceProviderImpl& operator=(
+      const FuchsiaMediaResourceProviderImpl&) = delete;
+  FuchsiaMediaResourceProviderImpl(const FuchsiaMediaResourceProviderImpl&&) =
+      delete;
+  FuchsiaMediaResourceProviderImpl& operator=(
+      const FuchsiaMediaResourceProviderImpl&&) = delete;
+
+  static void Bind(
+      content::RenderFrameHost* frame_host,
+      mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider>
+          receiver);
+
+ private:
+  FuchsiaMediaResourceProviderImpl(
+      content::RenderFrameHost* render_frame_host,
+      mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider>
+          receiver);
+
+  // media::mojom::FuchsiaMediaResourceProvider:
+  void CreateAudioConsumer(
+      fidl::InterfaceRequest<fuchsia::media::AudioConsumer> request) override;
+  void CreateAudioCapturer(
+      fidl::InterfaceRequest<fuchsia::media::AudioCapturer> request) override;
+};
+
+#endif  // FUCHSIA_ENGINE_BROWSER_FUCHSIA_MEDIA_RESOURCE_PROVIDER_IMPL_H_
diff --git a/fuchsia/engine/browser/media_resource_provider_service.cc b/fuchsia/engine/browser/media_resource_provider_service.cc
deleted file mode 100644
index 978566f..0000000
--- a/fuchsia/engine/browser/media_resource_provider_service.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "fuchsia/engine/browser/media_resource_provider_service.h"
-
-#include <lib/fidl/cpp/interface_handle.h>
-#include <lib/sys/cpp/component_context.h>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/fuchsia/process_context.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/document_service_base.h"
-#include "content/public/browser/permission_controller.h"
-#include "content/public/browser/provision_fetcher_factory.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/storage_partition.h"
-#include "fuchsia/engine/browser/frame_impl.h"
-#include "fuchsia/engine/switches.h"
-#include "media/base/media_switches.h"
-#include "media/base/provision_fetcher.h"
-#include "media/fuchsia/cdm/service/fuchsia_cdm_manager.h"
-#include "third_party/widevine/cdm/widevine_cdm_common.h"
-
-namespace {
-
-class MediaResourceProviderImpl final
-    : public content::DocumentServiceBase<
-          media::mojom::FuchsiaMediaResourceProvider> {
- public:
-  MediaResourceProviderImpl(
-      media::FuchsiaCdmManager* cdm_manager,
-      content::RenderFrameHost* render_frame_host,
-      mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider>
-          receiver);
-  ~MediaResourceProviderImpl() override;
-
-  MediaResourceProviderImpl(const MediaResourceProviderImpl&) = delete;
-  MediaResourceProviderImpl& operator=(const MediaResourceProviderImpl&) =
-      delete;
-
-  // media::mojom::FuchsiaMediaResourceProvider implementation.
-  void CreateCdm(
-      const std::string& key_system,
-      fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
-          request) override;
-  void CreateAudioConsumer(
-      fidl::InterfaceRequest<fuchsia::media::AudioConsumer> request) override;
-  void CreateAudioCapturer(
-      fidl::InterfaceRequest<fuchsia::media::AudioCapturer> request) override;
-
- private:
-  media::FuchsiaCdmManager* const cdm_manager_;
-};
-
-MediaResourceProviderImpl::MediaResourceProviderImpl(
-    media::FuchsiaCdmManager* cdm_manager,
-    content::RenderFrameHost* render_frame_host,
-    mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider> receiver)
-    : DocumentServiceBase(render_frame_host, std::move(receiver)),
-      cdm_manager_(cdm_manager) {
-  DCHECK(cdm_manager_);
-}
-
-MediaResourceProviderImpl::~MediaResourceProviderImpl() = default;
-
-void MediaResourceProviderImpl::CreateCdm(
-    const std::string& key_system,
-    fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
-        request) {
-  scoped_refptr<network::SharedURLLoaderFactory> loader_factory =
-      render_frame_host()
-          ->GetProcess()
-          ->GetBrowserContext()
-          ->GetDefaultStoragePartition()
-          ->GetURLLoaderFactoryForBrowserProcess();
-  media::CreateFetcherCB create_fetcher_cb = base::BindRepeating(
-      &content::CreateProvisionFetcher, std::move(loader_factory));
-  cdm_manager_->CreateAndProvision(
-      key_system, origin(), std::move(create_fetcher_cb), std::move(request));
-}
-
-void MediaResourceProviderImpl::CreateAudioConsumer(
-    fidl::InterfaceRequest<fuchsia::media::AudioConsumer> request) {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableAudioOutput)) {
-    LOG(WARNING)
-        << "Could not create AudioConsumer because audio output feature flag "
-           "was not enabled.";
-    return;
-  }
-
-  auto factory = base::ComponentContextForProcess()
-                     ->svc()
-                     ->Connect<fuchsia::media::SessionAudioConsumerFactory>();
-  factory->CreateAudioConsumer(
-      FrameImpl::FromRenderFrameHost(render_frame_host())->media_session_id(),
-      std::move(request));
-}
-
-void MediaResourceProviderImpl::CreateAudioCapturer(
-    fidl::InterfaceRequest<fuchsia::media::AudioCapturer> request) {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableAudioInput)) {
-    LOG(WARNING)
-        << "Could not create AudioCapturer because audio input feature flag "
-           "was not enabled.";
-    return;
-  }
-
-  if (render_frame_host()
-          ->GetBrowserContext()
-          ->GetPermissionController()
-          ->GetPermissionStatusForFrame(
-              content::PermissionType::AUDIO_CAPTURE, render_frame_host(),
-              origin().GetURL()) != blink::mojom::PermissionStatus::GRANTED) {
-    DLOG(WARNING)
-        << "Received CreateAudioCapturer request from an origin that doesn't "
-           "have AUDIO_CAPTURE permission.";
-    return;
-  }
-
-  auto factory = base::ComponentContextForProcess()
-                     ->svc()
-                     ->Connect<fuchsia::media::Audio>();
-  factory->CreateAudioCapturer(std::move(request), /*loopback=*/false);
-}
-
-template <typename KeySystemInterface>
-fidl::InterfaceHandle<fuchsia::media::drm::KeySystem> ConnectToKeySystem() {
-  static_assert(
-      (std::is_same<KeySystemInterface, fuchsia::media::drm::Widevine>::value ||
-       std::is_same<KeySystemInterface, fuchsia::media::drm::PlayReady>::value),
-      "KeySystemInterface must be either fuchsia::media::drm::Widevine or "
-      "fuchsia::media::drm::PlayReady");
-
-  // TODO(fxbug.dev/13674): Once the key system specific protocols are turned
-  // into services, we should not need to manually force the key system specific
-  // interface into the KeySystem interface.
-  fidl::InterfaceHandle<fuchsia::media::drm::KeySystem> key_system;
-  base::ComponentContextForProcess()->svc()->Connect(key_system.NewRequest(),
-                                                     KeySystemInterface::Name_);
-  return key_system;
-}
-
-std::unique_ptr<media::FuchsiaCdmManager> CreateCdmManager() {
-  media::FuchsiaCdmManager::CreateKeySystemCallbackMap
-      create_key_system_callbacks;
-
-  const auto* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kEnableWidevine)) {
-    create_key_system_callbacks.emplace(
-        kWidevineKeySystem,
-        base::BindRepeating(
-            &ConnectToKeySystem<fuchsia::media::drm::Widevine>));
-  }
-
-  std::string playready_key_system =
-      command_line->GetSwitchValueASCII(switches::kPlayreadyKeySystem);
-  if (!playready_key_system.empty()) {
-    create_key_system_callbacks.emplace(
-        playready_key_system,
-        base::BindRepeating(
-            &ConnectToKeySystem<fuchsia::media::drm::PlayReady>));
-  }
-
-  std::string cdm_data_directory =
-      command_line->GetSwitchValueASCII(switches::kCdmDataDirectory);
-
-  absl::optional<uint64_t> cdm_data_quota_bytes;
-  if (command_line->HasSwitch(switches::kCdmDataQuotaBytes)) {
-    uint64_t value = 0;
-    CHECK(base::StringToUint64(
-        command_line->GetSwitchValueASCII(switches::kCdmDataQuotaBytes),
-        &value));
-    cdm_data_quota_bytes = value;
-  }
-
-  return std::make_unique<media::FuchsiaCdmManager>(
-      std::move(create_key_system_callbacks),
-      base::FilePath(cdm_data_directory), cdm_data_quota_bytes);
-}
-
-}  // namespace
-
-MediaResourceProviderService::MediaResourceProviderService()
-    : cdm_manager_(CreateCdmManager()) {}
-
-MediaResourceProviderService::~MediaResourceProviderService() = default;
-
-void MediaResourceProviderService::Bind(
-    content::RenderFrameHost* frame_host,
-    mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider>
-        receiver) {
-  // The object will delete itself when connection to the frame is broken.
-  new MediaResourceProviderImpl(cdm_manager_.get(), frame_host,
-                                std::move(receiver));
-}
diff --git a/fuchsia/engine/browser/media_resource_provider_service.h b/fuchsia/engine/browser/media_resource_provider_service.h
deleted file mode 100644
index 56c1ed6..0000000
--- a/fuchsia/engine/browser/media_resource_provider_service.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef FUCHSIA_ENGINE_BROWSER_MEDIA_RESOURCE_PROVIDER_SERVICE_H_
-#define FUCHSIA_ENGINE_BROWSER_MEDIA_RESOURCE_PROVIDER_SERVICE_H_
-
-#include "media/fuchsia/mojom/fuchsia_media_resource_provider.mojom.h"
-
-namespace content {
-class RenderFrameHost;
-}  // namespace content
-
-namespace media {
-class FuchsiaCdmManager;
-}  // namespace media
-
-class MediaResourceProviderService {
- public:
-  MediaResourceProviderService();
-  ~MediaResourceProviderService();
-
-  MediaResourceProviderService(const MediaResourceProviderService&) = delete;
-  MediaResourceProviderService& operator=(const MediaResourceProviderService&) =
-      delete;
-
-  void Bind(content::RenderFrameHost* frame_host,
-            mojo::PendingReceiver<media::mojom::FuchsiaMediaResourceProvider>
-                receiver);
-
- private:
-  std::unique_ptr<media::FuchsiaCdmManager> cdm_manager_;
-};
-
-#endif  // FUCHSIA_ENGINE_BROWSER_MEDIA_RESOURCE_PROVIDER_SERVICE_H_
\ No newline at end of file
diff --git a/fuchsia/engine/browser/web_engine_browser_interface_binders.cc b/fuchsia/engine/browser/web_engine_browser_interface_binders.cc
index 4446073e..197921948 100644
--- a/fuchsia/engine/browser/web_engine_browser_interface_binders.cc
+++ b/fuchsia/engine/browser/web_engine_browser_interface_binders.cc
@@ -4,14 +4,16 @@
 
 #include "fuchsia/engine/browser/web_engine_browser_interface_binders.h"
 
+#include "fuchsia/engine/browser/cdm_provider_service.h"
 #include "fuchsia/engine/browser/frame_impl.h"
-#include "fuchsia/engine/browser/media_resource_provider_service.h"
+#include "fuchsia/engine/browser/fuchsia_media_resource_provider_impl.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 
 void PopulateFuchsiaFrameBinders(
     mojo::BinderMapWithContext<content::RenderFrameHost*>* map,
-    MediaResourceProviderService* media_resource_provider_service) {
+    CdmProviderService* cdm_provider_service) {
   map->Add<media::mojom::FuchsiaMediaResourceProvider>(
-      base::BindRepeating(&MediaResourceProviderService::Bind,
-                          base::Unretained(media_resource_provider_service)));
+      base::BindRepeating(&FuchsiaMediaResourceProviderImpl::Bind));
+  map->Add<media::mojom::FuchsiaCdmProvider>(base::BindRepeating(
+      &CdmProviderService::Bind, base::Unretained(cdm_provider_service)));
 }
diff --git a/fuchsia/engine/browser/web_engine_browser_interface_binders.h b/fuchsia/engine/browser/web_engine_browser_interface_binders.h
index 62b2df8..6f29c86 100644
--- a/fuchsia/engine/browser/web_engine_browser_interface_binders.h
+++ b/fuchsia/engine/browser/web_engine_browser_interface_binders.h
@@ -11,7 +11,7 @@
 class RenderFrameHost;
 }  // namespace content
 
-class MediaResourceProviderService;
+class CdmProviderService;
 
 // PopulateFuchsiaFrameBinders() registers BrowserInterfaceBroker's
 // GetInterface() handler callbacks for Fuchsia-specific RenferFrame-scoped
@@ -19,6 +19,6 @@
 // for handling InterfaceProvider's GetInterface() calls (see crbug.com/718652).
 void PopulateFuchsiaFrameBinders(
     mojo::BinderMapWithContext<content::RenderFrameHost*>* map,
-    MediaResourceProviderService* media_resource_provider_service);
+    CdmProviderService* cdm_provider_service);
 
 #endif  // FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_BROWSER_INTERFACE_BINDERS_H_
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.cc b/fuchsia/engine/browser/web_engine_browser_main_parts.cc
index 37b4fdcc..b765103f 100644
--- a/fuchsia/engine/browser/web_engine_browser_main_parts.cc
+++ b/fuchsia/engine/browser/web_engine_browser_main_parts.cc
@@ -34,8 +34,8 @@
 #include "content/public/common/result_codes.h"
 #include "fuchsia/base/inspect.h"
 #include "fuchsia/base/legacymetrics_client.h"
+#include "fuchsia/engine/browser/cdm_provider_service.h"
 #include "fuchsia/engine/browser/context_impl.h"
-#include "fuchsia/engine/browser/media_resource_provider_service.h"
 #include "fuchsia/engine/browser/web_engine_browser_context.h"
 #include "fuchsia/engine/browser/web_engine_devtools_controller.h"
 #include "fuchsia/engine/browser/web_engine_memory_inspector.h"
@@ -188,11 +188,10 @@
   screen_ = std::move(screen_ozone);
   display::Screen::SetScreenInstance(screen_.get());
 
-  // Create the MediaResourceProviderService at startup rather than on-demand,
+  // Create the CdmProviderService at startup rather than on-demand,
   // to allow it to perform potentially expensive startup work in the
   // background.
-  media_resource_provider_service_ =
-      std::make_unique<MediaResourceProviderService>();
+  cdm_provider_service_ = std::make_unique<CdmProviderService>();
 
   // Disable RenderFrameHost's Javascript injection restrictions so that the
   // Context and Frames can implement their own JS injection policy at a higher
diff --git a/fuchsia/engine/browser/web_engine_browser_main_parts.h b/fuchsia/engine/browser/web_engine_browser_main_parts.h
index 5e2ff5c..764f0d4 100644
--- a/fuchsia/engine/browser/web_engine_browser_main_parts.h
+++ b/fuchsia/engine/browser/web_engine_browser_main_parts.h
@@ -37,7 +37,7 @@
 class ComponentInspector;
 }
 
-class MediaResourceProviderService;
+class CdmProviderService;
 class WebEngineMemoryInspector;
 
 class WEB_ENGINE_EXPORT WebEngineBrowserMainParts
@@ -55,8 +55,8 @@
   WebEngineDevToolsController* devtools_controller() const {
     return devtools_controller_.get();
   }
-  MediaResourceProviderService* media_resource_provider_service() const {
-    return media_resource_provider_service_.get();
+  CdmProviderService* cdm_provider_service() const {
+    return cdm_provider_service_.get();
   }
 
   // content::BrowserMainParts overrides.
@@ -99,8 +99,7 @@
 
   std::unique_ptr<WebEngineDevToolsController> devtools_controller_;
   std::unique_ptr<cr_fuchsia::LegacyMetricsClient> legacy_metrics_client_;
-  std::unique_ptr<MediaResourceProviderService>
-      media_resource_provider_service_;
+  std::unique_ptr<CdmProviderService> cdm_provider_service_;
 
   // Used to respond to changes to the system's current locale.
   std::unique_ptr<base::FuchsiaIntlProfileWatcher> intl_profile_watcher_;
diff --git a/fuchsia/engine/browser/web_engine_content_browser_client.cc b/fuchsia/engine/browser/web_engine_content_browser_client.cc
index 339fe63..42b73d4 100644
--- a/fuchsia/engine/browser/web_engine_content_browser_client.cc
+++ b/fuchsia/engine/browser/web_engine_content_browser_client.cc
@@ -139,8 +139,7 @@
 void WebEngineContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
     content::RenderFrameHost* render_frame_host,
     mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
-  MediaResourceProviderService* const provider =
-      main_parts_->media_resource_provider_service();
+  CdmProviderService* const provider = main_parts_->cdm_provider_service();
   DCHECK(provider);
   PopulateFuchsiaFrameBinders(map, provider);
 }
diff --git a/gin/gin_features.cc b/gin/gin_features.cc
index 24b1446b..deb6b54 100644
--- a/gin/gin_features.cc
+++ b/gin/gin_features.cc
@@ -29,7 +29,7 @@
 
 // Enables concurrent inlining in TurboFan.
 const base::Feature kV8ConcurrentInlining{"V8ConcurrentInlining",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
+                                          base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables per-context marking worklists in V8 GC.
 const base::Feature kV8PerContextMarkingWorklist{
diff --git a/google_apis/drive/DIR_METADATA b/google_apis/drive/DIR_METADATA
index 6f9a3839..d737de5 100644
--- a/google_apis/drive/DIR_METADATA
+++ b/google_apis/drive/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Platform>Apps>FileManager"
-}
\ No newline at end of file
+mixins: "//components/drive/COMMON_METADATA"
diff --git a/google_apis/test/data/drive/DIR_METADATA b/google_apis/test/data/drive/DIR_METADATA
new file mode 100644
index 0000000..780966e
--- /dev/null
+++ b/google_apis/test/data/drive/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/drive/COMMON_METADATA"
diff --git a/gpu/COMMON_METADATA b/gpu/COMMON_METADATA
new file mode 100644
index 0000000..31b4fe9
--- /dev/null
+++ b/gpu/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>GPU>Internals"
+}
\ No newline at end of file
diff --git a/gpu/DIR_METADATA b/gpu/DIR_METADATA
index ddce9625..2907f304 100644
--- a/gpu/DIR_METADATA
+++ b/gpu/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>GPU>Internals"
-}
\ No newline at end of file
+mixins: "//gpu/COMMON_METADATA"
diff --git a/headless/COMMON_METADATA b/headless/COMMON_METADATA
new file mode 100644
index 0000000..92cc67e5
--- /dev/null
+++ b/headless/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Headless"
+}
+team_email: "headless-dev@chromium.org"
\ No newline at end of file
diff --git a/headless/DIR_METADATA b/headless/DIR_METADATA
index 5eb4acf..751218a 100644
--- a/headless/DIR_METADATA
+++ b/headless/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Headless"
-}
-team_email: "headless-dev@chromium.org"
\ No newline at end of file
+mixins: "//headless/COMMON_METADATA"
diff --git a/ios/COMMON_METADATA b/ios/COMMON_METADATA
new file mode 100644
index 0000000..44dbcc2
--- /dev/null
+++ b/ios/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Mobile"
+}
+team_email: "ios-directory-owners@chromium.org"
+os: IOS
\ No newline at end of file
diff --git a/ios/DIR_METADATA b/ios/DIR_METADATA
index 00cb703..a782e3ed 100644
--- a/ios/DIR_METADATA
+++ b/ios/DIR_METADATA
@@ -6,8 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "UI>Browser>Mobile"
-}
-team_email: "ios-directory-owners@chromium.org"
-os: IOS
\ No newline at end of file
+mixins: "//ios/COMMON_METADATA"
diff --git a/ios/chrome/app/application_delegate/metric_kit_subscriber.mm b/ios/chrome/app/application_delegate/metric_kit_subscriber.mm
index f3d2001d..0b060b4 100644
--- a/ios/chrome/app/application_delegate/metric_kit_subscriber.mm
+++ b/ios/chrome/app/application_delegate/metric_kit_subscriber.mm
@@ -50,7 +50,6 @@
 
 NSString* const kEnableMetricKit = @"EnableMetricKit";
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
 void ReportExitReason(base::HistogramBase* histogram,
                       MetricKitExitReason bucket,
                       NSUInteger count) {
@@ -59,7 +58,6 @@
   }
   histogram->AddCount(bucket, count);
 }
-#endif
 
 void ReportLongDuration(const char* histogram_name,
                         NSMeasurement* measurement) {
@@ -114,7 +112,6 @@
   }
 }
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
 void WriteDiagnosticPayloads(NSArray<MXDiagnosticPayload*>* payloads)
     API_AVAILABLE(ios(14.0)) {
   NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
@@ -204,7 +201,6 @@
     SendDiagnosticPayloads(payloads);
   }
 }
-#endif
 
 }  // namespace
 
@@ -281,7 +277,6 @@
   }
 }
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
 - (void)logForegroundExit:(MXForegroundExitData*)exitData
     API_AVAILABLE(ios(14.0)) {
   base::HistogramBase* histogramUMA = base::LinearHistogram::FactoryGet(
@@ -329,7 +324,6 @@
   ReportExitReason(histogramUMA, kBackgroundTaskAssertionTimeoutExit,
                    exitData.cumulativeBackgroundTaskAssertionTimeoutExitCount);
 }
-#endif
 
 - (void)processPayload:(MXMetricPayload*)payload {
   // TODO(crbug.com/1140474): See related bug for why |bundleVersion| comes from
@@ -370,15 +364,10 @@
   [self logStartupDurationMXHistogram:histogrammedApplicationHangTime
                        toUMAHistogram:"IOS.MetricKit.ApplicationHangTime"];
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-  if (@available(iOS 14, *)) {
-    [self logForegroundExit:payload.applicationExitMetrics.foregroundExitData];
-    [self logBackgroundExit:payload.applicationExitMetrics.backgroundExitData];
-  }
-#endif
+  [self logForegroundExit:payload.applicationExitMetrics.foregroundExitData];
+  [self logBackgroundExit:payload.applicationExitMetrics.backgroundExitData];
 }
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
 - (void)didReceiveDiagnosticPayloads:(NSArray<MXDiagnosticPayload*>*)payloads
     API_AVAILABLE(ios(14.0)) {
   NSUserDefaults* standard_defaults = [NSUserDefaults standardUserDefaults];
@@ -395,6 +384,5 @@
                        sendPayloads));
   }
 }
-#endif
 
 @end
diff --git a/ios/chrome/app/application_delegate/metric_kit_subscriber_unittest.mm b/ios/chrome/app/application_delegate/metric_kit_subscriber_unittest.mm
index 3af38df..97274b9 100644
--- a/ios/chrome/app/application_delegate/metric_kit_subscriber_unittest.mm
+++ b/ios/chrome/app/application_delegate/metric_kit_subscriber_unittest.mm
@@ -114,29 +114,25 @@
     tester.ExpectBucketCount("IOS.MetricKit.TimeToFirstDraw", 5, 2);
     tester.ExpectBucketCount("IOS.MetricKit.TimeToFirstDraw", 15, 4);
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-    if (base::ios::IsRunningOnIOS14OrLater()) {
-      tester.ExpectTotalCount("IOS.MetricKit.BackgroundExitData", 71);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 2, 1);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 4, 2);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 1, 5);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 6, 6);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 8, 7);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 5, 8);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 7, 9);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 3, 10);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 9, 11);
-      tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 0, 12);
+    tester.ExpectTotalCount("IOS.MetricKit.BackgroundExitData", 71);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 2, 1);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 4, 2);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 1, 5);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 6, 6);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 8, 7);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 5, 8);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 7, 9);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 3, 10);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 9, 11);
+    tester.ExpectBucketCount("IOS.MetricKit.BackgroundExitData", 0, 12);
 
-      tester.ExpectTotalCount("IOS.MetricKit.ForegroundExitData", 95);
-      tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 7, 13);
-      tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 1, 14);
-      tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 4, 15);
-      tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 0, 16);
-      tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 8, 18);
-      tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 2, 19);
-    }
-#endif
+    tester.ExpectTotalCount("IOS.MetricKit.ForegroundExitData", 95);
+    tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 7, 13);
+    tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 1, 14);
+    tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 4, 15);
+    tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 0, 16);
+    tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 8, 18);
+    tester.ExpectBucketCount("IOS.MetricKit.ForegroundExitData", 2, 19);
   }
 }
 
@@ -172,36 +168,31 @@
   }
 }
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
 TEST_F(MetricKitSubscriberTest, SaveDiagnosticReport) {
-  if (@available(iOS 14, *)) {
-    id mock_report = OCMClassMock([MXDiagnosticPayload class]);
-    NSDate* date = [NSDate date];
-    std::string file_data("report content");
-    NSData* data = [NSData dataWithBytes:file_data.c_str()
-                                  length:file_data.size()];
-    NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
-    [formatter setDateFormat:@"yyyyMMdd_HHmmss"];
-    [formatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
-    NSString* file_name =
-        [NSString stringWithFormat:@"Diagnostic-%@.json",
-                                   [formatter stringFromDate:date]];
+  id mock_report = OCMClassMock([MXDiagnosticPayload class]);
+  NSDate* date = [NSDate date];
+  std::string file_data("report content");
+  NSData* data = [NSData dataWithBytes:file_data.c_str()
+                                length:file_data.size()];
+  NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
+  [formatter setDateFormat:@"yyyyMMdd_HHmmss"];
+  [formatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
+  NSString* file_name = [NSString
+      stringWithFormat:@"Diagnostic-%@.json", [formatter stringFromDate:date]];
 
-    base::FilePath file_path =
-        MetricKitReportDirectory().Append(base::SysNSStringToUTF8(file_name));
-    OCMStub([mock_report timeStampEnd]).andReturn(date);
-    OCMStub([mock_report JSONRepresentation]).andReturn(data);
-    NSArray* array = @[ mock_report ];
-    [[MetricKitSubscriber sharedInstance] didReceiveDiagnosticPayloads:array];
+  base::FilePath file_path =
+      MetricKitReportDirectory().Append(base::SysNSStringToUTF8(file_name));
+  OCMStub([mock_report timeStampEnd]).andReturn(date);
+  OCMStub([mock_report JSONRepresentation]).andReturn(data);
+  NSArray* array = @[ mock_report ];
+  [[MetricKitSubscriber sharedInstance] didReceiveDiagnosticPayloads:array];
 
-    EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
-        base::test::ios::kWaitForFileOperationTimeout, ^bool() {
-          base::RunLoop().RunUntilIdle();
-          return base::PathExists(file_path);
-        }));
-    std::string content;
-    base::ReadFileToString(file_path, &content);
-    EXPECT_EQ(content, file_data);
-  }
+  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForFileOperationTimeout, ^bool() {
+        base::RunLoop().RunUntilIdle();
+        return base::PathExists(file_path);
+      }));
+  std::string content;
+  base::ReadFileToString(file_path, &content);
+  EXPECT_EQ(content, file_data);
 }
-#endif
diff --git a/ios/chrome/app/application_delegate/metrics_mediator.mm b/ios/chrome/app/application_delegate/metrics_mediator.mm
index 636c297..49904312 100644
--- a/ios/chrome/app/application_delegate/metrics_mediator.mm
+++ b/ios/chrome/app/application_delegate/metrics_mediator.mm
@@ -276,9 +276,8 @@
   }
 
 #if BUILDFLAG(ENABLE_WIDGET_KIT_EXTENSION)
-  if (@available(iOS 14, *)) {
-    [WidgetMetricsUtil logInstalledWidgets];
-  }
+  [WidgetMetricsUtil logInstalledWidgets];
+
 #endif
 
   // Create the first user action recorder and schedule a task to expire it
diff --git a/ios/chrome/app/application_delegate/mock_metrickit_metric_payload.mm b/ios/chrome/app/application_delegate/mock_metrickit_metric_payload.mm
index 28856de..a6fe398 100644
--- a/ios/chrome/app/application_delegate/mock_metrickit_metric_payload.mm
+++ b/ios/chrome/app/application_delegate/mock_metrickit_metric_payload.mm
@@ -136,7 +136,6 @@
   return responsiveness;
 }
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
 id MockMXAppExitMetric(NSDictionary* dictionary) API_AVAILABLE(ios(14.0)) {
   id app_exit_metric = OCMClassMock([MXAppExitMetric class]);
   id foreground = OCMClassMock([MXForegroundExitData class]);
@@ -198,7 +197,6 @@
 
   return app_exit_metric;
 }
-#endif
 
 id MockMetricPayload(NSDictionary* dictionary) {
   id mock_report = OCMClassMock([MXMetricPayload class]);
@@ -230,16 +228,12 @@
     OCMStub([mock_report applicationResponsivenessMetrics])
         .andReturn(responsiveness_metrics);
   }
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-  if (@available(iOS 14, *)) {
-    NSDictionary* exit_metrics_dict =
-        [dictionary objectForKey:@"applicationExitMetrics"];
-    if (exit_metrics_dict) {
-      id exit_metrics = MockMXAppExitMetric(exit_metrics_dict);
-      OCMStub([mock_report applicationExitMetrics]).andReturn(exit_metrics);
-    }
+  NSDictionary* exit_metrics_dict =
+      [dictionary objectForKey:@"applicationExitMetrics"];
+  if (exit_metrics_dict) {
+    id exit_metrics = MockMXAppExitMetric(exit_metrics_dict);
+    OCMStub([mock_report applicationExitMetrics]).andReturn(exit_metrics);
   }
-#endif
 
   OCMStub([mock_report metaData]).andReturn(MockMXMetadata());
   return mock_report;
diff --git a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
index fb5717d..f8e763b 100644
--- a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
+++ b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
@@ -160,9 +160,7 @@
 
 #if BUILDFLAG(IOS_SCREEN_TIME_ENABLED)
   if (IsScreenTimeIntegrationEnabled()) {
-    if (@available(iOS 14, *)) {
-      ScreenTimeHistoryDeleterFactory::GetInstance();
-    }
+    ScreenTimeHistoryDeleterFactory::GetInstance();
   }
 #endif
 }
diff --git a/ios/chrome/browser/component_updater/DIR_METADATA b/ios/chrome/browser/component_updater/DIR_METADATA
index ac9279c5..3e02530a 100644
--- a/ios/chrome/browser/component_updater/DIR_METADATA
+++ b/ios/chrome/browser/component_updater/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Installer>Components"
-}
-team_email: "chrome-updates-dev@chromium.org"
\ No newline at end of file
+mixins: "//chrome/browser/component_updater/COMMON_METADATA"
diff --git a/ios/chrome/browser/gcm/DIR_METADATA b/ios/chrome/browser/gcm/DIR_METADATA
index 428baeb..b43d56c 100644
--- a/ios/chrome/browser/gcm/DIR_METADATA
+++ b/ios/chrome/browser/gcm/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Services>CloudMessaging"
-}
\ No newline at end of file
+mixins: "//chrome/browser/gcm/COMMON_METADATA"
diff --git a/ios/chrome/browser/invalidation/DIR_METADATA b/ios/chrome/browser/invalidation/DIR_METADATA
index 47eb7b76..d9c51a7 100644
--- a/ios/chrome/browser/invalidation/DIR_METADATA
+++ b/ios/chrome/browser/invalidation/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Services>Invalidation"
-}
\ No newline at end of file
+mixins: "//components/invalidation/COMMON_METADATA"
diff --git a/ios/chrome/browser/language/DIR_METADATA b/ios/chrome/browser/language/DIR_METADATA
new file mode 100644
index 0000000..83bdb5a
--- /dev/null
+++ b/ios/chrome/browser/language/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/language/COMMON_METADATA"
diff --git a/ios/chrome/browser/ntp_tiles/DIR_METADATA b/ios/chrome/browser/ntp_tiles/DIR_METADATA
new file mode 100644
index 0000000..390105a
--- /dev/null
+++ b/ios/chrome/browser/ntp_tiles/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/ntp_tiles/COMMON_METADATA"
diff --git a/ios/chrome/browser/optimization_guide/BUILD.gn b/ios/chrome/browser/optimization_guide/BUILD.gn
index 5071c66..3d4daca 100644
--- a/ios/chrome/browser/optimization_guide/BUILD.gn
+++ b/ios/chrome/browser/optimization_guide/BUILD.gn
@@ -67,58 +67,3 @@
     "//testing/gtest",
   ]
 }
-
-source_set("eg_app_support+eg2") {
-  defines = [ "CHROME_EARL_GREY_2" ]
-  configs += [
-    "//build/config/compiler:enable_arc",
-    "//build/config/ios:xctest_config",
-  ]
-  testonly = true
-  sources = [
-    "optimization_guide_test_app_interface.h",
-    "optimization_guide_test_app_interface.mm",
-  ]
-  deps = [
-    "//base",
-    "//base/test:test_support",
-    "//components/optimization_guide/core",
-    "//components/optimization_guide/core:test_support",
-    "//components/optimization_guide/proto:optimization_guide_proto",
-    "//ios/chrome/browser",
-    "//ios/chrome/browser/optimization_guide",
-    "//ios/chrome/test/app:test_support",
-  ]
-}
-
-source_set("eg_test_support+eg2") {
-  defines = [ "CHROME_EARL_GREY_2" ]
-  configs += [
-    "//build/config/compiler:enable_arc",
-    "//build/config/ios:xctest_config",
-  ]
-  testonly = true
-  sources = [ "optimization_guide_test_app_interface.h" ]
-  deps = [ "//components/optimization_guide/proto:optimization_guide_proto" ]
-}
-
-source_set("eg2_tests") {
-  defines = [ "CHROME_EARL_GREY_2" ]
-  configs += [
-    "//build/config/compiler:enable_arc",
-    "//build/config/ios:xctest_config",
-  ]
-  testonly = true
-  sources = [ "hints_fetcher_egtest.mm" ]
-  deps = [
-    ":eg_test_support+eg2",
-    "//base/test:test_support",
-    "//components/optimization_guide/core:eg_test_support+eg2",
-    "//ios/chrome/browser/metrics:eg_test_support+eg2",
-    "//ios/chrome/test/earl_grey:eg_test_support+eg2",
-    "//ios/testing/earl_grey:eg_test_support+eg2",
-    "//ios/third_party/earl_grey2:test_lib",
-    "//net:test_support",
-  ]
-  frameworks = [ "UIKit.framework" ]
-}
diff --git a/ios/chrome/browser/optimization_guide/DIR_METADATA b/ios/chrome/browser/optimization_guide/DIR_METADATA
index fb4428a..0a043d53 100644
--- a/ios/chrome/browser/optimization_guide/DIR_METADATA
+++ b/ios/chrome/browser/optimization_guide/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>OptimizationGuide"
-}
+mixins: "//components/optimization_guide/COMMON_METADATA"
diff --git a/ios/chrome/browser/optimization_guide/hints_fetcher_egtest.mm b/ios/chrome/browser/optimization_guide/hints_fetcher_egtest.mm
deleted file mode 100644
index 6247429..0000000
--- a/ios/chrome/browser/optimization_guide/hints_fetcher_egtest.mm
+++ /dev/null
@@ -1,235 +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 "base/containers/flat_set.h"
-#import "base/strings/sys_string_conversions.h"
-#import "base/test/ios/wait_util.h"
-#import "components/optimization_guide/core/optimization_guide_enums.h"
-#import "components/optimization_guide/core/optimization_guide_switches.h"
-#import "components/optimization_guide/core/optimization_guide_test_util.h"
-#import "ios/chrome/browser/metrics/metrics_app_interface.h"
-#import "ios/chrome/browser/optimization_guide/optimization_guide_test_app_interface.h"
-#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
-#import "ios/chrome/test/earl_grey/chrome_test_case.h"
-#import "ios/testing/earl_grey/app_launch_manager.h"
-#import "ios/testing/earl_grey/earl_grey_test.h"
-#import "net/test/embedded_test_server/embedded_test_server.h"
-#import "net/test/embedded_test_server/http_request.h"
-#import "net/test/embedded_test_server/http_response.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-#if defined(CHROME_EARL_GREY_2)
-// TODO(crbug.com/1015113): The EG2 macro is breaking indexing for some reason
-// without the trailing semicolon.  For now, disable the extra semi warning
-// so Xcode indexing works for the egtest.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wc++98-compat-extra-semi"
-GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(OptimizationGuideTestAppInterface);
-#pragma clang diagnostic pop
-#endif  // defined(CHROME_EARL_GREY_2)
-
-namespace {
-
-void AppendSwitch(std::vector<std::string>* args,
-                  const std::string& cli_switch) {
-  args->push_back(std::string("--") + cli_switch);
-}
-
-// Handler for the hints server.
-std::unique_ptr<net::test_server::HttpResponse> HandleGetHintsRequest(
-    const std::string& origin_host,
-    const optimization_guide::HintsFetcherRemoteResponseType& response_type,
-    size_t& count_hints_requests_received,
-    const net::test_server::HttpRequest& request) {
-  // Fail the response if it does not have the expected attributes.
-  if (request.method != net::test_server::METHOD_POST)
-    return nullptr;
-  optimization_guide::proto::GetHintsRequest hints_request;
-  if (!hints_request.ParseFromString(request.content))
-    return nullptr;
-  if (hints_request.hosts().empty() && hints_request.urls().empty())
-    return nullptr;
-  // TODO(crbug.com/1015113): Verify that hosts count in the hint does not
-  // exceed MaxHostsForOptimizationGuideServiceHintsFetch()
-
-  count_hints_requests_received++;
-
-  auto response = std::make_unique<net::test_server::BasicHttpResponse>();
-
-  if (response_type ==
-      optimization_guide::HintsFetcherRemoteResponseType::kSuccessful) {
-    response->set_code(net::HTTP_OK);
-
-    optimization_guide::proto::GetHintsResponse get_hints_response;
-
-    optimization_guide::proto::Hint* hint = get_hints_response.add_hints();
-    hint->set_key_representation(optimization_guide::proto::HOST);
-    hint->set_key(origin_host);
-    optimization_guide::proto::PageHint* page_hint = hint->add_page_hints();
-    page_hint->set_page_pattern("page pattern");
-
-    std::string serialized_request;
-    get_hints_response.SerializeToString(&serialized_request);
-    response->set_content(serialized_request);
-  } else if (response_type ==
-             optimization_guide::HintsFetcherRemoteResponseType::
-                 kUnsuccessful) {
-    response->set_code(net::HTTP_NOT_FOUND);
-
-  } else if (response_type ==
-             optimization_guide::HintsFetcherRemoteResponseType::kMalformed) {
-    response->set_code(net::HTTP_OK);
-
-    std::string serialized_request = "Not a proto";
-    response->set_content(serialized_request);
-  } else if (response_type ==
-             optimization_guide::HintsFetcherRemoteResponseType::kHung) {
-    return std::make_unique<net::test_server::HungResponse>();
-  } else {
-    NOTREACHED();
-  }
-
-  return std::move(response);
-}
-
-}  // namespace
-
-@interface HintsFetcherEGTestCase : ChromeTestCase {
-  std::unique_ptr<net::EmbeddedTestServer> origin_server;
-}
-@property optimization_guide::HintsFetcherRemoteResponseType response_type;
-
-// Count of hints requests received so far by the hints server
-// |self.testServer|.
-@property size_t count_hints_requests_received;
-
-// Set of hosts and URLs for which a hints request is
-// expected to arrive. This set is verified to match with the set of hosts and
-// URLs present in the hints request. If null, then the verification is not
-// done.
-
-@property absl::optional<base::flat_set<std::string>>
-    expect_hints_request_for_hosts_and_urls_;
-@end
-
-@implementation HintsFetcherEGTestCase
-@synthesize count_hints_requests_received = _count_hints_requests_received;
-@synthesize response_type = _response_type;
-
-#pragma mark - Helpers
-
-- (AppLaunchConfiguration)appConfigurationForTestCase {
-  AppLaunchConfiguration config;
-  // TODO(crbug.com/1015113): Convert to directly use the kOptimizationHints
-  // feature.
-  config.additional_args.push_back("--enable-features=OptimizationHints");
-  AppendSwitch(&config.additional_args,
-               optimization_guide::switches::kPurgeHintsStore);
-  AppendSwitch(
-      &config.additional_args,
-      optimization_guide::switches::kDisableCheckingUserPermissionsForTesting);
-  AppendSwitch(&config.additional_args,
-               optimization_guide::switches::kFetchHintsOverrideTimer);
-  AppendSwitch(&config.additional_args,
-               optimization_guide::switches::kDebugLoggingEnabled);
-  config.additional_args.push_back("--force-variation-ids=4");
-  return config;
-}
-
-- (void)setUp {
-  [super setUp];
-  self.count_hints_requests_received = 0;
-  self.response_type =
-      optimization_guide::HintsFetcherRemoteResponseType::kSuccessful;
-
-  origin_server = std::make_unique<net::EmbeddedTestServer>(
-      net::EmbeddedTestServer::TYPE_HTTPS);
-  GREYAssertTrue(origin_server->Start(),
-                 @"Origin test server failed to start.");
-
-  // The tests use |self.testServer| as the optimization guide hints server.
-  self.testServer->RegisterRequestHandler(base::BindRepeating(
-      &HandleGetHintsRequest, origin_server->base_url().host(),
-      std::cref(_response_type), std::ref(_count_hints_requests_received)));
-  GREYAssertTrue(self.testServer->Start(), @"Hints server failed to start.");
-
-  GREYAssertNil([MetricsAppInterface setupHistogramTester],
-                @"Failed to set up histogram tester.");
-  [MetricsAppInterface overrideMetricsAndCrashReportingForTesting];
-
-  NSString* hints_server_host =
-      base::SysUTF8ToNSString(self.testServer->base_url().spec());
-
-  [OptimizationGuideTestAppInterface setGetHintsURL:hints_server_host];
-  [OptimizationGuideTestAppInterface
-      setComponentUpdateHints:base::SysUTF8ToNSString(
-                                  origin_server->base_url().host())];
-  [OptimizationGuideTestAppInterface
-      registerOptimizationType:optimization_guide::proto::OptimizationType::
-                                   NOSCRIPT];
-}
-
-- (void)tearDown {
-  [MetricsAppInterface stopOverridingMetricsAndCrashReportingForTesting];
-  GREYAssertNil([MetricsAppInterface releaseHistogramTester],
-                @"Failed to release histogram tester.");
-  [super tearDown];
-}
-
-#pragma mark - Tests
-
-// The tests in this file should correspond to the tests in
-// //chrome/browser/optimization_guide/hints_fetcher_browsertest.cc.
-// TODO(crbug.com/1241158): Add more EG2 tests so that the different pieces of
-// optimization guide hints fetching are integration tested. This includes tests
-// that verify hints fetcher failure cases, fetching of hints for multiple open
-// tabs at startup, hints are cleared when browsing history is cleared, etc.
-
-- (void)testHintsFetchBasic {
-  [ChromeEarlGrey loadURL:GURL("https://foo.com/test")];
-  // Wait for the hints to be served.
-  GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(
-                 base::test::ios::kWaitForPageLoadTimeout,
-                 ^{
-                   return self.count_hints_requests_received == 1;
-                 }),
-             @"Hints server did not receive hints request");
-  GREYAssertNil(
-      [MetricsAppInterface
-          expectUniqueSampleWithCount:1
-                            forBucket:
-                                static_cast<int>(
-                                    optimization_guide::
-                                        RaceNavigationFetchAttemptStatus::
-                                            kRaceNavigationFetchHostAndURL)
-                         forHistogram:@"OptimizationGuide.HintsManager."
-                                      @"RaceNavigationFetchAttemptStatus"],
-      @"Host and URL race fetch histogram missing");
-  GREYAssertNil(
-      [MetricsAppInterface
-          expectUniqueSampleWithCount:1
-                            forBucket:static_cast<int>(net::HTTP_OK)
-                         forHistogram:@"OptimizationGuide.HintsFetcher."
-                                      @"GetHintsRequest.Status"],
-      @"hints request histogram missing");
-  GREYAssertNil(
-      [MetricsAppInterface
-          expectUniqueSampleWithCount:1
-                            forBucket:static_cast<int>(net::OK)
-                         forHistogram:@"OptimizationGuide.HintsFetcher."
-                                      @"GetHintsRequest.NetErrorCode"],
-      @"hints request histogram missing");
-  GREYAssertNil(
-      [MetricsAppInterface
-          expectUniqueSampleWithCount:1
-                            forBucket:1
-                         forHistogram:@"OptimizationGuide.HintsFetcher."
-                                      @"GetHintsRequest.HintCount"],
-      @"hints request histogram missing");
-  [ChromeEarlGrey closeAllTabs];
-}
-
-@end
diff --git a/ios/chrome/browser/optimization_guide/optimization_guide_service.h b/ios/chrome/browser/optimization_guide/optimization_guide_service.h
index 251483f..f024994 100644
--- a/ios/chrome/browser/optimization_guide/optimization_guide_service.h
+++ b/ios/chrome/browser/optimization_guide/optimization_guide_service.h
@@ -73,7 +73,6 @@
  private:
   friend class OptimizationGuideServiceTest;
   friend class OptimizationGuideTabHelper;
-  friend class OptimizationGuideTestAppInterfaceWrapper;
 
   // Notifies |hints_manager_| that the navigation associated with
   // |navigation_data| has started or redirected.
diff --git a/ios/chrome/browser/optimization_guide/optimization_guide_test_app_interface.h b/ios/chrome/browser/optimization_guide/optimization_guide_test_app_interface.h
deleted file mode 100644
index 06c0065..0000000
--- a/ios/chrome/browser/optimization_guide/optimization_guide_test_app_interface.h
+++ /dev/null
@@ -1,32 +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 IOS_CHROME_BROWSER_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_TEST_APP_INTERFACE_H_
-#define IOS_CHROME_BROWSER_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_TEST_APP_INTERFACE_H_
-
-#import <Foundation/Foundation.h>
-
-#include "components/optimization_guide/proto/hints.pb.h"
-
-class OptimizationGuideTestAppInterfaceWrapper {
- public:
-  static void SetOptimizationGuideServiceUrl(NSString* url);
-};
-
-// The app interface for optimization guide EG2 tests.
-@interface OptimizationGuideTestAppInterface : NSObject
-
-// Sets the hints server URL used by the optimization guide infra.
-+ (void)setGetHintsURL:(NSString*)url;
-
-// Sets up component updates hints for testing.
-+ (void)setComponentUpdateHints:(NSString*)url;
-
-// Registers the optimization type for which hints should be fetched for.
-+ (void)registerOptimizationType:
-    (optimization_guide::proto::OptimizationType)type;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_TEST_APP_INTERFACE_H_
diff --git a/ios/chrome/browser/optimization_guide/optimization_guide_test_app_interface.mm b/ios/chrome/browser/optimization_guide/optimization_guide_test_app_interface.mm
deleted file mode 100644
index e905c6d..0000000
--- a/ios/chrome/browser/optimization_guide/optimization_guide_test_app_interface.mm
+++ /dev/null
@@ -1,73 +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 "ios/chrome/browser/optimization_guide/optimization_guide_test_app_interface.h"
-
-#include <vector>
-
-#import "base/command_line.h"
-#import "base/logging.h"
-#import "base/strings/sys_string_conversions.h"
-#import "components/optimization_guide/core/hints_component_info.h"
-#import "components/optimization_guide/core/hints_component_util.h"
-#import "components/optimization_guide/core/hints_fetcher_factory.h"
-#import "components/optimization_guide/core/hints_manager.h"
-#import "components/optimization_guide/core/optimization_guide_switches.h"
-#import "components/optimization_guide/core/optimization_hints_component_update_listener.h"
-#import "components/optimization_guide/core/test_hints_component_creator.h"
-#import "components/optimization_guide/proto/hints.pb.h"
-#import "ios/chrome/browser/optimization_guide/optimization_guide_service.h"
-#import "ios/chrome/browser/optimization_guide/optimization_guide_service_factory.h"
-#import "ios/chrome/test/app/chrome_test_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-void OptimizationGuideTestAppInterfaceWrapper::SetOptimizationGuideServiceUrl(
-    NSString* url) {
-  OptimizationGuideService* service =
-      OptimizationGuideServiceFactory::GetForBrowserState(
-          chrome_test_util::GetOriginalBrowserState());
-  GURL gurl(base::SysNSStringToUTF8(url));
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      optimization_guide::switches::kOptimizationGuideServiceGetHintsURL,
-      gurl.spec());
-  service->GetHintsManager()
-      ->GetHintsFetcherFactory()
-      ->OverrideOptimizationGuideServiceUrlForTesting(gurl);
-}
-
-optimization_guide::testing::TestHintsComponentCreator
-    test_hints_component_creator;
-
-@implementation OptimizationGuideTestAppInterface
-
-+ (void)setGetHintsURL:(NSString*)url {
-  OptimizationGuideTestAppInterfaceWrapper::SetOptimizationGuideServiceUrl(url);
-}
-
-+ (void)setComponentUpdateHints:(NSString*)url {
-  const optimization_guide::HintsComponentInfo& component_info =
-      test_hints_component_creator.CreateHintsComponentInfoWithPageHints(
-          optimization_guide::proto::NOSCRIPT, {base::SysNSStringToUTF8(url)},
-          "*");
-
-  // Use the max int as version in components info, so that it will pick up and
-  // update hints from test component info.
-  optimization_guide::HintsComponentInfo new_component_info(
-      base::Version({UINT32_MAX}), component_info.path);
-  optimization_guide::OptimizationHintsComponentUpdateListener::GetInstance()
-      ->MaybeUpdateHintsComponent(new_component_info);
-}
-
-+ (void)registerOptimizationType:
-    (optimization_guide::proto::OptimizationType)type {
-  OptimizationGuideService* service =
-      OptimizationGuideServiceFactory::GetForBrowserState(
-          chrome_test_util::GetOriginalBrowserState());
-  service->RegisterOptimizationTypes({type});
-}
-
-@end
diff --git a/ios/chrome/browser/policy/DIR_METADATA b/ios/chrome/browser/policy/DIR_METADATA
index a33911f..cc01422 100644
--- a/ios/chrome/browser/policy/DIR_METADATA
+++ b/ios/chrome/browser/policy/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Enterprise"
-}
+mixins: "//components/policy/COMMON_METADATA"
diff --git a/ios/chrome/browser/safe_browsing/password_protection_egtest.mm b/ios/chrome/browser/safe_browsing/password_protection_egtest.mm
index e398f4d4..71780fb6 100644
--- a/ios/chrome/browser/safe_browsing/password_protection_egtest.mm
+++ b/ios/chrome/browser/safe_browsing/password_protection_egtest.mm
@@ -123,9 +123,6 @@
 // TODO(crbug.com/1221635) This fails on iPad 14.4 and iPhone 14.5+
 - (void)DISABLED_testPasswordReuseDetectionWarning {
   // PhishGuard is only available on iOS 14.0 or above.
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [ChromeEarlGrey loadURL:_phishingURL];
   [ChromeEarlGrey waitForWebStateContainingText:kInputPage];
@@ -141,9 +138,6 @@
 // TODO(crbug.com/1213616) Test is flaky.
 - (void)DISABLED_testPasswordProtectionNotShownForAllowListedURL {
   // PhishGuard is only available on iOS 14.0 or above.
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [ChromeEarlGrey loadURL:_allowlistedURL];
   [ChromeEarlGrey waitForWebStateContainingText:kInputPage];
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_egtest.mm b/ios/chrome/browser/safe_browsing/safe_browsing_egtest.mm
index 44ec6bb..40686da 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_egtest.mm
+++ b/ios/chrome/browser/safe_browsing/safe_browsing_egtest.mm
@@ -292,14 +292,6 @@
 // Tests expanding the details on a malware warning, proceeding past the
 // warning, and navigating back/forward to the unsafe page.
 - (void)testProceedingPastMalwareWarning {
-  if (@available(iOS 14, *)) {
-  } else {
-    if (@available(iOS 13, *)) {
-      // TODO(crbug.com/1156574): This test is failing on iOS 13, not sure why.
-      EARL_GREY_TEST_DISABLED(@"Disabled on iOS 13 as it is failing.");
-    }
-  }
-
   [ChromeEarlGrey loadURL:_safeURL1];
   [ChromeEarlGrey waitForWebStateContainingText:_safeContent1];
 
@@ -344,14 +336,6 @@
 // Tests expanding the details on a malware warning, proceeding past the
 // warning, and navigating back/forward to the unsafe page, in incognito mode.
 - (void)testProceedingPastMalwareWarningInIncognito {
-  if (@available(iOS 14, *)) {
-  } else {
-    if (@available(iOS 13, *)) {
-      // TODO(crbug.com/1156574): This test is failing on iOS 13, not sure why.
-      EARL_GREY_TEST_DISABLED(@"Disabled on iOS 13 as it is failing.");
-    }
-  }
-
   [ChromeEarlGrey openNewIncognitoTab];
   [ChromeEarlGrey loadURL:_safeURL1];
   [ChromeEarlGrey waitForWebStateContainingText:_safeContent1];
diff --git a/ios/chrome/browser/screen_time/features.mm b/ios/chrome/browser/screen_time/features.mm
index 425d21e..ff2f094 100644
--- a/ios/chrome/browser/screen_time/features.mm
+++ b/ios/chrome/browser/screen_time/features.mm
@@ -12,8 +12,5 @@
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
 bool IsScreenTimeIntegrationEnabled() {
-  if (@available(iOS 14, *)) {
-    return base::FeatureList::IsEnabled(kScreenTimeIntegration);
-  }
-  return false;
+  return base::FeatureList::IsEnabled(kScreenTimeIntegration);
 }
diff --git a/ios/chrome/browser/screenshot/screenshot_delegate_unittest.mm b/ios/chrome/browser/screenshot/screenshot_delegate_unittest.mm
index 446cfa7..5521f8f696 100644
--- a/ios/chrome/browser/screenshot/screenshot_delegate_unittest.mm
+++ b/ios/chrome/browser/screenshot/screenshot_delegate_unittest.mm
@@ -49,112 +49,104 @@
 // be set and that data can be generated from it.
 TEST_F(ScreenshotDelegateTest, ScreenshotService) {
   // Expected: Empty NSData.
-  if (@available(iOS 14, *)) {
-    auto web_state = std::make_unique<web::FakeWebState>();
-    TestBrowser browser;
+  auto web_state = std::make_unique<web::FakeWebState>();
+  TestBrowser browser;
 
-    CRWWebViewScrollViewProxy* scroll_view_proxy =
-        [[CRWWebViewScrollViewProxy alloc] init];
-    UIScrollView* scroll_view = [[UIScrollView alloc] init];
-    [scroll_view_proxy setScrollView:scroll_view];
-    id web_view_proxy_mock = OCMProtocolMock(@protocol(CRWWebViewProxy));
-    [[[web_view_proxy_mock stub] andReturn:scroll_view_proxy] scrollViewProxy];
-    web_state->SetWebViewProxy(web_view_proxy_mock);
+  CRWWebViewScrollViewProxy* scroll_view_proxy =
+      [[CRWWebViewScrollViewProxy alloc] init];
+  UIScrollView* scroll_view = [[UIScrollView alloc] init];
+  [scroll_view_proxy setScrollView:scroll_view];
+  id web_view_proxy_mock = OCMProtocolMock(@protocol(CRWWebViewProxy));
+  [[[web_view_proxy_mock stub] andReturn:scroll_view_proxy] scrollViewProxy];
+  web_state->SetWebViewProxy(web_view_proxy_mock);
 
-    // Fake scroll_view contentOffset, contentSize and frame.
-    CGPoint content_offset = CGPointMake(10.0, 15.0);
-    CGSize content_size = CGSizeMake(425, 4000);
-    CGRect frame = CGRectMake(0, 0, 375, 812);
-    scroll_view.contentOffset = content_offset;
-    scroll_view.contentSize = content_size;
-    scroll_view.frame = frame;
+  // Fake scroll_view contentOffset, contentSize and frame.
+  CGPoint content_offset = CGPointMake(10.0, 15.0);
+  CGSize content_size = CGSizeMake(425, 4000);
+  CGRect frame = CGRectMake(0, 0, 375, 812);
+  scroll_view.contentOffset = content_offset;
+  scroll_view.contentSize = content_size;
+  scroll_view.frame = frame;
 
-    CGRect expected_rect_in_page = CGRectZero;
+  CGRect expected_rect_in_page = CGRectZero;
 
-    if (@available(iOS 14, *)) {
-      expected_rect_in_page =
-          CGRectMake(content_offset.x,
-                     content_size.height - frame.size.height - content_offset.y,
-                     frame.size.width, frame.size.height);
-    }
+  expected_rect_in_page =
+      CGRectMake(content_offset.x,
+                 content_size.height - frame.size.height - content_offset.y,
+                 frame.size.width, frame.size.height);
 
-    // Insert the web_state into the Browser.
-    int insertion_index = browser.GetWebStateList()->InsertWebState(
-        WebStateList::kInvalidIndex, std::move(web_state),
-        WebStateList::INSERT_NO_FLAGS, WebStateOpener());
-    browser.GetWebStateList()->ActivateWebStateAt(insertion_index);
+  // Insert the web_state into the Browser.
+  int insertion_index = browser.GetWebStateList()->InsertWebState(
+      WebStateList::kInvalidIndex, std::move(web_state),
+      WebStateList::INSERT_NO_FLAGS, WebStateOpener());
+  browser.GetWebStateList()->ActivateWebStateAt(insertion_index);
 
-    // Add the Browser to StubBrowserInterface.
-    browser_interface_.browser = &browser;
+  // Add the Browser to StubBrowserInterface.
+  browser_interface_.browser = &browser;
 
-    // Add the StubBrowserInterface to StubBrowserInterfaceProvider.
-    browser_interface_provider_.currentInterface = browser_interface_;
+  // Add the StubBrowserInterface to StubBrowserInterfaceProvider.
+  browser_interface_provider_.currentInterface = browser_interface_;
 
-    createScreenshotDelegate();
+  createScreenshotDelegate();
 
-    __block int nbCalls = 0;
-    [screenshotDelegate_ screenshotService:screenshot_service_
-        generatePDFRepresentationWithCompletion:^(NSData* PDFData,
-                                                  NSInteger indexOfCurrentPage,
-                                                  CGRect rectInCurrentPage) {
-          EXPECT_TRUE(PDFData);
-          EXPECT_TRUE(
-              CGRectEqualToRect(expected_rect_in_page, rectInCurrentPage));
-          ++nbCalls;
-        }];
+  __block int nbCalls = 0;
+  [screenshotDelegate_ screenshotService:screenshot_service_
+      generatePDFRepresentationWithCompletion:^(NSData* PDFData,
+                                                NSInteger indexOfCurrentPage,
+                                                CGRect rectInCurrentPage) {
+        EXPECT_TRUE(PDFData);
+        EXPECT_TRUE(
+            CGRectEqualToRect(expected_rect_in_page, rectInCurrentPage));
+        ++nbCalls;
+      }];
 
-    EXPECT_EQ(1, nbCalls);
-  }
+  EXPECT_EQ(1, nbCalls);
 }
 
 // Tests that when ScreenshotDelegate's browserInterfaceProvider has a nil
 // Browser screenshotService will return nil.
 TEST_F(ScreenshotDelegateTest, NilBrowser) {
   // Expected: nil NSData.
-  if (@available(iOS 14, *)) {
-    // Add the StubBrowserInterface with no set Browser to
-    // StubBrowserInterfaceProvider.
-    browser_interface_provider_.currentInterface = browser_interface_;
+  // Add the StubBrowserInterface with no set Browser to
+  // StubBrowserInterfaceProvider.
+  browser_interface_provider_.currentInterface = browser_interface_;
 
-    createScreenshotDelegate();
+  createScreenshotDelegate();
 
-    __block bool callback_ran = false;
-    [screenshotDelegate_ screenshotService:screenshot_service_
-        generatePDFRepresentationWithCompletion:^(NSData* PDFData,
-                                                  NSInteger indexOfCurrentPage,
-                                                  CGRect rectInCurrentPage) {
-          EXPECT_FALSE(PDFData);
-          callback_ran = true;
-        }];
+  __block bool callback_ran = false;
+  [screenshotDelegate_ screenshotService:screenshot_service_
+      generatePDFRepresentationWithCompletion:^(NSData* PDFData,
+                                                NSInteger indexOfCurrentPage,
+                                                CGRect rectInCurrentPage) {
+        EXPECT_FALSE(PDFData);
+        callback_ran = true;
+      }];
 
-    EXPECT_TRUE(callback_ran);
-  }
+  EXPECT_TRUE(callback_ran);
 }
 
 // Tests that when ScreenshotDelegate's browserInterfaceProvider has a nil
 // WebSatate screenshotService will return nil.
 TEST_F(ScreenshotDelegateTest, NilWebState) {
   // Expected: nil NSData.
-  if (@available(iOS 14, *)) {
-    TestBrowser browser;
+  TestBrowser browser;
 
-    // Add the empty Browser to StubBrowserInterface.
-    browser_interface_.browser = &browser;
+  // Add the empty Browser to StubBrowserInterface.
+  browser_interface_.browser = &browser;
 
-    // Add the StubBrowserInterface to StubBrowserInterfaceProvider.
-    browser_interface_provider_.currentInterface = browser_interface_;
+  // Add the StubBrowserInterface to StubBrowserInterfaceProvider.
+  browser_interface_provider_.currentInterface = browser_interface_;
 
-    createScreenshotDelegate();
+  createScreenshotDelegate();
 
-    __block bool callback_ran = false;
-    [screenshotDelegate_ screenshotService:screenshot_service_
-        generatePDFRepresentationWithCompletion:^(NSData* PDFData,
-                                                  NSInteger indexOfCurrentPage,
-                                                  CGRect rectInCurrentPage) {
-          EXPECT_FALSE(PDFData);
-          callback_ran = true;
-        }];
+  __block bool callback_ran = false;
+  [screenshotDelegate_ screenshotService:screenshot_service_
+      generatePDFRepresentationWithCompletion:^(NSData* PDFData,
+                                                NSInteger indexOfCurrentPage,
+                                                CGRect rectInCurrentPage) {
+        EXPECT_FALSE(PDFData);
+        callback_ran = true;
+      }];
 
-    EXPECT_TRUE(callback_ran);
-  }
+  EXPECT_TRUE(callback_ran);
 }
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm
index 8c51be97..e7628eb1 100644
--- a/ios/chrome/browser/signin/authentication_service.mm
+++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -299,7 +299,6 @@
   const AccountInfo account_info =
       identity_manager_->FindExtendedAccountInfoByAccountId(account_id);
   CHECK(!account_info.IsEmpty());
-  CHECK(!account_info.hosted_domain.empty());
 
   // |PrimaryAccountManager::SetAuthenticatedAccountId| simply ignores the call
   // if there is already a signed in user. Check that there is no signed in
@@ -327,6 +326,11 @@
   const CoreAccountId account_id = identity_manager_->PickAccountIdForAccount(
       base::SysNSStringToUTF8(identity.gaiaID),
       base::SysNSStringToUTF8(identity.userEmail));
+  const AccountInfo account_info =
+      identity_manager_->FindExtendedAccountInfoByAccountId(account_id);
+  CHECK(!account_info.IsEmpty());
+  CHECK(!account_info.hosted_domain.empty());
+
   const bool success =
       identity_manager_->GetPrimaryAccountMutator()->SetPrimaryAccount(
           account_id, signin::ConsentLevel::kSync);
diff --git a/ios/chrome/browser/sync/DIR_METADATA b/ios/chrome/browser/sync/DIR_METADATA
index 5099a4e6..9a5074d 100644
--- a/ios/chrome/browser/sync/DIR_METADATA
+++ b/ios/chrome/browser/sync/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Services>Sync"
-}
\ No newline at end of file
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/ios/chrome/browser/translate/DIR_METADATA b/ios/chrome/browser/translate/DIR_METADATA
new file mode 100644
index 0000000..58ea368c
--- /dev/null
+++ b/ios/chrome/browser/translate/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/translate/COMMON_METADATA"
diff --git a/ios/chrome/browser/ui/bookmarks/managed_bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/managed_bookmarks_egtest.mm
index 1b3c880a..ffb5693 100644
--- a/ios/chrome/browser/ui/bookmarks/managed_bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/managed_bookmarks_egtest.mm
@@ -322,21 +322,16 @@
 
 // Tests that swipe is disabled in managed bookmarks top-level folder and
 // sub-folder.
-- (void)testSwipeDisabled {
+// TODO(crbug.com/1105526) On iOS14 the swipe above will trigger a tap
+// instead, and dismiss the bookmarks UI. This test should be
+// refactored to account for swipe-on-disabled-rows-trigger-a-tap.
+- (void)DISABLED_testSwipeDisabled {
   [BookmarkEarlGreyUI openBookmarks];
   [self openCustomManagedBookmarksFolder];
 
   SwipeBookmarkNodeWithLabel(@"First_Managed_URL");
   VerifyDeleteSwipeButtonNil();
 
-  // TODO(crbug.com/1105526) On iOS14 the swipe above will trigger a tap
-  // instead, and dismiss the bookmarks UI.  Since the test is still effectively
-  // testing for swipeButton nil, simply return here.  This test should be
-  // refactored to account for swipe-on-disabled-rows-trigger-a-tap.
-  if (@available(iOS 14, *)) {
-    return;
-  }
-
   SwipeBookmarkNodeWithLabel(@"Managed_Sub_Folder");
   VerifyDeleteSwipeButtonNil();
 
diff --git a/ios/chrome/browser/ui/browser_container/browser_container_coordinator.mm b/ios/chrome/browser/ui/browser_container/browser_container_coordinator.mm
index 443afa22..3b2dbea 100644
--- a/ios/chrome/browser/ui/browser_container/browser_container_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_container/browser_container_coordinator.mm
@@ -157,16 +157,14 @@
   if (!IsScreenTimeIntegrationEnabled())
     return;
 
-  if (@available(iOS 14, *)) {
-    ScreenTimeCoordinator* screenTimeCoordinator =
-        [[ScreenTimeCoordinator alloc]
-            initWithBaseViewController:self.viewController
-                               browser:self.browser];
-    [screenTimeCoordinator start];
-    self.viewController.screenTimeViewController =
-        screenTimeCoordinator.viewController;
-    self.screenTimeCoordinator = screenTimeCoordinator;
-  }
+  ScreenTimeCoordinator* screenTimeCoordinator = [[ScreenTimeCoordinator alloc]
+      initWithBaseViewController:self.viewController
+                         browser:self.browser];
+  [screenTimeCoordinator start];
+  self.viewController.screenTimeViewController =
+      screenTimeCoordinator.viewController;
+  self.screenTimeCoordinator = screenTimeCoordinator;
+
 #endif
 }
 
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller_egtest.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller_egtest.mm
index 141a7fac..28c7993 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller_egtest.mm
@@ -151,17 +151,12 @@
   // Invoke the file picker.
   [ChromeEarlGrey tapWebStateElementWithID:@"file"];
 
-  if (@available(iOS 14, *)) {
-    // Tap on the toolbar to dismiss the file picker on iOS14.  In iOS14 a
-    // UIDropShadowView covers the entire app, so tapping anywhere should
-    // dismiss the file picker.
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::PrimaryToolbar()]
-        performAction:grey_tap()];
-  } else {
-    // Tap on the "Cancel" button to dismiss the file picker before iOS14.
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::CancelButton()]
-        performAction:grey_tap()];
-  }
+  // Tap on the toolbar to dismiss the file picker on iOS14.  In iOS14 a
+  // UIDropShadowView covers the entire app, so tapping anywhere should
+  // dismiss the file picker.
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::PrimaryToolbar()]
+      performAction:grey_tap()];
+
   [ChromeEarlGreyUI waitForAppToIdle];
 }
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
index 2ee8446..b01bf53 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -333,13 +333,9 @@
 
   [self.headerView addViewsToSearchField:self.fakeOmnibox];
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-  if (@available(iOS 14, *)) {
-    UIIndirectScribbleInteraction* scribbleInteraction =
-        [[UIIndirectScribbleInteraction alloc] initWithDelegate:self];
-    [self.fakeOmnibox addInteraction:scribbleInteraction];
-  }
-#endif  // defined(__IPHONE_14_0)
+  UIIndirectScribbleInteraction* scribbleInteraction =
+      [[UIIndirectScribbleInteraction alloc] initWithDelegate:self];
+  [self.fakeOmnibox addInteraction:scribbleInteraction];
 
   [self.headerView.voiceSearchButton addTarget:self
                                         action:@selector(loadVoiceSearch:)
@@ -622,8 +618,6 @@
 
 #pragma mark - UIIndirectScribbleInteractionDelegate
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-
 - (void)indirectScribbleInteraction:(UIIndirectScribbleInteraction*)interaction
               requestElementsInRect:(CGRect)rect
                          completion:
@@ -673,8 +667,6 @@
   return YES;
 }
 
-#endif  // defined(__IPHONE_14_0)
-
 #pragma mark - LogoAnimationControllerOwnerOwner
 
 - (id<LogoAnimationControllerOwner>)logoAnimationControllerOwner {
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_egtest.mm b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_egtest.mm
index 5c6da52..c88fd5f1 100644
--- a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_egtest.mm
+++ b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_egtest.mm
@@ -78,11 +78,6 @@
 #define MAYBE_testNonModalAppears DISABLED_testNonModalAppears
 #endif
 - (void)MAYBE_testNonModalAppears {
-  // Promos only appear on iOS 14 and up.
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
-
   [ChromeEarlGreyAppInterface copyURLToPasteBoard];
   [[EarlGrey selectElementWithMatcher:FakeOmniboxMatcher()]
       performAction:grey_tap()];
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler_unittest.mm b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler_unittest.mm
index 369512fa..87335d8 100644
--- a/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler_unittest.mm
+++ b/ios/chrome/browser/ui/default_promo/default_browser_promo_non_modal_scheduler_unittest.mm
@@ -126,10 +126,6 @@
 
 // Tests that the omnibox paste event triggers the promo to show.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest, TestOmniboxPasteShowsPromo) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserPastedInOmnibox];
 
@@ -154,10 +150,6 @@
 // promo.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest,
        TestFirstPartySchemeShowsPromo) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserEnteredAppViaFirstPartyScheme];
 
@@ -180,10 +172,6 @@
 
 // Tests that the completed share event triggers the promo.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest, TestShareCompletedShowsPromo) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserFinishedActivityFlow];
 
@@ -202,10 +190,6 @@
 // Tests that the promo dismisses automatically after the dismissal time and
 // the event is stored.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest, TestTimeoutDismissesPromo) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserPastedInOmnibox];
 
@@ -233,10 +217,6 @@
 
 // Tests that if the user takes the promo action, that is handled correctly.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest, TestActionDismissesPromo) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserPastedInOmnibox];
 
@@ -267,10 +247,6 @@
 // finishes, the promo does not show.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest,
        TestTabSwitchPreventsPromoShown) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserPastedInOmnibox];
 
@@ -292,10 +268,6 @@
 // Tests that if a message is triggered on page load, the promo is not shown.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest,
        TestMessagePreventsPromoShown) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserPastedInOmnibox];
 
@@ -332,10 +304,6 @@
 // does not update the shown promo count.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest,
        TestBackgroundingDismissesPromo) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserPastedInOmnibox];
 
@@ -364,10 +332,6 @@
 // Tests that entering the tab grid with the promo showing hides the promo but
 // does not update the shown promo count.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest, TestTabGridDismissesPromo) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserPastedInOmnibox];
 
@@ -394,10 +358,6 @@
 
 // Tests background cancel metric logs correctly.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest, TestBackgroundCancelMetric) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectUniqueSample(
@@ -420,10 +380,6 @@
 // Tests background cancel metric is not logged after a promo is shown.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest,
        TestBackgroundCancelMetricNotLogAfterPromoShown) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectUniqueSample(
@@ -456,10 +412,6 @@
 // Tests background cancel metric is not logged after a promo is dismissed.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest,
        TestBackgroundCancelMetricNotLogAfterPromoDismiss) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectUniqueSample(
@@ -498,10 +450,6 @@
 // Prevents crbug.com/1221379 regression.
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest,
        TestBackgroundCancelMetricDoesNotLogWhenPromoNotShown) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   base::HistogramTester histogram_tester;
   histogram_tester.ExpectUniqueSample(
@@ -541,10 +489,6 @@
 // Tests that if the user currently has Chrome as default, the promo does not
 // show. Prevents regression of crbug.com/1224875
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest, NoPromoIfDefault) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   // Mark Chrome as currently default
   [[NSUserDefaults standardUserDefaults]
@@ -566,10 +510,6 @@
 // DCHECK is not fired on the next page load. Prevents regression of
 // crbug.com/1224427
 TEST_F(DefaultBrowserPromoNonModalSchedulerTest, NoDCHECKIfPromoNotShown) {
-  // Default promo is not supported on iOS < 14
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
 
   [scheduler_ logUserPastedInOmnibox];
 
diff --git a/ios/chrome/browser/ui/default_promo/default_browser_utils_unittest.mm b/ios/chrome/browser/ui/default_promo/default_browser_utils_unittest.mm
index f0ba4e3..c28fc98 100644
--- a/ios/chrome/browser/ui/default_promo/default_browser_utils_unittest.mm
+++ b/ios/chrome/browser/ui/default_promo/default_browser_utils_unittest.mm
@@ -45,20 +45,6 @@
 
 // Tests interesting information for each type.
 TEST_F(DefaultBrowserUtilsTest, LogInterestingActivityEach) {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    // On iOS < 14 it should always be false.
-    LogLikelyInterestedDefaultBrowserUserActivity(DefaultPromoTypeGeneral);
-    EXPECT_FALSE(IsLikelyInterestedDefaultBrowserUser(DefaultPromoTypeGeneral));
-    LogLikelyInterestedDefaultBrowserUserActivity(DefaultPromoTypeStaySafe);
-    EXPECT_FALSE(
-        IsLikelyInterestedDefaultBrowserUser(DefaultPromoTypeStaySafe));
-    LogLikelyInterestedDefaultBrowserUserActivity(DefaultPromoTypeMadeForIOS);
-    EXPECT_FALSE(
-        IsLikelyInterestedDefaultBrowserUser(DefaultPromoTypeMadeForIOS));
-    LogLikelyInterestedDefaultBrowserUserActivity(DefaultPromoTypeAllTabs);
-    EXPECT_FALSE(IsLikelyInterestedDefaultBrowserUser(DefaultPromoTypeAllTabs));
-    return;
-  }
 
   // General promo.
   EXPECT_FALSE(IsLikelyInterestedDefaultBrowserUser(DefaultPromoTypeGeneral));
@@ -87,10 +73,6 @@
 
 // Tests most recent interest type.
 TEST_F(DefaultBrowserUtilsTest, MostRecentInterestDefaultPromoType) {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    // iOS < 14 not supported.
-    return;
-  }
   DefaultPromoType type = MostRecentInterestDefaultPromoType(NO);
   EXPECT_EQ(type, DefaultPromoTypeGeneral);
 
@@ -111,10 +93,6 @@
 
 // Tests cool down between promos.
 TEST_F(DefaultBrowserUtilsTest, PromoCoolDown) {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    // iOS < 14 not supported.
-    return;
-  }
   LogUserInteractionWithFullscreenPromo();
   EXPECT_TRUE(UserInPromoCooldown());
 
@@ -125,10 +103,6 @@
 
 // Tests no 2 tailored promos are not shown.
 TEST_F(DefaultBrowserUtilsTest, TailoredPromoDoesNotAppearTwoTimes) {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    // iOS < 14 not supported.
-    return;
-  }
   LogUserInteractionWithTailoredFullscreenPromo();
   EXPECT_TRUE(HasUserInteractedWithTailoredFullscreenPromoBefore());
 }
diff --git a/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm b/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm
index 03bfe60e6..843ad63 100644
--- a/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm
+++ b/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm
@@ -102,9 +102,8 @@
   XCUIApplication* app = [[XCUIApplication alloc] init];
   XCUIElement* goodTitle = app.staticTexts[@"good"];
 #if TARGET_IPHONE_SIMULATOR
-  if (@available(iOS 14, *)) {
-    goodTitle = app.staticTexts[@"Unsupported file format"];
-  }
+  goodTitle = app.staticTexts[@"Unsupported file format"];
+
 #endif
   GREYAssert(
       [goodTitle waitForExistenceWithTimeout:kWaitForARPresentationTimeout],
@@ -123,9 +122,8 @@
   XCUIApplication* app = [[XCUIApplication alloc] init];
   XCUIElement* goodTitle = app.staticTexts[@"good"];
 #if TARGET_IPHONE_SIMULATOR
-  if (@available(iOS 14, *)) {
-    goodTitle = app.staticTexts[@"Unsupported file format"];
-  }
+  goodTitle = app.staticTexts[@"Unsupported file format"];
+
 #endif
   GREYAssertFalse(
       [goodTitle waitForExistenceWithTimeout:kWaitForARPresentationTimeout],
@@ -144,9 +142,7 @@
   XCUIApplication* app = [[XCUIApplication alloc] init];
   XCUIElement* goodTitle = app.staticTexts[@"good"];
 #if TARGET_IPHONE_SIMULATOR
-  if (@available(iOS 14, *)) {
-    goodTitle = app.staticTexts[@"Unsupported file format"];
-  }
+  goodTitle = app.staticTexts[@"Unsupported file format"];
 #endif
   GREYAssertFalse(
       [goodTitle waitForExistenceWithTimeout:kWaitForARPresentationTimeout],
@@ -165,9 +161,7 @@
   XCUIApplication* app = [[XCUIApplication alloc] init];
   XCUIElement* goodTitle = app.staticTexts[@"good"];
 #if TARGET_IPHONE_SIMULATOR
-  if (@available(iOS 14, *)) {
-    goodTitle = app.staticTexts[@"Unsupported file format"];
-  }
+  goodTitle = app.staticTexts[@"Unsupported file format"];
 #endif
   GREYAssertFalse(
       [goodTitle waitForExistenceWithTimeout:kWaitForARPresentationTimeout],
@@ -190,9 +184,7 @@
   XCUIApplication* app = [[XCUIApplication alloc] init];
   XCUIElement* goodTitle = app.staticTexts[@"good"];
 #if TARGET_IPHONE_SIMULATOR
-  if (@available(iOS 14, *)) {
-    goodTitle = app.staticTexts[@"Unsupported file format"];
-  }
+  goodTitle = app.staticTexts[@"Unsupported file format"];
 #endif
   GREYAssert(
       [goodTitle waitForExistenceWithTimeout:kWaitForARPresentationTimeout],
diff --git a/ios/chrome/browser/ui/elements/text_view_selection_disabled.mm b/ios/chrome/browser/ui/elements/text_view_selection_disabled.mm
index 537746084..3de9e2e 100644
--- a/ios/chrome/browser/ui/elements/text_view_selection_disabled.mm
+++ b/ios/chrome/browser/ui/elements/text_view_selection_disabled.mm
@@ -11,12 +11,7 @@
 @implementation TextViewSelectionDisabled
 
 - (BOOL)canBecomeFirstResponder {
-  if (@available(iOS 14.0, *))
-    return NO;
-
-  // On iOS 13, the whole string responds to a tap if
-  // canBecomeFirstResponder returns NO.
-  return YES;
+  return NO;
 }
 
 @end
diff --git a/ios/chrome/browser/ui/first_run/resources/BUILD.gn b/ios/chrome/browser/ui/first_run/resources/BUILD.gn
index 00f2fd94..b5c7f6f 100644
--- a/ios/chrome/browser/ui/first_run/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/resources/BUILD.gn
@@ -56,6 +56,16 @@
   ]
 }
 
+imageset("forced_signin_screen_banner") {
+  sources = [
+    "forced_signin_screen_banner.imageset/Contents.json",
+    "forced_signin_screen_banner.imageset/forced_signin_screen_banner_dark@2x.png",
+    "forced_signin_screen_banner.imageset/forced_signin_screen_banner_dark@3x.png",
+    "forced_signin_screen_banner.imageset/forced_signin_screen_banner_light@2x.png",
+    "forced_signin_screen_banner.imageset/forced_signin_screen_banner_light@3x.png",
+  ]
+}
+
 imageset("sync_screen_banner") {
   sources = [
     "sync_screen_banner.imageset/Contents.json",
diff --git a/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/Contents.json b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/Contents.json
new file mode 100644
index 0000000..82e50bd
--- /dev/null
+++ b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/Contents.json
@@ -0,0 +1,40 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "forced_signin_screen_banner_light@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "filename" : "forced_signin_screen_banner_dark@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "forced_signin_screen_banner_light@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "filename" : "forced_signin_screen_banner_dark@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_dark@2x.png b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_dark@2x.png
new file mode 100644
index 0000000..c76839b5
--- /dev/null
+++ b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_dark@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_dark@3x.png b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_dark@3x.png
new file mode 100644
index 0000000..5e6bf65
--- /dev/null
+++ b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_dark@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_light@2x.png b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_light@2x.png
new file mode 100644
index 0000000..8b8ac1b
--- /dev/null
+++ b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_light@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_light@3x.png b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_light@3x.png
new file mode 100644
index 0000000..eae6636c
--- /dev/null
+++ b/ios/chrome/browser/ui/first_run/resources/forced_signin_screen_banner.imageset/forced_signin_screen_banner_light@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/first_run/signin/BUILD.gn b/ios/chrome/browser/ui/first_run/signin/BUILD.gn
index d245d63..00a5d79 100644
--- a/ios/chrome/browser/ui/first_run/signin/BUILD.gn
+++ b/ios/chrome/browser/ui/first_run/signin/BUILD.gn
@@ -47,6 +47,7 @@
     "//ios/chrome/browser/ui/elements:elements_internal",
     "//ios/chrome/browser/ui/first_run:constants",
     "//ios/chrome/browser/ui/first_run:first_run_ui",
+    "//ios/chrome/browser/ui/first_run/resources:forced_signin_screen_banner",
     "//ios/chrome/browser/ui/first_run/resources:signin_screen_banner",
     "//ios/chrome/browser/ui/settings/elements:constants",
     "//ios/chrome/browser/ui/settings/elements:enterprise_info_popover_view_controller",
diff --git a/ios/chrome/browser/ui/first_run/signin/signin_screen_view_controller.mm b/ios/chrome/browser/ui/first_run/signin/signin_screen_view_controller.mm
index 08e3e2d..0c3fd86 100644
--- a/ios/chrome/browser/ui/first_run/signin/signin_screen_view_controller.mm
+++ b/ios/chrome/browser/ui/first_run/signin/signin_screen_view_controller.mm
@@ -61,7 +61,9 @@
 - (void)viewDidLoad {
   self.view.accessibilityIdentifier =
       first_run::kFirstRunSignInScreenAccessibilityIdentifier;
-  self.bannerImage = [UIImage imageNamed:@"signin_screen_banner"];
+  self.bannerImage =
+      [UIImage imageNamed:self.forcedSignin ? @"forced_signin_screen_banner"
+                                            : @"signin_screen_banner"];
   self.isTallBanner = NO;
   self.scrollToEndMandatory = YES;
 
diff --git a/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm b/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm
index d750704..fd69ec5 100644
--- a/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm
+++ b/ios/chrome/browser/ui/infobars/translate_infobar_egtest.mm
@@ -727,12 +727,8 @@
 
 // Tests that the target language can be changed. TODO(crbug.com/1046629):
 // implement test for changing source language.
-- (void)testInfobarChangeTargetLanguage {
-  // TODO(crbug.com/1116012): This test is failing flaky on iOS14.
-  if (@available(iOS 14, *)) {
-    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS14.");
-  }
-
+// TODO(crbug.com/1116012): This test is failing flaky on iOS14.
+- (void)DISABLED_testInfobarChangeTargetLanguage {
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
diff --git a/ios/chrome/browser/ui/link_to_text/link_to_text_egtest.mm b/ios/chrome/browser/ui/link_to_text/link_to_text_egtest.mm
index 4770265..836ef4b7 100644
--- a/ios/chrome/browser/ui/link_to_text/link_to_text_egtest.mm
+++ b/ios/chrome/browser/ui/link_to_text/link_to_text_egtest.mm
@@ -276,36 +276,34 @@
 }
 
 - (void)testBadSelectionDisablesGenerateLink {
-  if (@available(iOS 14, *)) {
-    [ChromeEarlGrey loadURL:self.testServer->GetURL(kNoTextTestURL)];
-    [ChromeEarlGrey waitForWebStateContainingText:kNoTextTestPageTextSample];
+  [ChromeEarlGrey loadURL:self.testServer->GetURL(kNoTextTestURL)];
+  [ChromeEarlGrey waitForWebStateContainingText:kNoTextTestPageTextSample];
 
-    [ChromeTestCase removeAnyOpenMenusAndInfoBars];
+  [ChromeTestCase removeAnyOpenMenusAndInfoBars];
 
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
-        performAction:chrome_test_util::LongPressElementForContextMenu(
-                          [ElementSelector
-                              selectorWithElementID:kSimpleTextElementId],
-                          true)];
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
+      performAction:chrome_test_util::LongPressElementForContextMenu(
+                        [ElementSelector
+                            selectorWithElementID:kSimpleTextElementId],
+                        true)];
 
-    // TODO(crbug.com/1233056): Xcode 13 gesture recognizers seem to get stuck
-    // when the user longs presses on plain text.  For this test, disable EG
-    // synchronization.
-    ScopedSynchronizationDisabler disabler;
-    id<GREYMatcher> copyButton =
-        chrome_test_util::SystemSelectionCalloutCopyButton();
-    [ChromeEarlGrey waitForSufficientlyVisibleElementWithMatcher:copyButton];
+  // TODO(crbug.com/1233056): Xcode 13 gesture recognizers seem to get stuck
+  // when the user longs presses on plain text.  For this test, disable EG
+  // synchronization.
+  ScopedSynchronizationDisabler disabler;
+  id<GREYMatcher> copyButton =
+      chrome_test_util::SystemSelectionCalloutCopyButton();
+  [ChromeEarlGrey waitForSufficientlyVisibleElementWithMatcher:copyButton];
 
-    // Make sure the Link to Text button is not visible.
-    [[EarlGrey selectElementWithMatcher:
-                   chrome_test_util::SystemSelectionCalloutLinkToTextButton()]
-        assertWithMatcher:grey_notVisible()];
+  // Make sure the Link to Text button is not visible.
+  [[EarlGrey selectElementWithMatcher:
+                 chrome_test_util::SystemSelectionCalloutLinkToTextButton()]
+      assertWithMatcher:grey_notVisible()];
 
-    // TODO(crbug.com/1233056): Tap to dismiss the system selection callout
-    // buttons so tearDown doesn't hang when |disabler| goes out of scope.
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
-        performAction:grey_tap()];
-  }
+  // TODO(crbug.com/1233056): Tap to dismiss the system selection callout
+  // buttons so tearDown doesn't hang when |disabler| goes out of scope.
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
+      performAction:grey_tap()];
 }
 
 - (void)testInputDisablesGenerateLink {
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
index baca2f0f..27bdf6b 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
@@ -54,13 +54,7 @@
 
 }  // namespace
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-@interface LocationBarViewController (Scribble) <
-    UIIndirectScribbleInteractionDelegate>
-@end
-#endif  // defined(__IPHONE14_0)
-
-@interface LocationBarViewController ()
+@interface LocationBarViewController () <UIIndirectScribbleInteractionDelegate>
 // The injected edit view.
 @property(nonatomic, strong) UIView* editView;
 
@@ -204,13 +198,9 @@
                   action:@selector(showLongPressMenu:)];
   [_locationBarSteadyView.locationButton addGestureRecognizer:recognizer];
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-  if (@available(iOS 14, *)) {
-    UIIndirectScribbleInteraction* scribbleInteraction =
-        [[UIIndirectScribbleInteraction alloc] initWithDelegate:self];
-    [_locationBarSteadyView addInteraction:scribbleInteraction];
-  }
-#endif  // #if defined(__IPHONE_14_0)
+  UIIndirectScribbleInteraction* scribbleInteraction =
+      [[UIIndirectScribbleInteraction alloc] initWithDelegate:self];
+  [_locationBarSteadyView addInteraction:scribbleInteraction];
 
   DCHECK(self.editView) << "The edit view must be set at this point";
 
@@ -388,8 +378,6 @@
 
 #pragma mark - UIIndirectScribbleInteractionDelegate
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-
 - (void)indirectScribbleInteraction:(UIIndirectScribbleInteraction*)interaction
               requestElementsInRect:(CGRect)rect
                          completion:
@@ -431,8 +419,6 @@
   completion(self.delegate.omniboxScribbleForwardingTarget);
 }
 
-#endif  // defined(__IPHONE_14_0)
-
 #pragma mark - private
 
 - (void)locationBarSteadyViewTapped {
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index 279f41f..978934c1 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -840,13 +840,11 @@
   policyWatcherAgent->AddObserver(_policyWatcherObserverBridge.get());
   policyWatcherAgent->Initialize(handler);
 
-  if (@available(iOS 14, *)) {
-    if (base::FeatureList::IsEnabled(kEnableFullPageScreenshot)) {
-      self.screenshotDelegate = [[ScreenshotDelegate alloc]
-          initWithBrowserInterfaceProvider:self.browserViewWrangler];
-      [self.sceneState.scene.screenshotService
-          setDelegate:self.screenshotDelegate];
-    }
+  if (base::FeatureList::IsEnabled(kEnableFullPageScreenshot)) {
+    self.screenshotDelegate = [[ScreenshotDelegate alloc]
+        initWithBrowserInterfaceProvider:self.browserViewWrangler];
+    [self.sceneState.scene.screenshotService
+        setDelegate:self.screenshotDelegate];
   }
 
   // Only create the restoration helper if the session with the current session
diff --git a/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm b/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm
index b1dd9a4f..4a5a37bf 100644
--- a/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm
+++ b/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm
@@ -168,12 +168,6 @@
     return false;
   }
 
-  // Current NTP default browser promo should only be shown for users on iOS14.
-  if (!base::ios::IsRunningOnIOS14OrLater() &&
-      command_ == kSetDefaultBrowserCommand) {
-    return false;
-  }
-
   // Check optional restrictions.
 
   if (seconds_since_install_ > 0) {
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm b/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm
index 2eb4ea9..2e44ab4 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_egtest.mm
@@ -689,18 +689,8 @@
 }
 
 // TODO(crbug.com/1067815): Test can't pass on devices.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_testNoDefaultMatch testNoDefaultMatch
-#else
-#define MAYBE_testNoDefaultMatch DISABLED_testNoDefaultMatch
-#endif
-- (void)MAYBE_testNoDefaultMatch {
-  // TODO(crbug.com/1105869) Omnibox pasteboard suggestions are currently
-  // disabled on iOS14.
-  if (@available(iOS 14, *)) {
-    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS14.");
-  }
-
+// TODO(crbug.com/1253345) Re-enable this test
+- (void)DISABLED_testNoDefaultMatch {
   NSString* copiedText = @"test no default match1";
 
   // Put some text in pasteboard.
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
index a1f1dec..139f12f 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -122,12 +122,8 @@
   SetA11yLabelAndUiAutomationName(self.textField, IDS_ACCNAME_LOCATION,
                                   @"Address");
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-  if (@available(iOS 14, *)) {
-    [self.textField
-        addInteraction:[[UIScribbleInteraction alloc] initWithDelegate:self]];
-  }
-#endif  // defined(__IPHONE_14_0)
+  [self.textField
+      addInteraction:[[UIScribbleInteraction alloc] initWithDelegate:self]];
 }
 
 - (void)viewDidLoad {
@@ -660,8 +656,6 @@
 
 #pragma mark - UIScribbleInteractionDelegate
 
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-
 - (void)scribbleInteractionWillBeginWriting:(UIScribbleInteraction*)interaction
     API_AVAILABLE(ios(14.0)) {
   if (self.textField.isPreEditing) {
@@ -681,6 +675,4 @@
   [self.textField clearAutocompleteText];
 }
 
-#endif  // defined(__IPHONE_14_0)
-
 @end
diff --git a/ios/chrome/browser/ui/send_tab_to_self/DIR_METADATA b/ios/chrome/browser/ui/send_tab_to_self/DIR_METADATA
index 1642232..6e6111d 100644
--- a/ios/chrome/browser/ui/send_tab_to_self/DIR_METADATA
+++ b/ios/chrome/browser/ui/send_tab_to_self/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "UI>Browser>Sharing"
-}
\ No newline at end of file
+mixins: "//components/send_tab_to_self/COMMON_METADATA"
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
index 780ada6c..dff44c5b 100644
--- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -432,29 +432,17 @@
 
   // Defaults section.
   TableViewModel<TableViewItem*>* model = self.tableViewModel;
-  if (@available(iOS 14, *)) {
-    [model addSectionWithIdentifier:SettingsSectionIdentifierDefaults];
-    [model addItem:[self defaultBrowserCellItem]
-        toSectionWithIdentifier:SettingsSectionIdentifierDefaults];
-  }
+  [model addSectionWithIdentifier:SettingsSectionIdentifierDefaults];
+  [model addItem:[self defaultBrowserCellItem]
+      toSectionWithIdentifier:SettingsSectionIdentifierDefaults];
 
   // Show managed UI if default search engine is managed by policy.
   if ([self isDefaultSearchEngineManagedByPolicy]) {
-    if (@available(iOS 14, *)) {
-      [model addItem:[self managedSearchEngineItem]
-          toSectionWithIdentifier:SettingsSectionIdentifierDefaults];
-    } else {
-      [model addItem:[self managedSearchEngineItem]
-          toSectionWithIdentifier:SettingsSectionIdentifierBasics];
-    }
+    [model addItem:[self managedSearchEngineItem]
+        toSectionWithIdentifier:SettingsSectionIdentifierDefaults];
   } else {
-    if (@available(iOS 14, *)) {
-      [model addItem:[self searchEngineDetailItem]
-          toSectionWithIdentifier:SettingsSectionIdentifierDefaults];
-    } else {
-      [model addItem:[self searchEngineDetailItem]
-          toSectionWithIdentifier:SettingsSectionIdentifierBasics];
-    }
+    [model addItem:[self searchEngineDetailItem]
+        toSectionWithIdentifier:SettingsSectionIdentifierDefaults];
   }
 
   // Basics section
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/features.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/features.mm
index ae8adfa..ffd6480 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/features.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/features.mm
@@ -12,8 +12,5 @@
                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
 bool IsTabsBulkActionsEnabled() {
-  if (@available(iOS 14, *)) {
-    return base::FeatureList::IsEnabled(kTabsBulkActions);
-  }
-  return false;
+  return base::FeatureList::IsEnabled(kTabsBulkActions);
 }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller_unittest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller_unittest.mm
index f0df5a4..125c1d2 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller_unittest.mm
@@ -215,14 +215,10 @@
 
 // Tests that |-replaceItemID:withItem:| does not crash when updating an item
 // that is scrolled offscreen.
+// TODO(crbug.com/1104872): On iOS 14 iPhone X, visibleCellsCount is always
+// equal to the total number of cells, so the while loop below never
+// terminates.
 TEST_F(GridViewControllerTest, DISABLED_ReplaceScrolledOffScreenCell) {
-  // TODO(crbug.com/1104872): On iOS 14 iPhone X, visibleCellsCount is always
-  // equal to the total number of cells, so the while loop below never
-  // terminates.
-  if (@available(iOS 14, *)) {
-    return;
-  }
-
   // This test requires that the collection view be placed on the screen.
   SetRootViewController(view_controller_);
   EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
index ccffbb3..ad6b405 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_egtest.mm
@@ -423,10 +423,6 @@
 // Tests that Add to Bookmarks action is greyed out when editBookmarksEnabled
 // pref is set to false.
 - (void)testTabGridItemContextMenuAddToBookmarkGreyed {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    EARL_GREY_TEST_SKIPPED(
-        @"Context menu item traits are only set correctly after iOS 14.");
-  }
   [ChromeEarlGreyAppInterface
       setBoolValue:NO
        forUserPref:base::SysUTF8ToNSString(
@@ -936,11 +932,6 @@
 // Tests closing a tab in the tab grid edit mode and that edit mode is exited
 // after closing all tabs.
 - (void)testTabGridBulkActionCloseTabs {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    EARL_GREY_TEST_SKIPPED(
-        @"Bulk actions are only supported on iOS 14 and later.");
-  }
-
   [ChromeEarlGrey loadURL:_URL1];
   [ChromeEarlGrey waitForWebStateContainingText:kResponse1];
 
@@ -988,11 +979,6 @@
 // Tests selecting all items in the tab grid edit mode using the "Select all"
 // button.
 - (void)testTabGridBulkActionSelectAll {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    EARL_GREY_TEST_SKIPPED(
-        @"Bulk actions are only supported on iOS 14 and later.");
-  }
-
   [ChromeEarlGrey loadURL:_URL1];
   [ChromeEarlGrey waitForWebStateContainingText:kResponse1];
 
@@ -1040,11 +1026,6 @@
 // Tests deselecting all items in the tab grid edit mode using the "Deselect
 // all" button.
 - (void)testTabGridBulkActionDeselectAll {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    EARL_GREY_TEST_SKIPPED(
-        @"Bulk actions are only supported on iOS 14 and later.");
-  }
-
   [ChromeEarlGrey loadURL:_URL1];
   [ChromeEarlGrey waitForWebStateContainingText:kResponse1];
 
@@ -1103,11 +1084,6 @@
 
 // Tests adding items to Bookmarks from the tab grid edit mode.
 - (void)testTabGridBulkActionAddToBookmarks {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    EARL_GREY_TEST_SKIPPED(
-        @"Bulk actions are only supported on iOS 14 and later.");
-  }
-
   [ChromeEarlGrey loadURL:_URL1];
   [ChromeEarlGrey waitForWebStateContainingText:kResponse1];
 
@@ -1163,11 +1139,6 @@
 
 // Tests adding items to the readinglist from the tab grid edit mode.
 - (void)testTabGridBulkActionAddToReadingList {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    EARL_GREY_TEST_SKIPPED(
-        @"Bulk actions are only supported on iOS 14 and later.");
-  }
-
   [ChromeEarlGrey loadURL:_URL1];
   [ChromeEarlGrey waitForWebStateContainingText:kResponse1];
 
@@ -1207,10 +1178,6 @@
 - (void)testTabGridBulkActionShare {
   // TODO(crbug.com/1238501): The pasteboard is "not available at this time"
   // when running on device.
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    EARL_GREY_TEST_SKIPPED(
-        @"Bulk actions are only supported on iOS 14 and later.");
-  }
 
 #if !TARGET_OS_SIMULATOR
   EARL_GREY_TEST_SKIPPED(
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
index b01402d3..af3f041 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_view_controller.mm
@@ -251,10 +251,8 @@
 
   [self setupTopToolbar];
   [self setupBottomToolbar];
-  if (@available(iOS 14, *)) {
-    if (IsTabsBulkActionsEnabled())
-      [self setupEditButton];
-  }
+  if (IsTabsBulkActionsEnabled())
+    [self setupEditButton];
 
   // Hide the toolbars and the floating button, so they can fade in the first
   // time there's a transition into this view controller.
@@ -1315,33 +1313,31 @@
   self.bottomToolbar.mode = self.tabGridMode;
   self.topToolbar.mode = self.tabGridMode;
 
-  if (@available(iOS 14, *)) {
-    GridViewController* gridViewController =
-        [self gridViewControllerForPage:self.currentPage];
-    NSArray<NSString*>* items =
-        gridViewController.selectedShareableItemIDsForEditing;
-    UIMenu* menu = nil;
-    switch (self.currentPage) {
-      case TabGridPageIncognitoTabs:
-        menu = [UIMenu
-            menuWithChildren:[self.incognitoTabsDelegate
-                                 addToButtonMenuElementsForItems:items]];
-        break;
-      case TabGridPageRegularTabs:
-        menu = [UIMenu
-            menuWithChildren:[self.regularTabsDelegate
-                                 addToButtonMenuElementsForItems:items]];
-        break;
-      case TabGridPageRemoteTabs:
-        // No-op, Add To button inaccessible in remote tabs page.
-        break;
-    }
-    [self.bottomToolbar setAddToButtonMenu:menu];
-    BOOL incognitoTabsNeedsAuth =
-        (self.currentPage == TabGridPageIncognitoTabs &&
-         self.incognitoTabsViewController.contentNeedsAuthentication);
-    [self.bottomToolbar setAddToButtonEnabled:!incognitoTabsNeedsAuth];
+  GridViewController* gridViewController =
+      [self gridViewControllerForPage:self.currentPage];
+  NSArray<NSString*>* items =
+      gridViewController.selectedShareableItemIDsForEditing;
+  UIMenu* menu = nil;
+  switch (self.currentPage) {
+    case TabGridPageIncognitoTabs:
+      menu =
+          [UIMenu menuWithChildren:[self.incognitoTabsDelegate
+                                       addToButtonMenuElementsForItems:items]];
+      break;
+    case TabGridPageRegularTabs:
+      menu =
+          [UIMenu menuWithChildren:[self.regularTabsDelegate
+                                       addToButtonMenuElementsForItems:items]];
+      break;
+    case TabGridPageRemoteTabs:
+      // No-op, Add To button inaccessible in remote tabs page.
+      break;
   }
+  [self.bottomToolbar setAddToButtonMenu:menu];
+  BOOL incognitoTabsNeedsAuth =
+      (self.currentPage == TabGridPageIncognitoTabs &&
+       self.incognitoTabsViewController.contentNeedsAuthentication);
+  [self.bottomToolbar setAddToButtonEnabled:!incognitoTabsNeedsAuth];
 
   // When current page is a remote tabs page.
   if (self.currentPage == TabGridPageRemoteTabs) {
diff --git a/ios/chrome/browser/update_client/DIR_METADATA b/ios/chrome/browser/update_client/DIR_METADATA
index ac9279c5..10cd606 100644
--- a/ios/chrome/browser/update_client/DIR_METADATA
+++ b/ios/chrome/browser/update_client/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Installer>Components"
-}
-team_email: "chrome-updates-dev@chromium.org"
\ No newline at end of file
+mixins: "//components/update_client/COMMON_METADATA"
diff --git a/ios/chrome/browser/web/content_mode_egtest.mm b/ios/chrome/browser/web/content_mode_egtest.mm
index d4215e2..3b8dfff 100644
--- a/ios/chrome/browser/web/content_mode_egtest.mm
+++ b/ios/chrome/browser/web/content_mode_egtest.mm
@@ -139,12 +139,6 @@
 
 // Tests the platform when the page is inside an iframe.
 - (void)testIFrameNavigation {
-  // This test fails in iOS 13.4 but is fixed in iOS 14. See crbug.com//1076233.
-  if (base::ios::IsRunningOnOrLater(13, 4, 0) &&
-      !base::ios::IsRunningOnIOS14OrLater()) {
-    EARL_GREY_TEST_SKIPPED(@"Test disabled on iOS 13.4 but enabled in iOS 14");
-  }
-
   [ChromeEarlGrey loadURL:self.testServer->GetURL(kIFramePage)];
   [ChromeEarlGrey tapWebStateElementInIFrameWithID:kLinkPageLinkID];
 
diff --git a/ios/chrome/browser/web/font_size/font_size_js_unittest.mm b/ios/chrome/browser/web/font_size/font_size_js_unittest.mm
index b79d137..33dcad08 100644
--- a/ios/chrome/browser/web/font_size/font_size_js_unittest.mm
+++ b/ios/chrome/browser/web/font_size/font_size_js_unittest.mm
@@ -66,13 +66,6 @@
 
 // Tests that __gCrWeb.font_size.adjustFontSize works for any scale.
 TEST_F(FontSizeJsTest, TestAdjustFontSizeForScale) {
-  // TODO(crbug.com/983776): This test fails on iOS 13 ipad due to a
-  // simulator bug. Re-enable once iOS 13 support is dropped.
-  if (!base::ios::IsRunningOnIOS14OrLater() &&
-      ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
-    return;
-  }
-
   float original_size = 0;
   float current_size = 0;
 
@@ -187,13 +180,6 @@
 
 // Tests that __gCrWeb.font_size.adjustFontSize works for any CSS unit.
 TEST_F(FontSizeJsTest, TestAdjustFontSizeForUnit) {
-  // TODO(crbug.com/983776): This test fails on iOS 13 ipad due to a
-  // simulator bug. Re-enable once iOS 13 support is dropped.
-  if (!base::ios::IsRunningOnIOS14OrLater() &&
-      ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
-    return;
-  }
-
   float original_size = 0;
   float current_size = 0;
 
@@ -260,13 +246,6 @@
 
 // Tests that __gCrWeb.font_size.adjustFontSize works for nested elements.
 TEST_F(FontSizeJsTest, TestAdjustFontSizeForNestedElements) {
-  // TODO(crbug.com/983776): This test fails on iOS 13 ipad due to a
-  // simulator bug. Re-enable once iOS 13 support is dropped.
-  if (!base::ios::IsRunningOnIOS14OrLater() &&
-      ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
-    return;
-  }
-
   float original_size_1 = 0;
   float original_size_2 = 0;
   float current_size_1 = 0;
diff --git a/ios/chrome/browser/web/legacy_tls_egtest.mm b/ios/chrome/browser/web/legacy_tls_egtest.mm
index ea38bc1..50d06b3 100644
--- a/ios/chrome/browser/web/legacy_tls_egtest.mm
+++ b/ios/chrome/browser/web/legacy_tls_egtest.mm
@@ -73,32 +73,17 @@
   _safeContent = "Default response";
 }
 
-// On iOS < 14, the legacy TLS interstitial should not be shown.
-- (void)testLegacyTLSInterstitialNotShownOnOldVersions {
-  if (base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
-  [ChromeEarlGrey loadURL:_legacyTLSURL];
-  [ChromeEarlGrey waitForWebStateContainingText:_unsafeContent];
-}
-
 // The remaining tests in this file are only relevant for iOS 14 or later.
 
 // Test that loading a page from a server over TLS 1.0 causes the legacy TLS
 // interstitial to show.
 - (void)testLegacyTLSShowsInterstitial {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
   [ChromeEarlGrey loadURL:_legacyTLSURL];
   [ChromeEarlGrey waitForWebStateContainingText:_interstitialContent];
 }
 
 // Test that going back to safety returns the user to the previous page.
 - (void)testLegacyTLSInterstitialBackToSafety {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
   // Load a benign page first.
   [ChromeEarlGrey loadURL:_safeURL];
   [ChromeEarlGrey waitForWebStateContainingText:_safeContent];
@@ -115,9 +100,6 @@
 
 // Test that clicking through the interstitial works.
 - (void)testLegacyTLSInterstitialProceed {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
   // Load a benign page first.
   [ChromeEarlGrey loadURL:_safeURL];
   [ChromeEarlGrey waitForWebStateContainingText:_safeContent];
@@ -136,9 +118,6 @@
 // Test that clicking through the interstitial is remembered on a reload, and
 // we don't show the interstitial again.
 - (void)testLegacyTLSInterstitialAllowlist {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
   // Trigger the legacy TLS interstitial.
   [ChromeEarlGrey loadURL:_legacyTLSURL];
   [ChromeEarlGrey waitForWebStateContainingText:_interstitialContent];
@@ -161,9 +140,6 @@
 // Test that the allowlist is cleared after session restart and that we show the
 // legacy TLS interstitial again.
 - (void)testLegacyTLSInterstitialAllowlistClearedOnRestart {
-  if (!base::ios::IsRunningOnIOS14OrLater()) {
-    return;
-  }
   // Trigger the legacy TLS interstitial.
   [ChromeEarlGrey loadURL:_legacyTLSURL];
   [ChromeEarlGrey waitForWebStateContainingText:_interstitialContent];
diff --git a/ios/chrome/browser/web/navigation_egtest.mm b/ios/chrome/browser/web/navigation_egtest.mm
index 34fc844..b7ab25e 100644
--- a/ios/chrome/browser/web/navigation_egtest.mm
+++ b/ios/chrome/browser/web/navigation_egtest.mm
@@ -584,12 +584,6 @@
 // Tests that navigating forward from NTP works when resuming from session
 // restore. This is a regression test for https://crbug.com/814790.
 - (void)testRestoreHistoryToNTPAndNavigateForward {
-  // This test fails in iOS 13.4 but is fixed in iOS 14. See crbug.com/1076598.
-  if (base::ios::IsRunningOnOrLater(13, 4, 0) &&
-      !base::ios::IsRunningOnIOS14OrLater()) {
-    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 13.4 but enabled in iOS 14");
-  }
-
   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
   const GURL destinationURL = self.testServer->GetURL(kSimpleFileBasedTestURL);
   [ChromeEarlGrey loadURL:destinationURL];
diff --git a/ios/chrome/browser/widget_kit/widget_metrics_logger.swift b/ios/chrome/browser/widget_kit/widget_metrics_logger.swift
index 37f32d0..dfced661 100644
--- a/ios/chrome/browser/widget_kit/widget_metrics_logger.swift
+++ b/ios/chrome/browser/widget_kit/widget_metrics_logger.swift
@@ -6,7 +6,6 @@
 import WidgetKit
 
 /// Logs metrics associated with iOS 14 home screen widgets.
-@available(iOS 14.0, *)
 public final class WidgetsMetricLogger: NSObject {
 
   /// The queue onto which time-consuming work is dispatched.
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index ebc628c0..538a64c 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -88,7 +88,6 @@
     "//ios/chrome/browser/find_in_page",
     "//ios/chrome/browser/metrics:eg_app_support+eg2",
     "//ios/chrome/browser/ntp:features",
-    "//ios/chrome/browser/optimization_guide:eg_app_support+eg2",
     "//ios/chrome/browser/passwords",
     "//ios/chrome/browser/passwords:eg_app_support+eg2",
     "//ios/chrome/browser/policy:eg_app_support+eg2",
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn
index 739231fe..5058d89 100644
--- a/ios/chrome/test/earl_grey2/BUILD.gn
+++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -79,7 +79,6 @@
     "//ios/chrome/browser/metrics:eg2_tests",
     "//ios/chrome/browser/net:eg2_tests",
     "//ios/chrome/browser/ntp_tiles:eg2_tests",
-    "//ios/chrome/browser/optimization_guide:eg2_tests",
     "//ios/chrome/browser/passwords:eg2_tests",
     "//ios/chrome/browser/policy:eg2_tests",
     "//ios/chrome/browser/policy_url_blocking:eg2_tests",
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 1040aba..c6f2fe4 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-edc2763dbb2e2acc3e69d6e9a3edd51763f5cce5
\ No newline at end of file
+9e995606fb76abb33818848920af49495c392be5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index b8b54146..2cfd32f 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-dc9c72fbaec3c0c8a070eb1c589b752d76293861
\ No newline at end of file
+2c9e2bd4676a691f05253485b2cd74c512ecbdf7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 68be0de..c40ef446 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-f8742f02a58cdefc1f3f3abb9534ddc98a29cb3d
\ No newline at end of file
+610096f9bdfaba0dbfbd0c7530e6cb86ec8a856f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index f060a4f8..76494c5 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-de4058d853eea31253a8d695843a14ad0847b517
\ No newline at end of file
+cf8afe2097c8c2639f69f7701405011b1cfe6e71
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index aff7c2db..1ea6887 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-04bc4687ada5d113c4b0aba8c232bba54ef6aa66
\ No newline at end of file
+4d089675a12a105e8a0af62e77f0db70d708d792
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index 141fb1a..580675f 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b53d1c34a4f97cf7b31501537e97292ec431d83e
\ No newline at end of file
+3b0b014df6e4fb363690c0d9a092bc44dcf6b9b7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index d06ac16..f2e1c852 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-22e0045a7ffb9138e53e1b03dcde0dfa8145fcea
\ No newline at end of file
+15d343a1700dcf3b318b6f2a9070d10698b59aff
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 13a93840..f27b8687 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-05882d317307b81c5b006c6b001ec377752da8d3
\ No newline at end of file
+2a9ed0f5eb1a147821087194afdd84c2a12aced2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 21bc0f3..a2b4452 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-1016627a691a15f8977bc58742e6930e8ddd6de3
\ No newline at end of file
+dd1610016e54c33ae4cf455858f3f20175383e92
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index cb66d03b..7ec9154 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-7df8431d7e45e57d9f81d983001bdd74798dc16c
\ No newline at end of file
+0bd1c2a3161dc53fb958072bfebe8819cc5ba47d
\ No newline at end of file
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h b/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h
index 8c74685..7beab53 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity_interaction_manager.h
@@ -28,17 +28,10 @@
 // on iOS.
 @interface ChromeIdentityInteractionManager : NSObject
 
+// If |userEmail| is not set:
 // Starts the add account operation for a user. Presents user with the screen to
 // enter credentials.
-// Note: Calling this method will fail and the completion will be called with a
-// CHROME_IDENTITY_OPERATION_ONGOING error if there is already another add
-// account or reauthenticate operation ongoing.
-// * |viewController| will display the add account screens.
-// * |completion| will be called once the operation has finished.
-- (void)addAccountWithPresentingViewController:(UIViewController*)viewController
-                                    completion:
-                                        (SigninCompletionCallback)completion;
-
+// If |userEmail| is set:
 // Starts the reauthentication operation for a user. Presents user with the
 // screen to enter credentials with the email pre-entered.
 // Note: Calling this method will fail and the completion will be called with a
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm
index 054968b3..b57128d 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_interaction_manager.mm
@@ -106,6 +106,7 @@
 }
 
 - (void)addAccountWithPresentingViewController:(UIViewController*)viewController
+                                     userEmail:(NSString*)userEmail
                                     completion:
                                         (SigninCompletionCallback)completion {
   self.completionCallback = completion;
@@ -119,14 +120,6 @@
                              }];
 }
 
-- (void)addAccountWithPresentingViewController:(UIViewController*)viewController
-                                     userEmail:(NSString*)userEmail
-                                    completion:
-                                        (SigninCompletionCallback)completion {
-  [self addAccountWithPresentingViewController:viewController
-                                    completion:completion];
-}
-
 - (void)cancelAddAccountAnimated:(BOOL)animated
                       completion:(void (^)(void))completion {
   NSError* error = ios::provider::CreateUserCancelledSigninError();
diff --git a/ios/web_view/internal/sync/DIR_METADATA b/ios/web_view/internal/sync/DIR_METADATA
new file mode 100644
index 0000000..4a58e65
--- /dev/null
+++ b/ios/web_view/internal/sync/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/sync/COMMON_METADATA"
diff --git a/media/COMMON_METADATA b/media/COMMON_METADATA
new file mode 100644
index 0000000..0198eda
--- /dev/null
+++ b/media/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Media"
+}
\ No newline at end of file
diff --git a/media/DIR_METADATA b/media/DIR_METADATA
index 2dc14a4..69cd629e1 100644
--- a/media/DIR_METADATA
+++ b/media/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Media"
-}
\ No newline at end of file
+mixins: "//media/COMMON_METADATA"
diff --git a/media/audio/fuchsia/DIR_METADATA b/media/audio/fuchsia/DIR_METADATA
index abc57ac0f..5b3985ec 100644
--- a/media/audio/fuchsia/DIR_METADATA
+++ b/media/audio/fuchsia/DIR_METADATA
@@ -6,5 +6,5 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-team_email: "cr-fuchsia@chromium.org"
+mixins: "//build/fuchsia/COMMON_METADATA"
 os: FUCHSIA
\ No newline at end of file
diff --git a/media/capture/video/fuchsia/DIR_METADATA b/media/capture/video/fuchsia/DIR_METADATA
new file mode 100644
index 0000000..210aa6a
--- /dev/null
+++ b/media/capture/video/fuchsia/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//build/fuchsia/COMMON_METADATA"
diff --git a/media/filters/fuchsia/DIR_METADATA b/media/filters/fuchsia/DIR_METADATA
index abc57ac0f..5b3985ec 100644
--- a/media/filters/fuchsia/DIR_METADATA
+++ b/media/filters/fuchsia/DIR_METADATA
@@ -6,5 +6,5 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-team_email: "cr-fuchsia@chromium.org"
+mixins: "//build/fuchsia/COMMON_METADATA"
 os: FUCHSIA
\ No newline at end of file
diff --git a/media/fuchsia/cdm/client/BUILD.gn b/media/fuchsia/cdm/client/BUILD.gn
index fb7bd28..811750f 100644
--- a/media/fuchsia/cdm/client/BUILD.gn
+++ b/media/fuchsia/cdm/client/BUILD.gn
@@ -14,7 +14,7 @@
 
   deps = [
     "//media",
-    "//media/fuchsia/mojom",
+    "//media/fuchsia/mojom:cdm_provider",
     "//third_party/blink/public:blink_headers",
   ]
 }
diff --git a/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.cc b/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.cc
index 60c713e..a0c47dd 100644
--- a/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.cc
+++ b/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.cc
@@ -20,12 +20,11 @@
     const std::string& key_system,
     fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
         cdm_request) {
-  if (!media_resource_provider_) {
-    interface_broker_->GetInterface(
-        media_resource_provider_.BindNewPipeAndPassReceiver());
+  if (!cdm_provider_) {
+    interface_broker_->GetInterface(cdm_provider_.BindNewPipeAndPassReceiver());
   }
 
-  media_resource_provider_->CreateCdm(key_system, std::move(cdm_request));
+  cdm_provider_->CreateCdm(key_system, std::move(cdm_request));
 }
 
 }  // namespace media
diff --git a/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.h b/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.h
index aa098c2..4e63198d 100644
--- a/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.h
+++ b/media/fuchsia/cdm/client/mojo_fuchsia_cdm_provider.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "media/fuchsia/cdm/fuchsia_cdm_provider.h"
-#include "media/fuchsia/mojom/fuchsia_media_resource_provider.mojom.h"
+#include "media/fuchsia/mojom/fuchsia_cdm_provider.mojom.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
 namespace blink {
@@ -35,8 +35,7 @@
 
  private:
   blink::BrowserInterfaceBrokerProxy* const interface_broker_;
-  mojo::Remote<media::mojom::FuchsiaMediaResourceProvider>
-      media_resource_provider_;
+  mojo::Remote<media::mojom::FuchsiaCdmProvider> cdm_provider_;
 };
 
 }  // namespace media
diff --git a/media/fuchsia/mojom/BUILD.gn b/media/fuchsia/mojom/BUILD.gn
index 5d5a38d..c4e7838 100644
--- a/media/fuchsia/mojom/BUILD.gn
+++ b/media/fuchsia/mojom/BUILD.gn
@@ -14,11 +14,6 @@
   shared_cpp_typemaps = {
     types = [
       {
-        mojom = "media.mojom.CdmRequest"
-        cpp = "::fidl::InterfaceRequest<::fuchsia::media::drm::ContentDecryptionModule>"
-        move_only = true
-      },
-      {
         mojom = "media.mojom.AudioConsumerRequest"
         cpp = "::fidl::InterfaceRequest<::fuchsia::media::AudioConsumer>"
         move_only = true
@@ -33,6 +28,31 @@
     traits_public_deps = [
       "//fuchsia/mojom:traits",
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.media",
+    ]
+  }
+
+  cpp_typemaps = [ shared_cpp_typemaps ]
+  blink_cpp_typemaps = [ shared_cpp_typemaps ]
+}
+
+mojom("cdm_provider") {
+  sources = [ "fuchsia_cdm_provider.mojom" ]
+
+  export_class_attribute_blink = "BLINK_PLATFORM_EXPORT"
+  export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1"
+  export_header_blink = "third_party/blink/public/platform/web_common.h"
+
+  shared_cpp_typemaps = {
+    types = [
+      {
+        mojom = "media.mojom.CdmRequest"
+        cpp = "::fidl::InterfaceRequest<::fuchsia::media::drm::ContentDecryptionModule>"
+        move_only = true
+      },
+    ]
+    traits_headers = [ "fuchsia_cdm_provider_mojom_traits.h" ]
+    traits_public_deps = [
+      "//fuchsia/mojom:traits",
       "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.media.drm",
     ]
   }
diff --git a/media/fuchsia/mojom/fuchsia_cdm_provider.mojom b/media/fuchsia/mojom/fuchsia_cdm_provider.mojom
new file mode 100644
index 0000000..ac6eadd
--- /dev/null
+++ b/media/fuchsia/mojom/fuchsia_cdm_provider.mojom
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module media.mojom;
+
+// Mojo struct for
+// fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>.
+struct CdmRequest {
+  handle<platform> request;
+};
+
+// Interface used by the render to connect
+// fuchsia::media::drm::ContentDecryptionModule. Instances are document-scoped.
+interface FuchsiaCdmProvider {
+  // Create connection to fuchsia::media::drm::ContentDecryptionModule for
+  // |key_system|. Implementation should make sure the persistent storage is
+  // isolated per web origin.
+  CreateCdm(string key_system, CdmRequest cdm_request);
+};
diff --git a/media/fuchsia/mojom/fuchsia_cdm_provider_mojom_traits.h b/media/fuchsia/mojom/fuchsia_cdm_provider_mojom_traits.h
new file mode 100644
index 0000000..dd44fa5
--- /dev/null
+++ b/media/fuchsia/mojom/fuchsia_cdm_provider_mojom_traits.h
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_FUCHSIA_MOJOM_FUCHSIA_CDM_PROVIDER_MOJOM_TRAITS_H_
+#define MEDIA_FUCHSIA_MOJOM_FUCHSIA_CDM_PROVIDER_MOJOM_TRAITS_H_
+
+#include <fuchsia/media/drm/cpp/fidl.h>
+
+#include "fuchsia/mojom/fidl_interface_request_mojom_traits.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<
+    media::mojom::CdmRequestDataView,
+    fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>>
+    : public FidlInterfaceRequestStructTraits<
+          media::mojom::CdmRequestDataView,
+          fuchsia::media::drm::ContentDecryptionModule> {};
+
+}  // namespace mojo
+
+#endif  // MEDIA_FUCHSIA_MOJOM_FUCHSIA_CDM_PROVIDER_MOJOM_TRAITS_H_
diff --git a/media/fuchsia/mojom/fuchsia_media_resource_provider.mojom b/media/fuchsia/mojom/fuchsia_media_resource_provider.mojom
index 68a658a..596727b 100644
--- a/media/fuchsia/mojom/fuchsia_media_resource_provider.mojom
+++ b/media/fuchsia/mojom/fuchsia_media_resource_provider.mojom
@@ -4,12 +4,6 @@
 
 module media.mojom;
 
-// Mojo struct for
-// fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>.
-struct CdmRequest {
-  handle<platform> request;
-};
-
 // Mojo struct for fidl::InterfaceRequest<fuchsia::media::AudioConsumer>.
 struct AudioConsumerRequest {
   handle<platform> request;
@@ -23,11 +17,6 @@
 // Interface used by the render to create media resources. Instances are
 // document-scoped.
 interface FuchsiaMediaResourceProvider {
-  // Create connection to fuchsia::media::drm::ContentDecryptionModule for
-  // |key_system|. Implementation should make sure the persistent storage is
-  // isolated per web origin.
-  CreateCdm(string key_system, CdmRequest cdm_request);
-
   // Creates a fuchsia.media.AudioConsumer for the current frame.
   CreateAudioConsumer(AudioConsumerRequest request);
 
diff --git a/media/fuchsia/mojom/fuchsia_media_resource_provider_mojom_traits.h b/media/fuchsia/mojom/fuchsia_media_resource_provider_mojom_traits.h
index ef2ddd5..29aa82a5 100644
--- a/media/fuchsia/mojom/fuchsia_media_resource_provider_mojom_traits.h
+++ b/media/fuchsia/mojom/fuchsia_media_resource_provider_mojom_traits.h
@@ -5,21 +5,13 @@
 #ifndef MEDIA_FUCHSIA_MOJOM_FUCHSIA_MEDIA_RESOURCE_PROVIDER_MOJOM_TRAITS_H_
 #define MEDIA_FUCHSIA_MOJOM_FUCHSIA_MEDIA_RESOURCE_PROVIDER_MOJOM_TRAITS_H_
 
-#include <fuchsia/media/drm/cpp/fidl.h>
+#include <fuchsia/media/cpp/fidl.h>
 
 #include "fuchsia/mojom/fidl_interface_request_mojom_traits.h"
 
 namespace mojo {
 
 template <>
-struct StructTraits<
-    media::mojom::CdmRequestDataView,
-    fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>>
-    : public FidlInterfaceRequestStructTraits<
-          media::mojom::CdmRequestDataView,
-          fuchsia::media::drm::ContentDecryptionModule> {};
-
-template <>
 struct StructTraits<media::mojom::AudioConsumerRequestDataView,
                     fidl::InterfaceRequest<fuchsia::media::AudioConsumer>>
     : public FidlInterfaceRequestStructTraits<
diff --git a/net/COMMON_METADATA b/net/COMMON_METADATA
new file mode 100644
index 0000000..5296aae
--- /dev/null
+++ b/net/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Network"
+}
+team_email: "net-dev@chromium.org"
\ No newline at end of file
diff --git a/net/DIR_METADATA b/net/DIR_METADATA
index 7047164..11505f6a 100644
--- a/net/DIR_METADATA
+++ b/net/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Network"
-}
-team_email: "net-dev@chromium.org"
\ No newline at end of file
+mixins: "//net/COMMON_METADATA"
diff --git a/net/cookies/COMMON_METADATA b/net/cookies/COMMON_METADATA
new file mode 100644
index 0000000..191a115
--- /dev/null
+++ b/net/cookies/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Network>Cookies"
+}
\ No newline at end of file
diff --git a/net/cookies/DIR_METADATA b/net/cookies/DIR_METADATA
index 69f95ee..7499c32 100644
--- a/net/cookies/DIR_METADATA
+++ b/net/cookies/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Network>Cookies"
-}
\ No newline at end of file
+mixins: "//net/cookies/COMMON_METADATA"
diff --git a/net/dns/public/win_dns_system_settings_unittest.cc b/net/dns/public/win_dns_system_settings_unittest.cc
index 96ede05..4352df3 100644
--- a/net/dns/public/win_dns_system_settings_unittest.cc
+++ b/net/dns/public/win_dns_system_settings_unittest.cc
@@ -74,7 +74,8 @@
   return heap;
 }
 
-TEST(WinDnsSystemSettings, GetAllNameServersEmpty) {
+// TODO(crbug/1253805): Fix and reenable the test.
+TEST(WinDnsSystemSettings, DISABLED_GetAllNameServersEmpty) {
   AdapterInfo infos[2] = {
       {
           .if_type = IF_TYPE_USB,
@@ -98,7 +99,9 @@
   EXPECT_TRUE(nameservers.value().empty());
 }
 
-TEST(WinDnsSystemSettings, GetAllNameServersStatelessDiscoveryAdresses) {
+// TODO(crbug/1253805): Fix and reenable the test.
+TEST(WinDnsSystemSettings,
+     DISABLED_GetAllNameServersStatelessDiscoveryAdresses) {
   AdapterInfo infos[2] = {
       {
           .if_type = IF_TYPE_USB,
@@ -121,7 +124,8 @@
   EXPECT_TRUE(nameservers.value().empty());
 }
 
-TEST(WinDnsSystemSettings, GetAllNameServersValid) {
+// TODO(crbug/1253805): Fix and reenable the test.
+TEST(WinDnsSystemSettings, DISABLED_GetAllNameServersValid) {
   AdapterInfo infos[2] = {
       {.if_type = IF_TYPE_USB,
        .oper_status = IfOperStatusUp,
diff --git a/net/nqe/COMMON_METADATA b/net/nqe/COMMON_METADATA
new file mode 100644
index 0000000..8bb481ff
--- /dev/null
+++ b/net/nqe/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Network>NetworkQuality"
+}
\ No newline at end of file
diff --git a/net/nqe/DIR_METADATA b/net/nqe/DIR_METADATA
index 486a7d11..bdd33fcf 100644
--- a/net/nqe/DIR_METADATA
+++ b/net/nqe/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Network>NetworkQuality"
-}
\ No newline at end of file
+mixins: "//net/nqe/COMMON_METADATA"
diff --git a/net/quic/COMMON_METADATA b/net/quic/COMMON_METADATA
new file mode 100644
index 0000000..2613ad6
--- /dev/null
+++ b/net/quic/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Network>QUIC"
+}
\ No newline at end of file
diff --git a/net/quic/DIR_METADATA b/net/quic/DIR_METADATA
index a745a9d..3ee11f1 100644
--- a/net/quic/DIR_METADATA
+++ b/net/quic/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Network>QUIC"
-}
\ No newline at end of file
+mixins: "//net/quic/COMMON_METADATA"
diff --git a/net/tools/quic/DIR_METADATA b/net/tools/quic/DIR_METADATA
index a745a9d..3ee11f1 100644
--- a/net/tools/quic/DIR_METADATA
+++ b/net/tools/quic/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Network>QUIC"
-}
\ No newline at end of file
+mixins: "//net/quic/COMMON_METADATA"
diff --git a/pdf/COMMON_METADATA b/pdf/COMMON_METADATA
new file mode 100644
index 0000000..bfb1239
--- /dev/null
+++ b/pdf/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Plugins>PDF"
+}
\ No newline at end of file
diff --git a/pdf/DIR_METADATA b/pdf/DIR_METADATA
index 8734c2b..7ec54c5d 100644
--- a/pdf/DIR_METADATA
+++ b/pdf/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Plugins>PDF"
-}
\ No newline at end of file
+mixins: "//pdf/COMMON_METADATA"
diff --git a/printing/COMMON_METADATA b/printing/COMMON_METADATA
new file mode 100644
index 0000000..b4a91a0
--- /dev/null
+++ b/printing/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Printing"
+}
\ No newline at end of file
diff --git a/printing/DIR_METADATA b/printing/DIR_METADATA
index 751a2f1..2dc7b8c 100644
--- a/printing/DIR_METADATA
+++ b/printing/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Printing"
-}
\ No newline at end of file
+mixins: "//printing/COMMON_METADATA"
diff --git a/printing/sandbox/DIR_METADATA b/printing/sandbox/DIR_METADATA
new file mode 100644
index 0000000..9ca68bc
--- /dev/null
+++ b/printing/sandbox/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//sandbox/COMMON_METADATA"
diff --git a/sandbox/COMMON_METADATA b/sandbox/COMMON_METADATA
new file mode 100644
index 0000000..5732266
--- /dev/null
+++ b/sandbox/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Sandbox"
+}
+team_email: "security-dev@chromium.org"
\ No newline at end of file
diff --git a/sandbox/DIR_METADATA b/sandbox/DIR_METADATA
index 053acd7..795d9c5 100644
--- a/sandbox/DIR_METADATA
+++ b/sandbox/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Sandbox"
-}
-team_email: "security-dev@chromium.org"
\ No newline at end of file
+mixins: "//sandbox/COMMON_METADATA"
diff --git a/services/COMMON_METADATA b/services/COMMON_METADATA
new file mode 100644
index 0000000..c4a575a8
--- /dev/null
+++ b/services/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Services"
+}
\ No newline at end of file
diff --git a/services/DIR_METADATA b/services/DIR_METADATA
index 674a002..6bc88c2 100644
--- a/services/DIR_METADATA
+++ b/services/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Services"
-}
\ No newline at end of file
+mixins: "//services/COMMON_METADATA"
diff --git a/services/audio/COMMON_METADATA b/services/audio/COMMON_METADATA
new file mode 100644
index 0000000..4a9994d
--- /dev/null
+++ b/services/audio/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Media>Audio"
+}
\ No newline at end of file
diff --git a/services/audio/DIR_METADATA b/services/audio/DIR_METADATA
index e80d7931..b23a7add 100644
--- a/services/audio/DIR_METADATA
+++ b/services/audio/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Media>Audio"
-}
\ No newline at end of file
+mixins: "//services/audio/COMMON_METADATA"
diff --git a/services/device/COMMON_METADATA b/services/device/COMMON_METADATA
new file mode 100644
index 0000000..1050252
--- /dev/null
+++ b/services/device/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Services>Device"
+}
+team_email: "device-dev@chromium.org"
\ No newline at end of file
diff --git a/services/device/DIR_METADATA b/services/device/DIR_METADATA
index 78f0fb6..9790079 100644
--- a/services/device/DIR_METADATA
+++ b/services/device/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Services>Device"
-}
-team_email: "device-dev@chromium.org"
\ No newline at end of file
+mixins: "//services/device/COMMON_METADATA"
diff --git a/services/device/generic_sensor/COMMON_METADATA b/services/device/generic_sensor/COMMON_METADATA
new file mode 100644
index 0000000..7d50967
--- /dev/null
+++ b/services/device/generic_sensor/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Sensor"
+}
\ No newline at end of file
diff --git a/services/device/generic_sensor/DIR_METADATA b/services/device/generic_sensor/DIR_METADATA
index 8086a0c..dcf79e4 100644
--- a/services/device/generic_sensor/DIR_METADATA
+++ b/services/device/generic_sensor/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Blink>Sensor"
-}
\ No newline at end of file
+mixins: "//services/device/generic_sensor/COMMON_METADATA"
diff --git a/services/device/nfc/DIR_METADATA b/services/device/nfc/DIR_METADATA
index fddc30b..f42a037 100644
--- a/services/device/nfc/DIR_METADATA
+++ b/services/device/nfc/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Blink>NFC"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/nfc/COMMON_METADATA"
diff --git a/services/device/usb/DIR_METADATA b/services/device/usb/DIR_METADATA
index f4613891..32aa0ec9 100644
--- a/services/device/usb/DIR_METADATA
+++ b/services/device/usb/DIR_METADATA
@@ -6,6 +6,7 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
+mixins: "//chrome/browser/usb/COMMON_METADATA"
 monorail {
   component: "IO>USB"
 }
\ No newline at end of file
diff --git a/services/media_session/COMMON_METADATA b/services/media_session/COMMON_METADATA
new file mode 100644
index 0000000..28cafbcc
--- /dev/null
+++ b/services/media_session/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>Media>Session"
+}
+team_email: "media-dev@chromium.org"
\ No newline at end of file
diff --git a/services/media_session/DIR_METADATA b/services/media_session/DIR_METADATA
index dd031b9b..ad460e95 100644
--- a/services/media_session/DIR_METADATA
+++ b/services/media_session/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Media>Session"
-}
-team_email: "media-dev@chromium.org"
\ No newline at end of file
+mixins: "//services/media_session/COMMON_METADATA"
diff --git a/services/metrics/DIR_METADATA b/services/metrics/DIR_METADATA
index 1867dd61ee..8dbbaf6 100644
--- a/services/metrics/DIR_METADATA
+++ b/services/metrics/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Metrics"
-}
\ No newline at end of file
+mixins: "//base/metrics/COMMON_METADATA"
diff --git a/services/network/origin_policy/COMMON_METADATA b/services/network/origin_policy/COMMON_METADATA
new file mode 100644
index 0000000..0999d53
--- /dev/null
+++ b/services/network/origin_policy/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>SecurityFeature"
+}
\ No newline at end of file
diff --git a/services/network/origin_policy/DIR_METADATA b/services/network/origin_policy/DIR_METADATA
index 91bf639..616e28c5 100644
--- a/services/network/origin_policy/DIR_METADATA
+++ b/services/network/origin_policy/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Blink>SecurityFeature"
-}
\ No newline at end of file
+mixins: "//services/network/origin_policy/COMMON_METADATA"
diff --git a/services/resource_coordinator/COMMON_METADATA b/services/resource_coordinator/COMMON_METADATA
new file mode 100644
index 0000000..35eeb9be
--- /dev/null
+++ b/services/resource_coordinator/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Internals>PerformanceManager"
+}
+team_email: "catan-team@chromium.org"
\ No newline at end of file
diff --git a/services/resource_coordinator/DIR_METADATA b/services/resource_coordinator/DIR_METADATA
index 810880b..6b15a83a 100644
--- a/services/resource_coordinator/DIR_METADATA
+++ b/services/resource_coordinator/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>PerformanceManager"
-}
-team_email: "catan-team@chromium.org"
\ No newline at end of file
+mixins: "//services/resource_coordinator/COMMON_METADATA"
diff --git a/services/resource_coordinator/memory_instrumentation/COMMON_METADATA b/services/resource_coordinator/memory_instrumentation/COMMON_METADATA
new file mode 100644
index 0000000..dd2bdaf6
--- /dev/null
+++ b/services/resource_coordinator/memory_instrumentation/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Instrumentation>Memory"
+}
\ No newline at end of file
diff --git a/services/resource_coordinator/memory_instrumentation/DIR_METADATA b/services/resource_coordinator/memory_instrumentation/DIR_METADATA
index a44cefd..1632b49 100644
--- a/services/resource_coordinator/memory_instrumentation/DIR_METADATA
+++ b/services/resource_coordinator/memory_instrumentation/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Instrumentation>Memory"
-}
\ No newline at end of file
+mixins: "//services/resource_coordinator/memory_instrumentation/COMMON_METADATA"
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/DIR_METADATA b/services/resource_coordinator/public/cpp/memory_instrumentation/DIR_METADATA
new file mode 100644
index 0000000..aa12597
--- /dev/null
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//services/resource_coordinator/memory_instrumentation/COMMON_METADATA"
diff --git a/services/viz/DIR_METADATA b/services/viz/DIR_METADATA
index 4636c07..8ff07801 100644
--- a/services/viz/DIR_METADATA
+++ b/services/viz/DIR_METADATA
@@ -6,6 +6,7 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
+mixins: "//components/viz/COMMON_METADATA"
 monorail {
   component: "Internals>Services>Viz"
 }
\ No newline at end of file
diff --git a/services/viz/public/cpp/gpu/DIR_METADATA b/services/viz/public/cpp/gpu/DIR_METADATA
index ddce9625..2907f304 100644
--- a/services/viz/public/cpp/gpu/DIR_METADATA
+++ b/services/viz/public/cpp/gpu/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>GPU>Internals"
-}
\ No newline at end of file
+mixins: "//gpu/COMMON_METADATA"
diff --git a/storage/browser/blob/COMMON_METADATA b/storage/browser/blob/COMMON_METADATA
new file mode 100644
index 0000000..cec432d
--- /dev/null
+++ b/storage/browser/blob/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Storage>FileAPI"
+}
diff --git a/storage/browser/blob/DIR_METADATA b/storage/browser/blob/DIR_METADATA
index 30c02fb..9d48ccf 100644
--- a/storage/browser/blob/DIR_METADATA
+++ b/storage/browser/blob/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Blink>Storage>FileAPI"
-}
+mixins: "//storage/browser/blob/COMMON_METADATA"
diff --git a/storage/browser/quota/COMMON_METADATA b/storage/browser/quota/COMMON_METADATA
new file mode 100644
index 0000000..cf9ebe3
--- /dev/null
+++ b/storage/browser/quota/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Storage>Quota"
+}
diff --git a/storage/browser/quota/DIR_METADATA b/storage/browser/quota/DIR_METADATA
index f3365fa..406a1ebf 100644
--- a/storage/browser/quota/DIR_METADATA
+++ b/storage/browser/quota/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Blink>Storage>Quota"
-}
+mixins: "//storage/browser/quota/COMMON_METADATA"
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index e4e6ffa..e5be936 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -29069,7 +29069,8 @@
       {
         "args": [
           "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
+          "--recover-devices",
+          "--test-launcher-filter-file=../../testing/buildbot/filters/android-cronet-arm64-rel-marshmallow-tests.cronet_test_instrumentation_apk.filter"
         ],
         "merge": {
           "args": [
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index c78c26d..4cf1e7ca 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5898,21 +5898,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "dimension_sets": [
@@ -6006,21 +6006,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 5e5bfa77c..a34c8709 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -8798,11 +8798,6 @@
       }
     ]
   },
-  "ToTAndroidCoverage x86": {
-    "additional_compile_targets": [
-      "all"
-    ]
-  },
   "ToTAndroidOfficial": {
     "additional_compile_targets": [
       "all"
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 0049385..1e73bdf 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -83451,7 +83451,7 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "isolate_profile_data": true,
@@ -83459,14 +83459,14 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -83543,7 +83543,7 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "isolate_profile_data": true,
@@ -83551,14 +83551,14 @@
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -84927,21 +84927,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "dimension_sets": [
@@ -85039,21 +85039,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "dimension_sets": [
@@ -86594,21 +86594,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "dimension_sets": [
@@ -86706,21 +86706,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "dimension_sets": [
@@ -87463,21 +87463,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -87559,21 +87559,21 @@
       },
       {
         "args": [
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome",
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4655.4",
+        "name": "lacros_chrome_browsertests_run_in_series_Lacros version skew testing ash 96.0.4656.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v96.0.4655.4",
-              "revision": "version:96.0.4655.4"
+              "location": "lacros_version_skew_tests_v96.0.4656.0",
+              "revision": "version:96.0.4656.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index f4964bb..bdf45a82 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -161,6 +161,12 @@
       [ "//testing/buildbot/filters/android.emulator_11.crashpad_tests.filter" ]
 }
 
+source_set("cronet_test_instrumentation_apk_filters") {
+  testonly = true
+
+  data = [ "//testing/buildbot/filters/android-cronet-arm64-rel-marshmallow-tests.cronet_test_instrumentation_apk.filter" ]
+}
+
 source_set("sync_integration_tests_filters") {
   testonly = true
 
diff --git a/testing/buildbot/filters/android-cronet-arm64-rel-marshmallow-tests.cronet_test_instrumentation_apk.filter b/testing/buildbot/filters/android-cronet-arm64-rel-marshmallow-tests.cronet_test_instrumentation_apk.filter
new file mode 100644
index 0000000..dd68563
--- /dev/null
+++ b/testing/buildbot/filters/android-cronet-arm64-rel-marshmallow-tests.cronet_test_instrumentation_apk.filter
@@ -0,0 +1,4 @@
+# crbug.com/1248421
+-NQETest.testQuicDisable
+-QuicTest.testQuicLoadUrl
+-QuicTest.testNQEWithQuic
diff --git a/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter b/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter
index d52a20a8..4114778 100644
--- a/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter
+++ b/testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter
@@ -7,7 +7,7 @@
 -BookmarkBarViewTest*
 -ChromeVisibilityObserverInteractiveTest.VisibilityTest
 -ClipboardTest/PlatformClipboardTest.ReadAvailablePlatformSpecificFormatNamesTest
--CrossSiteSubframe/DragAndDropBrowserTest*
+-CrossSiteSubframe/DragAndDrop*BrowserTest*
 -DesktopWidgetTestInteractive.DesktopNativeWidgetWithModalTransientChild
 -DesktopWindowTreeHostLinuxTest.CaptureEventForwarding
 -DesktopWindowTreeHostLinuxTest.Deactivate
diff --git a/testing/buildbot/filters/ozone-linux.interactive_ui_tests_wayland.filter b/testing/buildbot/filters/ozone-linux.interactive_ui_tests_wayland.filter
index 567a710..b686edd 100644
--- a/testing/buildbot/filters/ozone-linux.interactive_ui_tests_wayland.filter
+++ b/testing/buildbot/filters/ozone-linux.interactive_ui_tests_wayland.filter
@@ -27,7 +27,7 @@
 -ChromeVisibilityObserverInteractiveTest.VisibilityTest
 -CrossSiteSubframe/DragAndDropBrowserTest.CrossSiteDrag/0
 -CrossSiteSubframe/DragAndDropBrowserTest.CrossTabDrag/0
--CrossSiteSubframe/DragAndDropBrowserTest.DragStartInFrame/0
+-CrossSiteSubframe/DragAndDropWithoutScalingBrowserTest.DragStartInFrame/*
 -DesktopWidgetTestInteractive.DesktopNativeWidgetWithModalTransientChild
 -DesktopWindowTreeHostLinuxTest.CaptureEventForwarding
 -DesktopWindowTreeHostLinuxTest.Deactivate
@@ -51,7 +51,7 @@
 -PopupBlockerBrowserTest.ModalPopUnder
 -SameSiteSubframe/DragAndDropBrowserTest.CrossSiteDrag/0
 -SameSiteSubframe/DragAndDropBrowserTest.CrossTabDrag/0
--SameSiteSubframe/DragAndDropBrowserTest.DragStartInFrame/0
+-SameSiteSubframe/DragAndDropWithoutScalingBrowserTest.DragStartInFrame/*
 -SessionRestoreInteractiveTest.RestoreMinimizedWindow
 -SitePerProcessInteractiveBrowserTest.TabAndMouseFocusNavigation
 -StartupBrowserCreatorTest.LastUsedProfileActivated
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index c90b42f..7d520044 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1453,6 +1453,15 @@
       },
     },
   },
+  'cronet_test_instrumentation_apk': {
+    'modifications': {
+      'android-cronet-arm64-rel-marshmallow-tests': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/android-cronet-arm64-rel-marshmallow-tests.cronet_test_instrumentation_apk.filter',
+        ],
+      },
+    },
+  },
   'depth_capture_tests': {
     'remove_from': [
       # TODO(https://crbug.com/850107): Remove the Android FYI Release (Pixel 2)
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 6bd5dcf..0434add 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -52,16 +52,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4655.4/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v96.0.4656.0/test_ash_chrome',
       '--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter',
     ],
-    'identifier': 'Lacros version skew testing ash 96.0.4655.4',
+    'identifier': 'Lacros version skew testing ash 96.0.4656.0',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v96.0.4655.4',
-          'revision': 'version:96.0.4655.4',
+          'location': 'lacros_version_skew_tests_v96.0.4656.0',
+          'revision': 'version:96.0.4656.0',
         },
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 94201e8..a8ef7b1d 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1631,11 +1631,6 @@
           'all',
         ],
       },
-      'ToTAndroidCoverage x86': {
-        'additional_compile_targets': [
-          'all',
-        ],
-      },
       'ToTAndroidOfficial': {
         'additional_compile_targets': [
           'all',
diff --git a/third_party/blink/common/blob/DIR_METADATA b/third_party/blink/common/blob/DIR_METADATA
index 955fe831..df68346 100644
--- a/third_party/blink/common/blob/DIR_METADATA
+++ b/third_party/blink/common/blob/DIR_METADATA
@@ -1,5 +1,3 @@
-monorail {
-  component: "Blink>Storage>FileAPI"
-}
+mixins: "//storage/browser/blob/COMMON_METADATA"
 
 team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/common/bluetooth/DIR_METADATA b/third_party/blink/common/bluetooth/DIR_METADATA
index 002457dc..c7987cd 100644
--- a/third_party/blink/common/bluetooth/DIR_METADATA
+++ b/third_party/blink/common/bluetooth/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Bluetooth"
-}
+mixins: "//content/browser/bluetooth/COMMON_METADATA"
 
-team_email: "web-bluetooth@chromium.org"
diff --git a/third_party/blink/common/cache_storage/DIR_METADATA b/third_party/blink/common/cache_storage/DIR_METADATA
new file mode 100644
index 0000000..306fb835
--- /dev/null
+++ b/third_party/blink/common/cache_storage/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/cache_storage/COMMON_METADATA"
diff --git a/third_party/blink/common/fetch/DIR_METADATA b/third_party/blink/common/fetch/DIR_METADATA
index dbf3715..08e5ee1 100644
--- a/third_party/blink/common/fetch/DIR_METADATA
+++ b/third_party/blink/common/fetch/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Network>FetchAPI"
-}
+mixins: "//third_party/blink/renderer/core/fetch/COMMON_METADATA"
 
-team_email: "blink-network-dev@chromium.org"
diff --git a/third_party/blink/common/manifest/DIR_METADATA b/third_party/blink/common/manifest/DIR_METADATA
index 0ff3ed55..78b240e 100644
--- a/third_party/blink/common/manifest/DIR_METADATA
+++ b/third_party/blink/common/manifest/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>AppManifest"
-}
+mixins: "//third_party/blink/renderer/modules/manifest/COMMON_METADATA"
diff --git a/third_party/blink/common/mediastream/COMMON_METADATA b/third_party/blink/common/mediastream/COMMON_METADATA
new file mode 100644
index 0000000..066f18a
--- /dev/null
+++ b/third_party/blink/common/mediastream/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>GetUserMedia"
+}
+
+team_email: "webrtc-dev@chromium.org"
diff --git a/third_party/blink/common/mediastream/DIR_METADATA b/third_party/blink/common/mediastream/DIR_METADATA
index 066f18a..50babda 100644
--- a/third_party/blink/common/mediastream/DIR_METADATA
+++ b/third_party/blink/common/mediastream/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>GetUserMedia"
-}
+mixins: "//third_party/blink/common/mediastream/COMMON_METADATA"
 
-team_email: "webrtc-dev@chromium.org"
diff --git a/third_party/blink/common/notifications/DIR_METADATA b/third_party/blink/common/notifications/DIR_METADATA
index e05071ce..47e6248 100644
--- a/third_party/blink/common/notifications/DIR_METADATA
+++ b/third_party/blink/common/notifications/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Notifications"
-}
+mixins: "//content/browser/notifications/COMMON_METADATA"
 
-team_email: "platform-capabilities@chromium.org"
diff --git a/third_party/blink/common/origin_trials/COMMON_METADATA b/third_party/blink/common/origin_trials/COMMON_METADATA
new file mode 100644
index 0000000..69a375b1
--- /dev/null
+++ b/third_party/blink/common/origin_trials/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Internals>OriginTrials"
+}
+
+team_email: "experimentation-dev@chromium.org"
diff --git a/third_party/blink/common/origin_trials/DIR_METADATA b/third_party/blink/common/origin_trials/DIR_METADATA
index 69a375b1..247c6a90 100644
--- a/third_party/blink/common/origin_trials/DIR_METADATA
+++ b/third_party/blink/common/origin_trials/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>OriginTrials"
-}
+mixins: "//third_party/blink/common/origin_trials/COMMON_METADATA"
 
-team_email: "experimentation-dev@chromium.org"
diff --git a/third_party/blink/common/peerconnection/DIR_METADATA b/third_party/blink/common/peerconnection/DIR_METADATA
new file mode 100644
index 0000000..7c8a8e8
--- /dev/null
+++ b/third_party/blink/common/peerconnection/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/peerconnection/COMMON_METADATA"
diff --git a/third_party/blink/common/permissions/DIR_METADATA b/third_party/blink/common/permissions/DIR_METADATA
index e558745..961484f 100644
--- a/third_party/blink/common/permissions/DIR_METADATA
+++ b/third_party/blink/common/permissions/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>PermissionsAPI"
-}
+mixins: "//third_party/blink/renderer/modules/permissions/COMMON_METADATA"
diff --git a/third_party/blink/common/permissions_policy/COMMON_METADATA b/third_party/blink/common/permissions_policy/COMMON_METADATA
new file mode 100644
index 0000000..3eb37bc
--- /dev/null
+++ b/third_party/blink/common/permissions_policy/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>FeaturePolicy"
+}
diff --git a/third_party/blink/common/permissions_policy/DIR_METADATA b/third_party/blink/common/permissions_policy/DIR_METADATA
index 3eb37bc..fbe9b746 100644
--- a/third_party/blink/common/permissions_policy/DIR_METADATA
+++ b/third_party/blink/common/permissions_policy/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>FeaturePolicy"
-}
+mixins: "//third_party/blink/common/permissions_policy/COMMON_METADATA"
diff --git a/third_party/blink/common/privacy_budget/DIR_METADATA b/third_party/blink/common/privacy_budget/DIR_METADATA
index 8799ee18..5e0dd183 100644
--- a/third_party/blink/common/privacy_budget/DIR_METADATA
+++ b/third_party/blink/common/privacy_budget/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Privacy>Fingerprinting"
-}
+mixins: "//third_party/blink/public/common/privacy_budget/COMMON_METADATA"
 
-team_email: "privacy-sandbox-dev@chromium.org"
diff --git a/third_party/blink/common/scheduler/DIR_METADATA b/third_party/blink/common/scheduler/DIR_METADATA
new file mode 100644
index 0000000..99b25bc
--- /dev/null
+++ b/third_party/blink/common/scheduler/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/platform/scheduler/COMMON_METADATA"
diff --git a/third_party/blink/common/service_worker/DIR_METADATA b/third_party/blink/common/service_worker/DIR_METADATA
index 2a951d09..72616d6 100644
--- a/third_party/blink/common/service_worker/DIR_METADATA
+++ b/third_party/blink/common/service_worker/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
+mixins: "//content/browser/service_worker/COMMON_METADATA"
 
-team_email: "worker-dev@chromium.org"
diff --git a/third_party/blink/perf_tests/css/DIR_METADATA b/third_party/blink/perf_tests/css/DIR_METADATA
new file mode 100644
index 0000000..2c25ef65
--- /dev/null
+++ b/third_party/blink/perf_tests/css/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/core/css/COMMON_METADATA"
diff --git a/third_party/blink/perf_tests/dom/DIR_METADATA b/third_party/blink/perf_tests/dom/DIR_METADATA
new file mode 100644
index 0000000..eccaabb
--- /dev/null
+++ b/third_party/blink/perf_tests/dom/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/core/dom/COMMON_METADATA"
diff --git a/third_party/blink/perf_tests/parser/DIR_METADATA b/third_party/blink/perf_tests/parser/DIR_METADATA
new file mode 100644
index 0000000..2f78df8
--- /dev/null
+++ b/third_party/blink/perf_tests/parser/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/core/html/parser/COMMON_METADATA"
diff --git a/third_party/blink/perf_tests/webgl/DIR_METADATA b/third_party/blink/perf_tests/webgl/DIR_METADATA
new file mode 100644
index 0000000..216bb112
--- /dev/null
+++ b/third_party/blink/perf_tests/webgl/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/webgl/COMMON_METADATA"
diff --git a/third_party/blink/perf_tests/webgpu/DIR_METADATA b/third_party/blink/perf_tests/webgpu/DIR_METADATA
new file mode 100644
index 0000000..45a4c8d
--- /dev/null
+++ b/third_party/blink/perf_tests/webgpu/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/webgpu/COMMON_METADATA"
diff --git a/third_party/blink/public/common/blob/DIR_METADATA b/third_party/blink/public/common/blob/DIR_METADATA
index 955fe831..df68346 100644
--- a/third_party/blink/public/common/blob/DIR_METADATA
+++ b/third_party/blink/public/common/blob/DIR_METADATA
@@ -1,5 +1,3 @@
-monorail {
-  component: "Blink>Storage>FileAPI"
-}
+mixins: "//storage/browser/blob/COMMON_METADATA"
 
 team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/common/bluetooth/DIR_METADATA b/third_party/blink/public/common/bluetooth/DIR_METADATA
index 002457dc..c7987cd 100644
--- a/third_party/blink/public/common/bluetooth/DIR_METADATA
+++ b/third_party/blink/public/common/bluetooth/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Bluetooth"
-}
+mixins: "//content/browser/bluetooth/COMMON_METADATA"
 
-team_email: "web-bluetooth@chromium.org"
diff --git a/third_party/blink/public/common/cache_storage/DIR_METADATA b/third_party/blink/public/common/cache_storage/DIR_METADATA
index 787f6c41..aa6e552 100644
--- a/third_party/blink/public/common/cache_storage/DIR_METADATA
+++ b/third_party/blink/public/common/cache_storage/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>CacheStorage"
-}
+mixins: "//content/browser/cache_storage/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/common/css/DIR_METADATA b/third_party/blink/public/common/css/DIR_METADATA
index 1876fb3..e19b821b 100644
--- a/third_party/blink/public/common/css/DIR_METADATA
+++ b/third_party/blink/public/common/css/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>CSS"
-}
+mixins: "//third_party/blink/renderer/core/css/COMMON_METADATA"
 
-team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/public/common/fetch/DIR_METADATA b/third_party/blink/public/common/fetch/DIR_METADATA
index dbf3715..08e5ee1 100644
--- a/third_party/blink/public/common/fetch/DIR_METADATA
+++ b/third_party/blink/public/common/fetch/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Network>FetchAPI"
-}
+mixins: "//third_party/blink/renderer/core/fetch/COMMON_METADATA"
 
-team_email: "blink-network-dev@chromium.org"
diff --git a/third_party/blink/public/common/font_access/DIR_METADATA b/third_party/blink/public/common/font_access/DIR_METADATA
index 58e4513..be579e99 100644
--- a/third_party/blink/public/common/font_access/DIR_METADATA
+++ b/third_party/blink/public/common/font_access/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Storage>FontAccess"
-}
+mixins: "//content/browser/font_access/COMMON_METADATA"
diff --git a/third_party/blink/public/common/manifest/DIR_METADATA b/third_party/blink/public/common/manifest/DIR_METADATA
index 0ff3ed55..78b240e 100644
--- a/third_party/blink/public/common/manifest/DIR_METADATA
+++ b/third_party/blink/public/common/manifest/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>AppManifest"
-}
+mixins: "//third_party/blink/renderer/modules/manifest/COMMON_METADATA"
diff --git a/third_party/blink/public/common/media/DIR_METADATA b/third_party/blink/public/common/media/DIR_METADATA
index 6667e7f..41e8f64 100644
--- a/third_party/blink/public/common/media/DIR_METADATA
+++ b/third_party/blink/public/common/media/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Media"
-}
+mixins: "//media/COMMON_METADATA"
diff --git a/third_party/blink/public/common/net/DIR_METADATA b/third_party/blink/public/common/net/DIR_METADATA
new file mode 100644
index 0000000..09f5b5e
--- /dev/null
+++ b/third_party/blink/public/common/net/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//net/COMMON_METADATA"
diff --git a/third_party/blink/public/common/notifications/DIR_METADATA b/third_party/blink/public/common/notifications/DIR_METADATA
index e05071ce..47e6248 100644
--- a/third_party/blink/public/common/notifications/DIR_METADATA
+++ b/third_party/blink/public/common/notifications/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Notifications"
-}
+mixins: "//content/browser/notifications/COMMON_METADATA"
 
-team_email: "platform-capabilities@chromium.org"
diff --git a/third_party/blink/public/common/origin_trials/DIR_METADATA b/third_party/blink/public/common/origin_trials/DIR_METADATA
new file mode 100644
index 0000000..14641a38
--- /dev/null
+++ b/third_party/blink/public/common/origin_trials/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/common/origin_trials/COMMON_METADATA"
diff --git a/third_party/blink/public/common/peerconnection/DIR_METADATA b/third_party/blink/public/common/peerconnection/DIR_METADATA
new file mode 100644
index 0000000..7c8a8e8
--- /dev/null
+++ b/third_party/blink/public/common/peerconnection/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/peerconnection/COMMON_METADATA"
diff --git a/third_party/blink/public/common/permissions/DIR_METADATA b/third_party/blink/public/common/permissions/DIR_METADATA
index e558745..961484f 100644
--- a/third_party/blink/public/common/permissions/DIR_METADATA
+++ b/third_party/blink/public/common/permissions/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>PermissionsAPI"
-}
+mixins: "//third_party/blink/renderer/modules/permissions/COMMON_METADATA"
diff --git a/third_party/blink/public/common/privacy_budget/COMMON_METADATA b/third_party/blink/public/common/privacy_budget/COMMON_METADATA
new file mode 100644
index 0000000..8799ee18
--- /dev/null
+++ b/third_party/blink/public/common/privacy_budget/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Privacy>Fingerprinting"
+}
+
+team_email: "privacy-sandbox-dev@chromium.org"
diff --git a/third_party/blink/public/common/privacy_budget/DIR_METADATA b/third_party/blink/public/common/privacy_budget/DIR_METADATA
index 8799ee18..5e0dd183 100644
--- a/third_party/blink/public/common/privacy_budget/DIR_METADATA
+++ b/third_party/blink/public/common/privacy_budget/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Privacy>Fingerprinting"
-}
+mixins: "//third_party/blink/public/common/privacy_budget/COMMON_METADATA"
 
-team_email: "privacy-sandbox-dev@chromium.org"
diff --git a/third_party/blink/public/common/scheduler/DIR_METADATA b/third_party/blink/public/common/scheduler/DIR_METADATA
new file mode 100644
index 0000000..99b25bc
--- /dev/null
+++ b/third_party/blink/public/common/scheduler/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/platform/scheduler/COMMON_METADATA"
diff --git a/third_party/blink/public/common/service_worker/DIR_METADATA b/third_party/blink/public/common/service_worker/DIR_METADATA
index 2a951d09..72616d6 100644
--- a/third_party/blink/public/common/service_worker/DIR_METADATA
+++ b/third_party/blink/public/common/service_worker/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
+mixins: "//content/browser/service_worker/COMMON_METADATA"
 
-team_email: "worker-dev@chromium.org"
diff --git a/third_party/blink/public/common/sms/DIR_METADATA b/third_party/blink/public/common/sms/DIR_METADATA
index 9ade438..ec8e734 100644
--- a/third_party/blink/public/common/sms/DIR_METADATA
+++ b/third_party/blink/public/common/sms/DIR_METADATA
@@ -1,5 +1,5 @@
+mixins: "//content/browser/sms/COMMON_METADATA"
 monorail {
   component: "Blink>SMS"
 }
 
-team_email: "fugu-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/app_banner/DIR_METADATA b/third_party/blink/public/mojom/app_banner/DIR_METADATA
new file mode 100644
index 0000000..c32e345c
--- /dev/null
+++ b/third_party/blink/public/mojom/app_banner/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/app_banner/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/appcache/DIR_METADATA b/third_party/blink/public/mojom/appcache/DIR_METADATA
index df95601..2b930e5 100644
--- a/third_party/blink/public/mojom/appcache/DIR_METADATA
+++ b/third_party/blink/public/mojom/appcache/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>AppCache"
-}
+mixins: "//content/browser/appcache/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/badging/DIR_METADATA b/third_party/blink/public/mojom/badging/DIR_METADATA
index 3b6698c5..7ee5c266 100644
--- a/third_party/blink/public/mojom/badging/DIR_METADATA
+++ b/third_party/blink/public/mojom/badging/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls"
-}
+mixins: "//chrome/browser/badging/COMMON_METADATA"
 
-team_email: "pwa-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/blob/DIR_METADATA b/third_party/blink/public/mojom/blob/DIR_METADATA
index 955fe831..df68346 100644
--- a/third_party/blink/public/mojom/blob/DIR_METADATA
+++ b/third_party/blink/public/mojom/blob/DIR_METADATA
@@ -1,5 +1,3 @@
-monorail {
-  component: "Blink>Storage>FileAPI"
-}
+mixins: "//storage/browser/blob/COMMON_METADATA"
 
 team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/bluetooth/DIR_METADATA b/third_party/blink/public/mojom/bluetooth/DIR_METADATA
index 002457dc..c7987cd 100644
--- a/third_party/blink/public/mojom/bluetooth/DIR_METADATA
+++ b/third_party/blink/public/mojom/bluetooth/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Bluetooth"
-}
+mixins: "//content/browser/bluetooth/COMMON_METADATA"
 
-team_email: "web-bluetooth@chromium.org"
diff --git a/third_party/blink/public/mojom/buckets/DIR_METADATA b/third_party/blink/public/mojom/buckets/DIR_METADATA
new file mode 100644
index 0000000..e4ba8a5a
--- /dev/null
+++ b/third_party/blink/public/mojom/buckets/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/buckets/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/cache_storage/DIR_METADATA b/third_party/blink/public/mojom/cache_storage/DIR_METADATA
index 787f6c41..aa6e552 100644
--- a/third_party/blink/public/mojom/cache_storage/DIR_METADATA
+++ b/third_party/blink/public/mojom/cache_storage/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>CacheStorage"
-}
+mixins: "//content/browser/cache_storage/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/compute_pressure/DIR_METADATA b/third_party/blink/public/mojom/compute_pressure/DIR_METADATA
index 40a233c..dcc8a85 100644
--- a/third_party/blink/public/mojom/compute_pressure/DIR_METADATA
+++ b/third_party/blink/public/mojom/compute_pressure/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>PerformanceAPIs>ComputePressure"
-}
+mixins: "//content/browser/compute_pressure/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/cookie_store/DIR_METADATA b/third_party/blink/public/mojom/cookie_store/DIR_METADATA
index 5d203702..acd575c 100644
--- a/third_party/blink/public/mojom/cookie_store/DIR_METADATA
+++ b/third_party/blink/public/mojom/cookie_store/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>CookiesAPI"
-}
+mixins: "//content/browser/cookie_store/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/dom_storage/DIR_METADATA b/third_party/blink/public/mojom/dom_storage/DIR_METADATA
index f5d8083..9f9b3e4 100644
--- a/third_party/blink/public/mojom/dom_storage/DIR_METADATA
+++ b/third_party/blink/public/mojom/dom_storage/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>DOMStorage"
-}
+mixins: "//content/browser/dom_storage/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/fetch/DIR_METADATA b/third_party/blink/public/mojom/fetch/DIR_METADATA
index dbf3715..08e5ee1 100644
--- a/third_party/blink/public/mojom/fetch/DIR_METADATA
+++ b/third_party/blink/public/mojom/fetch/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Network>FetchAPI"
-}
+mixins: "//third_party/blink/renderer/core/fetch/COMMON_METADATA"
 
-team_email: "blink-network-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/file_system_access/DIR_METADATA b/third_party/blink/public/mojom/file_system_access/DIR_METADATA
index 7ed791f7..34dd65f 100644
--- a/third_party/blink/public/mojom/file_system_access/DIR_METADATA
+++ b/third_party/blink/public/mojom/file_system_access/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>FileSystem"
-}
+mixins: "//content/browser/file_system_access/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/filesystem/DIR_METADATA b/third_party/blink/public/mojom/filesystem/DIR_METADATA
index 7ed791f7..710bd02 100644
--- a/third_party/blink/public/mojom/filesystem/DIR_METADATA
+++ b/third_party/blink/public/mojom/filesystem/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>FileSystem"
-}
+mixins: "//third_party/blink/renderer/modules/filesystem/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/font_access/DIR_METADATA b/third_party/blink/public/mojom/font_access/DIR_METADATA
index a1f8c39..68d1f01 100644
--- a/third_party/blink/public/mojom/font_access/DIR_METADATA
+++ b/third_party/blink/public/mojom/font_access/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>FontAccess"
-}
+mixins: "//content/browser/font_access/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/hid/DIR_METADATA b/third_party/blink/public/mojom/hid/DIR_METADATA
index 8a71cf1..09b5667 100644
--- a/third_party/blink/public/mojom/hid/DIR_METADATA
+++ b/third_party/blink/public/mojom/hid/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>HID"
-}
+mixins: "//third_party/blink/renderer/modules/hid/COMMON_METADATA"
 
-team_email: "device-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/idle/DIR_METADATA b/third_party/blink/public/mojom/idle/DIR_METADATA
index 4245efd..7b9dd684 100644
--- a/third_party/blink/public/mojom/idle/DIR_METADATA
+++ b/third_party/blink/public/mojom/idle/DIR_METADATA
@@ -1 +1 @@
-team_email: "fugu-dev@chromium.org"
+mixins: "//content/browser/idle/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/locks/DIR_METADATA b/third_party/blink/public/mojom/locks/DIR_METADATA
index e7483ec7..b8a6675 100644
--- a/third_party/blink/public/mojom/locks/DIR_METADATA
+++ b/third_party/blink/public/mojom/locks/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage"
-}
+mixins: "//content/browser/locks/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/manifest/DIR_METADATA b/third_party/blink/public/mojom/manifest/DIR_METADATA
index 0ff3ed55..78b240e 100644
--- a/third_party/blink/public/mojom/manifest/DIR_METADATA
+++ b/third_party/blink/public/mojom/manifest/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>AppManifest"
-}
+mixins: "//third_party/blink/renderer/modules/manifest/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/media/DIR_METADATA b/third_party/blink/public/mojom/media/DIR_METADATA
new file mode 100644
index 0000000..41e8f64
--- /dev/null
+++ b/third_party/blink/public/mojom/media/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//media/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/mediasession/DIR_METADATA b/third_party/blink/public/mojom/mediasession/DIR_METADATA
new file mode 100644
index 0000000..6d22557
--- /dev/null
+++ b/third_party/blink/public/mojom/mediasession/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/mediasession/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/native_io/DIR_METADATA b/third_party/blink/public/mojom/native_io/DIR_METADATA
index a2e0dfd..c7f5262 100644
--- a/third_party/blink/public/mojom/native_io/DIR_METADATA
+++ b/third_party/blink/public/mojom/native_io/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>NativeIO"
-}
+mixins: "//content/browser/native_io/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/payments/DIR_METADATA b/third_party/blink/public/mojom/payments/DIR_METADATA
index cd26685..269283c4 100644
--- a/third_party/blink/public/mojom/payments/DIR_METADATA
+++ b/third_party/blink/public/mojom/payments/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Payments"
-}
+mixins: "//components/payments/COMMON_METADATA"
 
-team_email: "payments-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/peerconnection/DIR_METADATA b/third_party/blink/public/mojom/peerconnection/DIR_METADATA
new file mode 100644
index 0000000..7c8a8e8
--- /dev/null
+++ b/third_party/blink/public/mojom/peerconnection/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/peerconnection/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/performance_manager/DIR_METADATA b/third_party/blink/public/mojom/performance_manager/DIR_METADATA
new file mode 100644
index 0000000..e9e0173
--- /dev/null
+++ b/third_party/blink/public/mojom/performance_manager/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/performance_manager/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/permissions/DIR_METADATA b/third_party/blink/public/mojom/permissions/DIR_METADATA
index e558745..961484f 100644
--- a/third_party/blink/public/mojom/permissions/DIR_METADATA
+++ b/third_party/blink/public/mojom/permissions/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>PermissionsAPI"
-}
+mixins: "//third_party/blink/renderer/modules/permissions/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/prerender/DIR_METADATA b/third_party/blink/public/mojom/prerender/DIR_METADATA
index 64dbad5..1881f70 100644
--- a/third_party/blink/public/mojom/prerender/DIR_METADATA
+++ b/third_party/blink/public/mojom/prerender/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Preload>Prerender"
-}
+mixins: "//content/browser/prerender/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/presentation/DIR_METADATA b/third_party/blink/public/mojom/presentation/DIR_METADATA
new file mode 100644
index 0000000..6e954ec
--- /dev/null
+++ b/third_party/blink/public/mojom/presentation/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/presentation/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/push_messaging/DIR_METADATA b/third_party/blink/public/mojom/push_messaging/DIR_METADATA
index 2fcdc00d..fe8460b 100644
--- a/third_party/blink/public/mojom/push_messaging/DIR_METADATA
+++ b/third_party/blink/public/mojom/push_messaging/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>PushAPI"
-}
+mixins: "//content/browser/push_messaging/COMMON_METADATA"
 
-team_email: "platform-capabilities@chromium.org"
diff --git a/third_party/blink/public/mojom/quota/DIR_METADATA b/third_party/blink/public/mojom/quota/DIR_METADATA
index da39edd..e881dfb 100644
--- a/third_party/blink/public/mojom/quota/DIR_METADATA
+++ b/third_party/blink/public/mojom/quota/DIR_METADATA
@@ -1,5 +1,3 @@
-monorail {
-  component: "Blink>Storage>Quota"
-}
+mixins: "//storage/browser/quota/COMMON_METADATA"
 
 team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/script/DIR_METADATA b/third_party/blink/public/mojom/script/DIR_METADATA
index b7353a1..80b42c85 100644
--- a/third_party/blink/public/mojom/script/DIR_METADATA
+++ b/third_party/blink/public/mojom/script/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>HTML>Script"
-}
+mixins: "//third_party/blink/renderer/core/script/COMMON_METADATA"
 
-team_email: "module-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/serial/DIR_METADATA b/third_party/blink/public/mojom/serial/DIR_METADATA
index 9d970329..423968b 100644
--- a/third_party/blink/public/mojom/serial/DIR_METADATA
+++ b/third_party/blink/public/mojom/serial/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Serial"
-}
+mixins: "//content/browser/serial/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/service_worker/DIR_METADATA b/third_party/blink/public/mojom/service_worker/DIR_METADATA
index 2a951d09..72616d6 100644
--- a/third_party/blink/public/mojom/service_worker/DIR_METADATA
+++ b/third_party/blink/public/mojom/service_worker/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
+mixins: "//content/browser/service_worker/COMMON_METADATA"
 
-team_email: "worker-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/sms/DIR_METADATA b/third_party/blink/public/mojom/sms/DIR_METADATA
new file mode 100644
index 0000000..52a7d1c8
--- /dev/null
+++ b/third_party/blink/public/mojom/sms/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/sms/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/speculation_rules/DIR_METADATA b/third_party/blink/public/mojom/speculation_rules/DIR_METADATA
new file mode 100644
index 0000000..202bb5c
--- /dev/null
+++ b/third_party/blink/public/mojom/speculation_rules/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/core/speculation_rules/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/speech/DIR_METADATA b/third_party/blink/public/mojom/speech/DIR_METADATA
index 49120a8..4b16894 100644
--- a/third_party/blink/public/mojom/speech/DIR_METADATA
+++ b/third_party/blink/public/mojom/speech/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Speech"
-}
+mixins: "//third_party/blink/renderer/modules/speech/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/subapps/DIR_METADATA b/third_party/blink/public/mojom/subapps/DIR_METADATA
index 7f1ffb86..0b17525fb 100644
--- a/third_party/blink/public/mojom/subapps/DIR_METADATA
+++ b/third_party/blink/public/mojom/subapps/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls>Desktop"
-}
+mixins: "//third_party/blink/renderer/modules/subapps/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/webaudio/DIR_METADATA b/third_party/blink/public/mojom/webaudio/DIR_METADATA
index 1ee4b38..a1448a1d 100644
--- a/third_party/blink/public/mojom/webaudio/DIR_METADATA
+++ b/third_party/blink/public/mojom/webaudio/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebAudio"
-}
+mixins: "//third_party/blink/renderer/modules/webaudio/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/webid/DIR_METADATA b/third_party/blink/public/mojom/webid/DIR_METADATA
index b36c62f..136e07617 100644
--- a/third_party/blink/public/mojom/webid/DIR_METADATA
+++ b/third_party/blink/public/mojom/webid/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Identity>WebID"
-}
+mixins: "//content/browser/webid/COMMON_METADATA"
diff --git a/third_party/blink/public/mojom/webtransport/DIR_METADATA b/third_party/blink/public/mojom/webtransport/DIR_METADATA
index 6957d2b..716d102 100644
--- a/third_party/blink/public/mojom/webtransport/DIR_METADATA
+++ b/third_party/blink/public/mojom/webtransport/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Network>WebTransport"
-}
+mixins: "//third_party/blink/renderer/modules/webtransport/COMMON_METADATA"
 
-team_email: "blink-network-dev@chromium.org"
diff --git a/third_party/blink/public/platform/media/DIR_METADATA b/third_party/blink/public/platform/media/DIR_METADATA
new file mode 100644
index 0000000..41e8f64
--- /dev/null
+++ b/third_party/blink/public/platform/media/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//media/COMMON_METADATA"
diff --git a/third_party/blink/public/platform/modules/mediastream/DIR_METADATA b/third_party/blink/public/platform/modules/mediastream/DIR_METADATA
index 066f18a..50babda 100644
--- a/third_party/blink/public/platform/modules/mediastream/DIR_METADATA
+++ b/third_party/blink/public/platform/modules/mediastream/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>GetUserMedia"
-}
+mixins: "//third_party/blink/common/mediastream/COMMON_METADATA"
 
-team_email: "webrtc-dev@chromium.org"
diff --git a/third_party/blink/public/platform/modules/remoteplayback/DIR_METADATA b/third_party/blink/public/platform/modules/remoteplayback/DIR_METADATA
new file mode 100644
index 0000000..92a791a6
--- /dev/null
+++ b/third_party/blink/public/platform/modules/remoteplayback/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/remoteplayback/COMMON_METADATA"
diff --git a/third_party/blink/public/platform/modules/service_worker/DIR_METADATA b/third_party/blink/public/platform/modules/service_worker/DIR_METADATA
index 2a951d09..72616d6 100644
--- a/third_party/blink/public/platform/modules/service_worker/DIR_METADATA
+++ b/third_party/blink/public/platform/modules/service_worker/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
+mixins: "//content/browser/service_worker/COMMON_METADATA"
 
-team_email: "worker-dev@chromium.org"
diff --git a/third_party/blink/public/platform/modules/video_capture/DIR_METADATA b/third_party/blink/public/platform/modules/video_capture/DIR_METADATA
new file mode 100644
index 0000000..4bc84a2
--- /dev/null
+++ b/third_party/blink/public/platform/modules/video_capture/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/platform/video_capture/COMMON_METADATA"
diff --git a/third_party/blink/public/platform/modules/webrtc/COMMON_METADATA b/third_party/blink/public/platform/modules/webrtc/COMMON_METADATA
new file mode 100644
index 0000000..66cc019
--- /dev/null
+++ b/third_party/blink/public/platform/modules/webrtc/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebRTC"
+}
diff --git a/third_party/blink/public/platform/modules/webrtc/DIR_METADATA b/third_party/blink/public/platform/modules/webrtc/DIR_METADATA
index 66cc019..58da5fd 100644
--- a/third_party/blink/public/platform/modules/webrtc/DIR_METADATA
+++ b/third_party/blink/public/platform/modules/webrtc/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebRTC"
-}
+mixins: "//third_party/blink/public/platform/modules/webrtc/COMMON_METADATA"
diff --git a/third_party/blink/public/platform/scheduler/DIR_METADATA b/third_party/blink/public/platform/scheduler/DIR_METADATA
index 66a9685..ba981d6 100644
--- a/third_party/blink/public/platform/scheduler/DIR_METADATA
+++ b/third_party/blink/public/platform/scheduler/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Scheduling"
-}
+mixins: "//third_party/blink/renderer/platform/scheduler/COMMON_METADATA"
 
-team_email: "scheduler-dev@chromium.org"
diff --git a/third_party/blink/public/web/modules/media/DIR_METADATA b/third_party/blink/public/web/modules/media/DIR_METADATA
index 6667e7f..41e8f64 100644
--- a/third_party/blink/public/web/modules/media/DIR_METADATA
+++ b/third_party/blink/public/web/modules/media/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Media"
-}
+mixins: "//media/COMMON_METADATA"
diff --git a/third_party/blink/public/web/modules/mediastream/DIR_METADATA b/third_party/blink/public/web/modules/mediastream/DIR_METADATA
index 066f18a..50babda 100644
--- a/third_party/blink/public/web/modules/mediastream/DIR_METADATA
+++ b/third_party/blink/public/web/modules/mediastream/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>GetUserMedia"
-}
+mixins: "//third_party/blink/common/mediastream/COMMON_METADATA"
 
-team_email: "webrtc-dev@chromium.org"
diff --git a/third_party/blink/public/web/modules/service_worker/DIR_METADATA b/third_party/blink/public/web/modules/service_worker/DIR_METADATA
index 2a951d09..72616d6 100644
--- a/third_party/blink/public/web/modules/service_worker/DIR_METADATA
+++ b/third_party/blink/public/web/modules/service_worker/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
+mixins: "//content/browser/service_worker/COMMON_METADATA"
 
-team_email: "worker-dev@chromium.org"
diff --git a/third_party/blink/renderer/bindings/COMMON_METADATA b/third_party/blink/renderer/bindings/COMMON_METADATA
new file mode 100644
index 0000000..9eb47abd
--- /dev/null
+++ b/third_party/blink/renderer/bindings/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>Bindings"
+}
+
+team_email: "blink-reviews-bindings@chromium.org"
diff --git a/third_party/blink/renderer/bindings/DIR_METADATA b/third_party/blink/renderer/bindings/DIR_METADATA
index 9eb47abd..177ac487 100644
--- a/third_party/blink/renderer/bindings/DIR_METADATA
+++ b/third_party/blink/renderer/bindings/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Bindings"
-}
+mixins: "//third_party/blink/renderer/bindings/COMMON_METADATA"
 
-team_email: "blink-reviews-bindings@chromium.org"
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index f09a413..1b4b165 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -62,6 +62,8 @@
                     "core/v8/native_value_traits_buffer_sources.cc",
                     "core/v8/native_value_traits_impl.cc",
                     "core/v8/native_value_traits_impl.h",
+                    "core/v8/observable_array.cc",
+                    "core/v8/observable_array.h",
                     "core/v8/profiler_trace_builder.cc",
                     "core/v8/profiler_trace_builder.h",
                     "core/v8/referrer_script_info.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
index b899507..90ed890 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
@@ -66,20 +66,6 @@
     const ScriptState* callback_relevant_script_state,
     const ScriptState* incumbent_script_state);
 
-using InstallTemplateFunction =
-    void (*)(v8::Isolate* isolate,
-             const DOMWrapperWorld& world,
-             v8::Local<v8::FunctionTemplate> interface_template);
-
-using InstallRuntimeEnabledFeaturesFunction =
-    void (*)(v8::Isolate*,
-             const DOMWrapperWorld&,
-             v8::Local<v8::Object> instance_object,
-             v8::Local<v8::Object> prototype_object,
-             v8::Local<v8::Function> interface_object);
-
-using InstallRuntimeEnabledFeaturesOnTemplateFunction = InstallTemplateFunction;
-
 namespace bindings {
 
 CORE_EXPORT void SetupIDLInterfaceTemplate(
diff --git a/third_party/blink/renderer/bindings/core/v8/observable_array.cc b/third_party/blink/renderer/bindings/core/v8/observable_array.cc
new file mode 100644
index 0000000..82c8891
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/observable_array.cc
@@ -0,0 +1,82 @@
+// 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 "third_party/blink/renderer/bindings/core/v8/observable_array.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
+#include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
+#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "v8/include/v8-object.h"
+#include "v8/include/v8-proxy.h"
+
+namespace blink {
+
+namespace bindings {
+
+// static
+const WrapperTypeInfo ObservableArrayExoticObjectImpl::wrapper_type_info_body_{
+    gin::kEmbedderBlink,
+    /*install_interface_template_func=*/nullptr,
+    /*install_context_dependent_props_func=*/nullptr,
+    "ObservableArrayExoticObject",
+    /*parent_class=*/nullptr,
+    WrapperTypeInfo::kWrapperTypeNoPrototype,
+    // v8::Proxy (without an internal field) is used as a (pseudo) wrapper.
+    WrapperTypeInfo::kNoInternalFieldClassId,
+    WrapperTypeInfo::kNotInheritFromActiveScriptWrappable,
+    WrapperTypeInfo::kIdlObservableArray,
+};
+
+// static
+const WrapperTypeInfo& ObservableArrayExoticObjectImpl::wrapper_type_info_ =
+    ObservableArrayExoticObjectImpl::wrapper_type_info_body_;
+
+ObservableArrayExoticObjectImpl::ObservableArrayExoticObjectImpl(
+    bindings::ObservableArrayBase* observable_array_backing_list_object)
+    : ObservableArrayExoticObject(observable_array_backing_list_object) {}
+
+v8::MaybeLocal<v8::Value> ObservableArrayExoticObjectImpl::Wrap(
+    ScriptState* script_state) {
+  DCHECK(!DOMDataStore::ContainsWrapper(this, script_state->GetIsolate()));
+
+  v8::Local<v8::Value> target;
+  if (!ToV8Traits<bindings::ObservableArrayBase>::ToV8(script_state,
+                                                       GetBackingListObject())
+           .ToLocal(&target)) {
+    return {};
+  }
+  CHECK(target->IsObject());
+  v8::Local<v8::Object> handler;
+  // TODO(yukishiino): Set `handler` to an appropriate object.
+  v8::Local<v8::Proxy> proxy;
+  if (!v8::Proxy::New(script_state->GetContext(), target.As<v8::Object>(),
+                      handler)
+           .ToLocal(&proxy)) {
+    return {};
+  }
+  v8::Local<v8::Object> wrapper = proxy.As<v8::Object>();
+
+  // Register the proxy object as a (pseudo) wrapper object although the proxy
+  // object does not have an internal field pointing to a Blink object.
+  const bool is_new_entry = script_state->World().DomDataStore().Set(
+      script_state->GetIsolate(), this, GetWrapperTypeInfo(), wrapper);
+  CHECK(is_new_entry);
+
+  return wrapper;
+}
+
+v8::Local<v8::Object> ObservableArrayExoticObjectImpl::AssociateWithWrapper(
+    v8::Isolate* isolate,
+    const WrapperTypeInfo* wrapper_type_info,
+    v8::Local<v8::Object> wrapper) {
+  // The proxy object does not have an internal field and cannot be associated
+  // with a Blink object directly.
+  NOTREACHED();
+  return {};
+}
+
+}  // namespace bindings
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/observable_array.h b/third_party/blink/renderer/bindings/core/v8/observable_array.h
new file mode 100644
index 0000000..4ad263f
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/observable_array.h
@@ -0,0 +1,128 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_OBSERVABLE_ARRAY_H_
+#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_OBSERVABLE_ARRAY_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/bindings/observable_array_base.h"
+#include "third_party/blink/renderer/platform/heap/heap_traits.h"
+
+namespace blink {
+
+class ExceptionState;
+class ScriptState;
+
+namespace bindings {
+
+// The implementation class of ObservableArrayExoticObject.
+class CORE_EXPORT ObservableArrayExoticObjectImpl final
+    : public ObservableArrayExoticObject {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  explicit ObservableArrayExoticObjectImpl(
+      bindings::ObservableArrayBase* observable_array_backing_list_object);
+  ~ObservableArrayExoticObjectImpl() override = default;
+
+  // ScriptWrappable overrides
+  v8::MaybeLocal<v8::Value> Wrap(ScriptState* script_state) override;
+  WARN_UNUSED_RESULT v8::Local<v8::Object> AssociateWithWrapper(
+      v8::Isolate* isolate,
+      const WrapperTypeInfo* wrapper_type_info,
+      v8::Local<v8::Object> wrapper) override;
+
+ private:
+  static const WrapperTypeInfo wrapper_type_info_body_;
+};
+
+template <typename ElementType>
+class ObservableArrayImplHelper : public bindings::ObservableArrayBase {
+ public:
+  using BackingListType = VectorOf<ElementType>;
+  using size_type = uint32_t;
+  using value_type = ElementType;
+  using iterator = typename BackingListType::iterator;
+  using const_iterator = typename BackingListType::const_iterator;
+  using reverse_iterator = typename BackingListType::reverse_iterator;
+  using const_reverse_iterator =
+      typename BackingListType::const_reverse_iterator;
+  using SetAlgorithmCallback =
+      void (ScriptWrappable::*)(ScriptState* script_state,
+                                size_type index,
+                                value_type& value,
+                                ExceptionState& exception_state);
+  using DeleteAlgorithmCallback =
+      void (ScriptWrappable::*)(ScriptState* script_state,
+                                size_type index,
+                                ExceptionState& exception_state);
+
+  explicit ObservableArrayImplHelper(
+      ScriptWrappable* platform_object,
+      SetAlgorithmCallback set_algorithm_callback,
+      DeleteAlgorithmCallback delete_algorithm_callback)
+      : bindings::ObservableArrayBase(
+            platform_object,
+            MakeGarbageCollected<bindings::ObservableArrayExoticObjectImpl>(
+                this)),
+        set_algorithm_callback_(set_algorithm_callback),
+        delete_algorithm_callback_(delete_algorithm_callback) {}
+  ~ObservableArrayImplHelper() override = default;
+
+  // Returns the observable array exotic object, which is the value to be
+  // returned as the IDL attribute value.  Do not use `this` object (= the
+  // observable array backing list object) as the IDL attribute value.
+  using bindings::ObservableArrayBase::GetExoticObject;
+
+  // Vector-compatible APIs
+  wtf_size_t size() const { return backing_list_.size(); }
+  wtf_size_t capacity() const { return backing_list_.capacity(); }
+  bool IsEmpty() const { return backing_list_.IsEmpty(); }
+  void ReserveCapacity(size_type new_capacity) {
+    backing_list_.ReserveCapacity(new_capacity);
+  }
+  void ReserveInitialCapacity(size_type initial_capacity) {
+    backing_list_.ReserveInitialCapacity(initial_capacity);
+  }
+  value_type& at(size_type index) { return backing_list_.at(index); }
+  const value_type& at(size_type index) const {
+    return backing_list_.at(index);
+  }
+  value_type& operator[](size_type index) { return backing_list_[index]; }
+  const value_type& operator[](size_type index) const {
+    return backing_list_[index];
+  }
+  value_type* data() { return backing_list_.data(); }
+  const value_type* data() const { return backing_list_.data(); }
+  iterator begin() { return backing_list_.begin(); }
+  iterator end() { return backing_list_.end(); }
+  const_iterator begin() const { return backing_list_.begin(); }
+  const_iterator end() const { return backing_list_.end(); }
+  reverse_iterator rbegin() { return backing_list_.rbegin(); }
+  reverse_iterator rend() { return backing_list_.rend(); }
+  const_reverse_iterator rbegin() const { return backing_list_.rbegin(); }
+  const_reverse_iterator rend() const { return backing_list_.rend(); }
+  value_type& front() { return backing_list_.front(); }
+  value_type& back() { return backing_list_.back(); }
+  const value_type& front() const { return backing_list_.front(); }
+  const value_type& back() const { return backing_list_.back(); }
+
+  void Trace(Visitor* visitor) const override {
+    ObservableArrayBase::Trace(visitor);
+    TraceIfNeeded<BackingListType>::Trace(visitor, backing_list_);
+  }
+
+ private:
+  BackingListType backing_list_;
+  // [[SetAlgorithm]]
+  SetAlgorithmCallback set_algorithm_callback_ = nullptr;
+  // [[DeleteAlgorithm]]
+  DeleteAlgorithmCallback delete_algorithm_callback_ = nullptr;
+};
+
+}  // namespace bindings
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_OBSERVABLE_ARRAY_H_
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
index 087d0e4..1b86dcc 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -806,6 +806,8 @@
   isolate->SetPromiseRejectCallback(PromiseRejectHandlerInWorker);
   isolate->SetModifyCodeGenerationFromStringsCallback(
       CodeGenerationCheckCallbackInMainThread);
+  isolate->SetAllowWasmCodeGenerationCallback(
+      WasmCodeGenerationCheckCallbackInMainThread);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/build/scripts/core/css/DIR_METADATA b/third_party/blink/renderer/build/scripts/core/css/DIR_METADATA
new file mode 100644
index 0000000..2c25ef65
--- /dev/null
+++ b/third_party/blink/renderer/build/scripts/core/css/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/core/css/COMMON_METADATA"
diff --git a/third_party/blink/renderer/build/scripts/core/style/DIR_METADATA b/third_party/blink/renderer/build/scripts/core/style/DIR_METADATA
new file mode 100644
index 0000000..9575425
--- /dev/null
+++ b/third_party/blink/renderer/build/scripts/core/style/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/core/style/COMMON_METADATA"
diff --git a/third_party/blink/renderer/controller/performance_manager/DIR_METADATA b/third_party/blink/renderer/controller/performance_manager/DIR_METADATA
new file mode 100644
index 0000000..e9e0173
--- /dev/null
+++ b/third_party/blink/renderer/controller/performance_manager/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/performance_manager/COMMON_METADATA"
diff --git a/third_party/blink/renderer/core/accessibility/DIR_METADATA b/third_party/blink/renderer/core/accessibility/DIR_METADATA
index 7a89266..e2f7b33 100644
--- a/third_party/blink/renderer/core/accessibility/DIR_METADATA
+++ b/third_party/blink/renderer/core/accessibility/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Accessibility"
-}
+mixins: "//third_party/blink/renderer/modules/accessibility/COMMON_METADATA"
 
-team_email: "chromium-accessibility@chromium.org"
diff --git a/third_party/blink/renderer/core/animation/COMMON_METADATA b/third_party/blink/renderer/core/animation/COMMON_METADATA
new file mode 100644
index 0000000..072e8c9
--- /dev/null
+++ b/third_party/blink/renderer/core/animation/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>Animation"
+}
+
+team_email: "animations-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/animation/DIR_METADATA b/third_party/blink/renderer/core/animation/DIR_METADATA
index 072e8c9..53a71f7 100644
--- a/third_party/blink/renderer/core/animation/DIR_METADATA
+++ b/third_party/blink/renderer/core/animation/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Animation"
-}
+mixins: "//third_party/blink/renderer/core/animation/COMMON_METADATA"
 
-team_email: "animations-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/css/COMMON_METADATA b/third_party/blink/renderer/core/css/COMMON_METADATA
new file mode 100644
index 0000000..1876fb3
--- /dev/null
+++ b/third_party/blink/renderer/core/css/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>CSS"
+}
+
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/css/DIR_METADATA b/third_party/blink/renderer/core/css/DIR_METADATA
index 1876fb3..e19b821b 100644
--- a/third_party/blink/renderer/core/css/DIR_METADATA
+++ b/third_party/blink/renderer/core/css/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>CSS"
-}
+mixins: "//third_party/blink/renderer/core/css/COMMON_METADATA"
 
-team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/css/css_segmented_font_face.cc b/third_party/blink/renderer/core/css/css_segmented_font_face.cc
index 4f5d9a64..78d2c84 100644
--- a/third_party/blink/renderer/core/css/css_segmented_font_face.cc
+++ b/third_party/blink/renderer/core/css/css_segmented_font_face.cc
@@ -246,8 +246,15 @@
 bool CascadePriorityHigherThan(const FontFace& new_font_face,
                                const FontFace& existing_font_face) {
   // We should reach here only for CSS-connected font faces, which must have an
-  // owner document.
-  DCHECK(new_font_face.GetDocument());
+  // owner document. However, there are cases where we don't have a document
+  // here, possibly caused by ExecutionContext or Document lifecycle issues.
+  // TODO(crbug.com/1250831): Find out the root cause and fix it.
+  if (!new_font_face.GetDocument() || !existing_font_face.GetDocument()) {
+    NOTREACHED();
+    // In the buggy case, to ensure a stable ordering, font faces without a
+    // document are considered higher priority.
+    return !new_font_face.GetDocument();
+  }
   DCHECK_EQ(new_font_face.GetDocument(), existing_font_face.GetDocument());
   DCHECK(new_font_face.GetStyleRule());
   DCHECK(existing_font_face.GetStyleRule());
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
index a2e7a1f8..45ffaa2d 100644
--- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -801,7 +801,7 @@
   if (StopPropagateTextDecorations(style, element))
     style.ClearAppliedTextDecorations();
   else
-    style.RestoreParentTextDecorations(parent_style);
+    style.RestoreParentTextDecorations(layout_parent_style);
   if (svg_element) {
     style.ApplySvgTextDecorations();
   } else {
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index 29242c4..8f7ad6fe 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -1770,7 +1770,18 @@
     const ComputedStyle& layout_parent_style) {
   if (parent_style.InheritedEqual(layout_parent_style))
     return nullptr;
-  return CreateAnonymousStyleWithDisplay(parent_style, EDisplay::kInline);
+  scoped_refptr<ComputedStyle> text_style =
+      CreateAnonymousStyleWithDisplay(parent_style, EDisplay::kInline);
+  // If the parent with display:contents has its own text-decoration,
+  // remove it from AppliedTextDecorations.
+  wtf_size_t parent_decorations = parent_style.AppliedTextDecorations().size();
+  if (parent_decorations >
+      layout_parent_style.AppliedTextDecorations().size()) {
+    text_style->ClearAppliedTextDecorations();
+    if (parent_decorations > 1u)
+      text_style->RestoreParentTextDecorations(layout_parent_style);
+  }
+  return text_style;
 }
 
 #define PROPAGATE_FROM(source, getter, setter, initial) \
diff --git a/third_party/blink/renderer/core/dom/COMMON_METADATA b/third_party/blink/renderer/core/dom/COMMON_METADATA
new file mode 100644
index 0000000..347a1b0
--- /dev/null
+++ b/third_party/blink/renderer/core/dom/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>DOM"
+}
+
+team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/dom/DIR_METADATA b/third_party/blink/renderer/core/dom/DIR_METADATA
index 347a1b0..7a3c8d6 100644
--- a/third_party/blink/renderer/core/dom/DIR_METADATA
+++ b/third_party/blink/renderer/core/dom/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>DOM"
-}
+mixins: "//third_party/blink/renderer/core/dom/COMMON_METADATA"
 
-team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder.cc b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
index 1c79343..9603813 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder.cc
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder.cc
@@ -140,20 +140,21 @@
 }
 
 void LayoutTreeBuilderForText::CreateLayoutObject() {
-  const ComputedStyle& style = *style_;
+  const ComputedStyle* style = style_.get();
   LayoutObject* layout_object_parent = context_.parent;
   LayoutObject* next_layout_object = NextLayoutObject();
   if (LayoutObject* wrapper = CreateInlineWrapperForDisplayContentsIfNeeded()) {
     layout_object_parent = wrapper;
     next_layout_object = nullptr;
+    style = wrapper->Style();
   }
 
   LegacyLayout legacy_layout = layout_object_parent->ForceLegacyLayout()
                                    ? LegacyLayout::kForce
                                    : LegacyLayout::kAuto;
   LayoutText* new_layout_object =
-      node_->CreateTextLayoutObject(style, legacy_layout);
-  if (!layout_object_parent->IsChildAllowed(new_layout_object, style)) {
+      node_->CreateTextLayoutObject(*style, legacy_layout);
+  if (!layout_object_parent->IsChildAllowed(new_layout_object, *style)) {
     new_layout_object->Destroy();
     return;
   }
@@ -167,7 +168,7 @@
 
   node_->SetLayoutObject(new_layout_object);
   DCHECK(!new_layout_object->Style());
-  new_layout_object->SetStyle(&style);
+  new_layout_object->SetStyle(style);
 
   layout_object_parent->AddChild(new_layout_object, next_layout_object);
 }
diff --git a/third_party/blink/renderer/core/fetch/COMMON_METADATA b/third_party/blink/renderer/core/fetch/COMMON_METADATA
new file mode 100644
index 0000000..dbf3715
--- /dev/null
+++ b/third_party/blink/renderer/core/fetch/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>Network>FetchAPI"
+}
+
+team_email: "blink-network-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/fetch/DIR_METADATA b/third_party/blink/renderer/core/fetch/DIR_METADATA
index dbf3715..08e5ee1 100644
--- a/third_party/blink/renderer/core/fetch/DIR_METADATA
+++ b/third_party/blink/renderer/core/fetch/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Network>FetchAPI"
-}
+mixins: "//third_party/blink/renderer/core/fetch/COMMON_METADATA"
 
-team_email: "blink-network-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/html/parser/COMMON_METADATA b/third_party/blink/renderer/core/html/parser/COMMON_METADATA
new file mode 100644
index 0000000..18fa0a6
--- /dev/null
+++ b/third_party/blink/renderer/core/html/parser/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>HTML>Parser"
+}
+
+team_email: "loading-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/html/parser/DIR_METADATA b/third_party/blink/renderer/core/html/parser/DIR_METADATA
index 18fa0a6..11bcfde 100644
--- a/third_party/blink/renderer/core/html/parser/DIR_METADATA
+++ b/third_party/blink/renderer/core/html/parser/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>HTML>Parser"
-}
+mixins: "//third_party/blink/renderer/core/html/parser/COMMON_METADATA"
 
-team_email: "loading-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/html/portal/COMMON_METADATA b/third_party/blink/renderer/core/html/portal/COMMON_METADATA
new file mode 100644
index 0000000..1e4fe50
--- /dev/null
+++ b/third_party/blink/renderer/core/html/portal/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Portals"
+}
diff --git a/third_party/blink/renderer/core/html/portal/DIR_METADATA b/third_party/blink/renderer/core/html/portal/DIR_METADATA
index 1e4fe50..842d7f2 100644
--- a/third_party/blink/renderer/core/html/portal/DIR_METADATA
+++ b/third_party/blink/renderer/core/html/portal/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Portals"
-}
+mixins: "//third_party/blink/renderer/core/html/portal/COMMON_METADATA"
diff --git a/third_party/blink/renderer/core/layout/geometry/physical_rect.cc b/third_party/blink/renderer/core/layout/geometry/physical_rect.cc
index 00a6001..27daca4 100644
--- a/third_party/blink/renderer/core/layout/geometry/physical_rect.cc
+++ b/third_party/blink/renderer/core/layout/geometry/physical_rect.cc
@@ -28,9 +28,14 @@
 }
 
 LayoutUnit PhysicalRect::SquaredDistanceTo(const PhysicalOffset& point) const {
-  LayoutUnit diff_x =
-      point.left - clampTo<LayoutUnit>(point.left, X(), Right());
-  LayoutUnit diff_y = point.top - clampTo<LayoutUnit>(point.top, Y(), Bottom());
+  LayoutUnit x1 = X(), x2 = Right();
+  if (x1 > x2)
+    std::swap(x1, x2);
+  LayoutUnit diff_x = point.left - clampTo<LayoutUnit>(point.left, x1, x2);
+  LayoutUnit y1 = Y(), y2 = Bottom();
+  if (y1 > y2)
+    std::swap(y1, y2);
+  LayoutUnit diff_y = point.top - clampTo<LayoutUnit>(point.top, y1, y2);
   return diff_x * diff_x + diff_y * diff_y;
 }
 
diff --git a/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc b/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc
index b9bd748..8cd817c 100644
--- a/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc
+++ b/third_party/blink/renderer/core/layout/geometry/physical_rect_test.cc
@@ -102,6 +102,16 @@
       << "on the left edge";
 
   EXPECT_EQ(0, rect.SquaredDistanceTo(PhysicalOffset(10, 190))) << "contained";
+
+  // Huge size
+  rect = PhysicalRect(LayoutUnit(500), LayoutUnit(), LayoutUnit::Max(),
+                      LayoutUnit());
+  EXPECT_GT(rect.SquaredDistanceTo(PhysicalOffset(10, 0)), 0);
+
+  // Negative size
+  rect = PhysicalRect(LayoutUnit(500), LayoutUnit(), LayoutUnit(-100),
+                      LayoutUnit());
+  EXPECT_EQ(1, rect.SquaredDistanceTo(PhysicalOffset(501, 0)));
 }
 
 TEST(PhysicalRectTest, InclusiveIntersect) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
index dff9101..bd8f9a1 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
@@ -313,8 +313,13 @@
   DCHECK(*this);
   const LayoutObject* const layout_object = GetLayoutObject();
   // We use |IsInline()| to exclude floating and out-of-flow objects.
-  if (!layout_object || !layout_object->IsInline() ||
-      layout_object->IsAtomicInlineLevel())
+  if (!layout_object || layout_object->IsAtomicInlineLevel())
+    return false;
+  // When |Current()| is block-in-inline, e.g. <span><div>foo</div></span>, it
+  // should be part of culled inline box[1].
+  // [1]
+  // external/wpt/shadow-dom/DocumentOrShadowRoot-prototype-elementFromPoint.html
+  if (!layout_object->IsInline() && !layout_object->IsBlockInInline())
     return false;
   DCHECK(!layout_object->IsFloatingOrOutOfFlowPositioned());
   DCHECK(!BoxFragment() || !BoxFragment()->IsFormattingContextRoot());
diff --git a/third_party/blink/renderer/core/loader/appcache/DIR_METADATA b/third_party/blink/renderer/core/loader/appcache/DIR_METADATA
index df95601..2b930e5 100644
--- a/third_party/blink/renderer/core/loader/appcache/DIR_METADATA
+++ b/third_party/blink/renderer/core/loader/appcache/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Storage>AppCache"
-}
+mixins: "//content/browser/appcache/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/origin_trials/DIR_METADATA b/third_party/blink/renderer/core/origin_trials/DIR_METADATA
new file mode 100644
index 0000000..14641a38
--- /dev/null
+++ b/third_party/blink/renderer/core/origin_trials/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/common/origin_trials/COMMON_METADATA"
diff --git a/third_party/blink/renderer/core/permissions_policy/DIR_METADATA b/third_party/blink/renderer/core/permissions_policy/DIR_METADATA
new file mode 100644
index 0000000..fbe9b746
--- /dev/null
+++ b/third_party/blink/renderer/core/permissions_policy/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/common/permissions_policy/COMMON_METADATA"
diff --git a/third_party/blink/renderer/core/script/COMMON_METADATA b/third_party/blink/renderer/core/script/COMMON_METADATA
new file mode 100644
index 0000000..b7353a1
--- /dev/null
+++ b/third_party/blink/renderer/core/script/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>HTML>Script"
+}
+
+team_email: "module-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/script/DIR_METADATA b/third_party/blink/renderer/core/script/DIR_METADATA
index b7353a1..80b42c85 100644
--- a/third_party/blink/renderer/core/script/DIR_METADATA
+++ b/third_party/blink/renderer/core/script/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>HTML>Script"
-}
+mixins: "//third_party/blink/renderer/core/script/COMMON_METADATA"
 
-team_email: "module-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/speculation_rules/COMMON_METADATA b/third_party/blink/renderer/core/speculation_rules/COMMON_METADATA
new file mode 100644
index 0000000..9300d9c
--- /dev/null
+++ b/third_party/blink/renderer/core/speculation_rules/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Preload"
+}
diff --git a/third_party/blink/renderer/core/speculation_rules/DIR_METADATA b/third_party/blink/renderer/core/speculation_rules/DIR_METADATA
index 9300d9c..202bb5c 100644
--- a/third_party/blink/renderer/core/speculation_rules/DIR_METADATA
+++ b/third_party/blink/renderer/core/speculation_rules/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Preload"
-}
+mixins: "//third_party/blink/renderer/core/speculation_rules/COMMON_METADATA"
diff --git a/third_party/blink/renderer/core/style/COMMON_METADATA b/third_party/blink/renderer/core/style/COMMON_METADATA
new file mode 100644
index 0000000..1876fb3
--- /dev/null
+++ b/third_party/blink/renderer/core/style/COMMON_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Blink>CSS"
+}
+
+team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/style/DIR_METADATA b/third_party/blink/renderer/core/style/DIR_METADATA
index 1876fb3..e37ff0b 100644
--- a/third_party/blink/renderer/core/style/DIR_METADATA
+++ b/third_party/blink/renderer/core/style/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>CSS"
-}
+mixins: "//third_party/blink/renderer/core/style/COMMON_METADATA"
 
-team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/renderer/modules/accessibility/COMMON_METADATA b/third_party/blink/renderer/modules/accessibility/COMMON_METADATA
new file mode 100644
index 0000000..007f823
--- /dev/null
+++ b/third_party/blink/renderer/modules/accessibility/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Accessibility"
+}
+team_email: "chromium-accessibility@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/accessibility/DIR_METADATA b/third_party/blink/renderer/modules/accessibility/DIR_METADATA
index 007f823..f7c5b969 100644
--- a/third_party/blink/renderer/modules/accessibility/DIR_METADATA
+++ b/third_party/blink/renderer/modules/accessibility/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Accessibility"
-}
-team_email: "chromium-accessibility@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/accessibility/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/app_banner/COMMON_METADATA b/third_party/blink/renderer/modules/app_banner/COMMON_METADATA
new file mode 100644
index 0000000..45ae75a7
--- /dev/null
+++ b/third_party/blink/renderer/modules/app_banner/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Browser>WebAppInstalls"
+}
+team_email: "pwa-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/app_banner/DIR_METADATA b/third_party/blink/renderer/modules/app_banner/DIR_METADATA
index 45ae75a7..c32e345c 100644
--- a/third_party/blink/renderer/modules/app_banner/DIR_METADATA
+++ b/third_party/blink/renderer/modules/app_banner/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/app_banner/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/background_sync/DIR_METADATA b/third_party/blink/renderer/modules/background_sync/DIR_METADATA
index 283199ae..8a6d80f 100644
--- a/third_party/blink/renderer/modules/background_sync/DIR_METADATA
+++ b/third_party/blink/renderer/modules/background_sync/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>BackgroundSync"
-}
\ No newline at end of file
+mixins: "//components/background_sync/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/badging/DIR_METADATA b/third_party/blink/renderer/modules/badging/DIR_METADATA
index 45ae75a7..b7768f9 100644
--- a/third_party/blink/renderer/modules/badging/DIR_METADATA
+++ b/third_party/blink/renderer/modules/badging/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
\ No newline at end of file
+mixins: "//chrome/browser/badging/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/beacon/COMMON_METADATA b/third_party/blink/renderer/modules/beacon/COMMON_METADATA
new file mode 100644
index 0000000..17e49e6a
--- /dev/null
+++ b/third_party/blink/renderer/modules/beacon/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Network"
+}
+team_email: "blink-network-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/beacon/DIR_METADATA b/third_party/blink/renderer/modules/beacon/DIR_METADATA
index 17e49e6a..d0a05961 100644
--- a/third_party/blink/renderer/modules/beacon/DIR_METADATA
+++ b/third_party/blink/renderer/modules/beacon/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Network"
-}
-team_email: "blink-network-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/beacon/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/bluetooth/DIR_METADATA b/third_party/blink/renderer/modules/bluetooth/DIR_METADATA
index 1db37d6..cd51015 100644
--- a/third_party/blink/renderer/modules/bluetooth/DIR_METADATA
+++ b/third_party/blink/renderer/modules/bluetooth/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Bluetooth"
-}
-team_email: "web-bluetooth@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/bluetooth/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/buckets/DIR_METADATA b/third_party/blink/renderer/modules/buckets/DIR_METADATA
new file mode 100644
index 0000000..e4ba8a5a
--- /dev/null
+++ b/third_party/blink/renderer/modules/buckets/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//content/browser/buckets/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/cache_storage/DIR_METADATA b/third_party/blink/renderer/modules/cache_storage/DIR_METADATA
index c09c8e0..306fb835 100644
--- a/third_party/blink/renderer/modules/cache_storage/DIR_METADATA
+++ b/third_party/blink/renderer/modules/cache_storage/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>CacheStorage"
-}
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/cache_storage/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/compute_pressure/DIR_METADATA b/third_party/blink/renderer/modules/compute_pressure/DIR_METADATA
index 40a233c..dcc8a85 100644
--- a/third_party/blink/renderer/modules/compute_pressure/DIR_METADATA
+++ b/third_party/blink/renderer/modules/compute_pressure/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>PerformanceAPIs>ComputePressure"
-}
+mixins: "//content/browser/compute_pressure/COMMON_METADATA"
 
-team_email: "storage-dev@chromium.org"
diff --git a/third_party/blink/renderer/modules/cookie_store/DIR_METADATA b/third_party/blink/renderer/modules/cookie_store/DIR_METADATA
index 348e0c9a..fe26091 100644
--- a/third_party/blink/renderer/modules/cookie_store/DIR_METADATA
+++ b/third_party/blink/renderer/modules/cookie_store/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>CookiesAPI"
-}
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/cookie_store/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/direct_sockets/COMMON_METADATA b/third_party/blink/renderer/modules/direct_sockets/COMMON_METADATA
new file mode 100644
index 0000000..6cb0ce25
--- /dev/null
+++ b/third_party/blink/renderer/modules/direct_sockets/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Network"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/direct_sockets/DIR_METADATA b/third_party/blink/renderer/modules/direct_sockets/DIR_METADATA
index 6cb0ce25..07b80730 100644
--- a/third_party/blink/renderer/modules/direct_sockets/DIR_METADATA
+++ b/third_party/blink/renderer/modules/direct_sockets/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Network"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/direct_sockets/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/file_system_access/DIR_METADATA b/third_party/blink/renderer/modules/file_system_access/DIR_METADATA
index 9f7250a..29ed859f 100644
--- a/third_party/blink/renderer/modules/file_system_access/DIR_METADATA
+++ b/third_party/blink/renderer/modules/file_system_access/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>FileSystem"
-}
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/file_system_access/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/filesystem/COMMON_METADATA b/third_party/blink/renderer/modules/filesystem/COMMON_METADATA
new file mode 100644
index 0000000..9f7250a
--- /dev/null
+++ b/third_party/blink/renderer/modules/filesystem/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Storage>FileSystem"
+}
+team_email: "storage-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/filesystem/DIR_METADATA b/third_party/blink/renderer/modules/filesystem/DIR_METADATA
index 9f7250a..edbd35fe0 100644
--- a/third_party/blink/renderer/modules/filesystem/DIR_METADATA
+++ b/third_party/blink/renderer/modules/filesystem/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>FileSystem"
-}
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/filesystem/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/font_access/DIR_METADATA b/third_party/blink/renderer/modules/font_access/DIR_METADATA
index 2b228dc..be579e99 100644
--- a/third_party/blink/renderer/modules/font_access/DIR_METADATA
+++ b/third_party/blink/renderer/modules/font_access/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>FontAccess"
-}
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/font_access/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/hid/COMMON_METADATA b/third_party/blink/renderer/modules/hid/COMMON_METADATA
new file mode 100644
index 0000000..6a05639
--- /dev/null
+++ b/third_party/blink/renderer/modules/hid/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>HID"
+}
+team_email: "device-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/hid/DIR_METADATA b/third_party/blink/renderer/modules/hid/DIR_METADATA
index 6a05639..9260825 100644
--- a/third_party/blink/renderer/modules/hid/DIR_METADATA
+++ b/third_party/blink/renderer/modules/hid/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>HID"
-}
-team_email: "device-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/hid/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/idle/DIR_METADATA b/third_party/blink/renderer/modules/idle/DIR_METADATA
index d78e9e4..7b9dd684 100644
--- a/third_party/blink/renderer/modules/idle/DIR_METADATA
+++ b/third_party/blink/renderer/modules/idle/DIR_METADATA
@@ -1 +1 @@
-team_email: "fugu-dev@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/idle/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/locks/DIR_METADATA b/third_party/blink/renderer/modules/locks/DIR_METADATA
index 832447e4..7716613 100644
--- a/third_party/blink/renderer/modules/locks/DIR_METADATA
+++ b/third_party/blink/renderer/modules/locks/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage"
-}
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/locks/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/manifest/COMMON_METADATA b/third_party/blink/renderer/modules/manifest/COMMON_METADATA
new file mode 100644
index 0000000..0ff3ed55
--- /dev/null
+++ b/third_party/blink/renderer/modules/manifest/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>AppManifest"
+}
diff --git a/third_party/blink/renderer/modules/manifest/DIR_METADATA b/third_party/blink/renderer/modules/manifest/DIR_METADATA
index 0ff3ed55..78b240e 100644
--- a/third_party/blink/renderer/modules/manifest/DIR_METADATA
+++ b/third_party/blink/renderer/modules/manifest/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>AppManifest"
-}
+mixins: "//third_party/blink/renderer/modules/manifest/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/media/DIR_METADATA b/third_party/blink/renderer/modules/media/DIR_METADATA
index 0198eda..41e8f64 100644
--- a/third_party/blink/renderer/modules/media/DIR_METADATA
+++ b/third_party/blink/renderer/modules/media/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Media"
-}
\ No newline at end of file
+mixins: "//media/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/media_capabilities/COMMON_METADATA b/third_party/blink/renderer/modules/media_capabilities/COMMON_METADATA
new file mode 100644
index 0000000..9d49970
--- /dev/null
+++ b/third_party/blink/renderer/modules/media_capabilities/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Media>Capabilities"
+}
+team_email: "media-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/media_capabilities/DIR_METADATA b/third_party/blink/renderer/modules/media_capabilities/DIR_METADATA
index 9d49970..8b8bc4321 100644
--- a/third_party/blink/renderer/modules/media_capabilities/DIR_METADATA
+++ b/third_party/blink/renderer/modules/media_capabilities/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Media>Capabilities"
-}
-team_email: "media-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/media_capabilities/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/mediasession/COMMON_METADATA b/third_party/blink/renderer/modules/mediasession/COMMON_METADATA
new file mode 100644
index 0000000..3d5ee21
--- /dev/null
+++ b/third_party/blink/renderer/modules/mediasession/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Media>Session"
+}
+team_email: "media-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/mediasession/DIR_METADATA b/third_party/blink/renderer/modules/mediasession/DIR_METADATA
index 3d5ee21..6d22557 100644
--- a/third_party/blink/renderer/modules/mediasession/DIR_METADATA
+++ b/third_party/blink/renderer/modules/mediasession/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Media>Session"
-}
-team_email: "media-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/mediasession/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/native_io/DIR_METADATA b/third_party/blink/renderer/modules/native_io/DIR_METADATA
index 24413c7c36..9873cbb 100644
--- a/third_party/blink/renderer/modules/native_io/DIR_METADATA
+++ b/third_party/blink/renderer/modules/native_io/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Storage>NativeIO"
-}
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/native_io/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/netinfo/COMMON_METADATA b/third_party/blink/renderer/modules/netinfo/COMMON_METADATA
new file mode 100644
index 0000000..edfc773
--- /dev/null
+++ b/third_party/blink/renderer/modules/netinfo/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>Network>NetInfo"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/netinfo/DIR_METADATA b/third_party/blink/renderer/modules/netinfo/DIR_METADATA
index edfc773..6396aff 100644
--- a/third_party/blink/renderer/modules/netinfo/DIR_METADATA
+++ b/third_party/blink/renderer/modules/netinfo/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Internals>Network>NetInfo"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/netinfo/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/nfc/COMMON_METADATA b/third_party/blink/renderer/modules/nfc/COMMON_METADATA
new file mode 100644
index 0000000..b0c98883
--- /dev/null
+++ b/third_party/blink/renderer/modules/nfc/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>NFC"
+}
+team_email: "device-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/nfc/DIR_METADATA b/third_party/blink/renderer/modules/nfc/DIR_METADATA
index b0c98883..f38ac080 100644
--- a/third_party/blink/renderer/modules/nfc/DIR_METADATA
+++ b/third_party/blink/renderer/modules/nfc/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>NFC"
-}
-team_email: "device-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/nfc/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/notifications/COMMON_METADATA b/third_party/blink/renderer/modules/notifications/COMMON_METADATA
new file mode 100644
index 0000000..72589bb
--- /dev/null
+++ b/third_party/blink/renderer/modules/notifications/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "UI>Notifications"
+}
+team_email: "platform-capabilities@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/notifications/DIR_METADATA b/third_party/blink/renderer/modules/notifications/DIR_METADATA
index 72589bb..956386e 100644
--- a/third_party/blink/renderer/modules/notifications/DIR_METADATA
+++ b/third_party/blink/renderer/modules/notifications/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Notifications"
-}
-team_email: "platform-capabilities@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/notifications/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/payments/DIR_METADATA b/third_party/blink/renderer/modules/payments/DIR_METADATA
index 667a28bf..9dddbb4 100644
--- a/third_party/blink/renderer/modules/payments/DIR_METADATA
+++ b/third_party/blink/renderer/modules/payments/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Payments"
-}
-team_email: "payments-dev@chromium.org"
\ No newline at end of file
+mixins: "//components/payments/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/peerconnection/COMMON_METADATA b/third_party/blink/renderer/modules/peerconnection/COMMON_METADATA
new file mode 100644
index 0000000..7fdbb5e
--- /dev/null
+++ b/third_party/blink/renderer/modules/peerconnection/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebRTC"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/peerconnection/DIR_METADATA b/third_party/blink/renderer/modules/peerconnection/DIR_METADATA
index 7fdbb5e..7c8a8e8 100644
--- a/third_party/blink/renderer/modules/peerconnection/DIR_METADATA
+++ b/third_party/blink/renderer/modules/peerconnection/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebRTC"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/peerconnection/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/permissions/COMMON_METADATA b/third_party/blink/renderer/modules/permissions/COMMON_METADATA
new file mode 100644
index 0000000..0d36a0e
--- /dev/null
+++ b/third_party/blink/renderer/modules/permissions/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>PermissionsAPI"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/permissions/DIR_METADATA b/third_party/blink/renderer/modules/permissions/DIR_METADATA
index 0d36a0e..961484f 100644
--- a/third_party/blink/renderer/modules/permissions/DIR_METADATA
+++ b/third_party/blink/renderer/modules/permissions/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>PermissionsAPI"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/permissions/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/picture_in_picture/COMMON_METADATA b/third_party/blink/renderer/modules/picture_in_picture/COMMON_METADATA
new file mode 100644
index 0000000..c6851fa1
--- /dev/null
+++ b/third_party/blink/renderer/modules/picture_in_picture/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Media>PictureInPicture"
+}
+team_email: "media-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/picture_in_picture/DIR_METADATA b/third_party/blink/renderer/modules/picture_in_picture/DIR_METADATA
index c6851fa1..26f3796 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/DIR_METADATA
+++ b/third_party/blink/renderer/modules/picture_in_picture/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Media>PictureInPicture"
-}
-team_email: "media-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/picture_in_picture/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/presentation/COMMON_METADATA b/third_party/blink/renderer/modules/presentation/COMMON_METADATA
new file mode 100644
index 0000000..8c61a5f
--- /dev/null
+++ b/third_party/blink/renderer/modules/presentation/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>PresentationAPI"
+}
+team_email: "media-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/presentation/DIR_METADATA b/third_party/blink/renderer/modules/presentation/DIR_METADATA
index 8c61a5f..6e954ec 100644
--- a/third_party/blink/renderer/modules/presentation/DIR_METADATA
+++ b/third_party/blink/renderer/modules/presentation/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>PresentationAPI"
-}
-team_email: "media-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/presentation/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/push_messaging/DIR_METADATA b/third_party/blink/renderer/modules/push_messaging/DIR_METADATA
index ee3c1ea..a684b81 100644
--- a/third_party/blink/renderer/modules/push_messaging/DIR_METADATA
+++ b/third_party/blink/renderer/modules/push_messaging/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>PushAPI"
-}
-team_email: "platform-capabilities@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/push_messaging/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/quota/DIR_METADATA b/third_party/blink/renderer/modules/quota/DIR_METADATA
index d01bdb5..355a7d8 100644
--- a/third_party/blink/renderer/modules/quota/DIR_METADATA
+++ b/third_party/blink/renderer/modules/quota/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>Storage>Quota"
-}
+mixins: "//storage/browser/quota/COMMON_METADATA"
 team_email: "storage-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/remoteplayback/COMMON_METADATA b/third_party/blink/renderer/modules/remoteplayback/COMMON_METADATA
new file mode 100644
index 0000000..b8c73508
--- /dev/null
+++ b/third_party/blink/renderer/modules/remoteplayback/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Media>RemotePlayback"
+}
+team_email: "media-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/remoteplayback/DIR_METADATA b/third_party/blink/renderer/modules/remoteplayback/DIR_METADATA
index b8c73508..92a791a6 100644
--- a/third_party/blink/renderer/modules/remoteplayback/DIR_METADATA
+++ b/third_party/blink/renderer/modules/remoteplayback/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Media>RemotePlayback"
-}
-team_email: "media-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/remoteplayback/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/scheduler/DIR_METADATA b/third_party/blink/renderer/modules/scheduler/DIR_METADATA
new file mode 100644
index 0000000..99b25bc
--- /dev/null
+++ b/third_party/blink/renderer/modules/scheduler/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/platform/scheduler/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/screen_orientation/COMMON_METADATA b/third_party/blink/renderer/modules/screen_orientation/COMMON_METADATA
new file mode 100644
index 0000000..7a3e881
--- /dev/null
+++ b/third_party/blink/renderer/modules/screen_orientation/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>ScreenOrientation"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/screen_orientation/DIR_METADATA b/third_party/blink/renderer/modules/screen_orientation/DIR_METADATA
index 7a3e881..a18bc81 100644
--- a/third_party/blink/renderer/modules/screen_orientation/DIR_METADATA
+++ b/third_party/blink/renderer/modules/screen_orientation/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>ScreenOrientation"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/screen_orientation/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/serial/DIR_METADATA b/third_party/blink/renderer/modules/serial/DIR_METADATA
index 9b3d5d83..423968b 100644
--- a/third_party/blink/renderer/modules/serial/DIR_METADATA
+++ b/third_party/blink/renderer/modules/serial/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Serial"
-}
\ No newline at end of file
+mixins: "//content/browser/serial/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/service_worker/DIR_METADATA b/third_party/blink/renderer/modules/service_worker/DIR_METADATA
index f0962523..e253a13 100644
--- a/third_party/blink/renderer/modules/service_worker/DIR_METADATA
+++ b/third_party/blink/renderer/modules/service_worker/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>ServiceWorker"
-}
-team_email: "worker-dev@chromium.org"
\ No newline at end of file
+mixins: "//content/browser/service_worker/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/speech/COMMON_METADATA b/third_party/blink/renderer/modules/speech/COMMON_METADATA
new file mode 100644
index 0000000..a354eb6
--- /dev/null
+++ b/third_party/blink/renderer/modules/speech/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>Speech"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/speech/DIR_METADATA b/third_party/blink/renderer/modules/speech/DIR_METADATA
index a354eb6..4b16894 100644
--- a/third_party/blink/renderer/modules/speech/DIR_METADATA
+++ b/third_party/blink/renderer/modules/speech/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Speech"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/speech/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/subapps/COMMON_METADATA b/third_party/blink/renderer/modules/subapps/COMMON_METADATA
new file mode 100644
index 0000000..7f1ffb86
--- /dev/null
+++ b/third_party/blink/renderer/modules/subapps/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>WebAppInstalls>Desktop"
+}
diff --git a/third_party/blink/renderer/modules/subapps/DIR_METADATA b/third_party/blink/renderer/modules/subapps/DIR_METADATA
index 7f1ffb86..0b17525fb 100644
--- a/third_party/blink/renderer/modules/subapps/DIR_METADATA
+++ b/third_party/blink/renderer/modules/subapps/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "UI>Browser>WebAppInstalls>Desktop"
-}
+mixins: "//third_party/blink/renderer/modules/subapps/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/wake_lock/COMMON_METADATA b/third_party/blink/renderer/modules/wake_lock/COMMON_METADATA
new file mode 100644
index 0000000..c7b3d7e9
--- /dev/null
+++ b/third_party/blink/renderer/modules/wake_lock/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>WakeLock"
+}
+team_email: "device-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/wake_lock/DIR_METADATA b/third_party/blink/renderer/modules/wake_lock/DIR_METADATA
index c7b3d7e9..e5b41fd 100644
--- a/third_party/blink/renderer/modules/wake_lock/DIR_METADATA
+++ b/third_party/blink/renderer/modules/wake_lock/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>WakeLock"
-}
-team_email: "device-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/wake_lock/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/webaudio/COMMON_METADATA b/third_party/blink/renderer/modules/webaudio/COMMON_METADATA
new file mode 100644
index 0000000..cd6016a
--- /dev/null
+++ b/third_party/blink/renderer/modules/webaudio/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebAudio"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/webaudio/DIR_METADATA b/third_party/blink/renderer/modules/webaudio/DIR_METADATA
index cd6016a..a1448a1d 100644
--- a/third_party/blink/renderer/modules/webaudio/DIR_METADATA
+++ b/third_party/blink/renderer/modules/webaudio/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebAudio"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/webaudio/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/webgl/COMMON_METADATA b/third_party/blink/renderer/modules/webgl/COMMON_METADATA
new file mode 100644
index 0000000..ab221ae1
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgl/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebGL"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/webgl/DIR_METADATA b/third_party/blink/renderer/modules/webgl/DIR_METADATA
index ab221ae1..216bb112 100644
--- a/third_party/blink/renderer/modules/webgl/DIR_METADATA
+++ b/third_party/blink/renderer/modules/webgl/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebGL"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/webgl/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/webgpu/COMMON_METADATA b/third_party/blink/renderer/modules/webgpu/COMMON_METADATA
new file mode 100644
index 0000000..5f64887
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>WebGPU"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/webgpu/DIR_METADATA b/third_party/blink/renderer/modules/webgpu/DIR_METADATA
index 5f64887..45a4c8d 100644
--- a/third_party/blink/renderer/modules/webgpu/DIR_METADATA
+++ b/third_party/blink/renderer/modules/webgpu/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebGPU"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/webgpu/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index f4cce578..ff6ab16 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -189,12 +189,13 @@
   }
 }
 
-void GPUDevice::OnDeviceLostError(const char* message) {
+void GPUDevice::OnDeviceLostError(WGPUDeviceLostReason, const char* message) {
   if (!GetExecutionContext())
     return;
   AddConsoleWarning(message);
 
   if (lost_property_->GetState() == LostProperty::kPending) {
+    // TODO(crbug.com/1253721): Add the `reason` attribute to GPUDeviceLostInfo.
     auto* device_lost_info = MakeGarbageCollected<GPUDeviceLostInfo>(message);
     lost_property_->Resolve(device_lost_info);
   }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.h b/third_party/blink/renderer/modules/webgpu/gpu_device.h
index a8deb2b..16222442 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.h
@@ -146,7 +146,7 @@
 
   void OnUncapturedError(WGPUErrorType errorType, const char* message);
   void OnLogging(WGPULoggingType loggingType, const char* message);
-  void OnDeviceLostError(const char* message);
+  void OnDeviceLostError(WGPUDeviceLostReason, const char* message);
 
   void OnPopErrorScopeCallback(ScriptPromiseResolver* resolver,
                                WGPUErrorType type,
@@ -175,7 +175,9 @@
   // We need to be sure to free it on deletion of the device.
   // Inside OnDeviceLostError we'll release the unique_ptr to avoid a double
   // free.
-  std::unique_ptr<DawnRepeatingCallback<void(const char*)>> lost_callback_;
+  std::unique_ptr<
+      DawnRepeatingCallback<void(WGPUDeviceLostReason, const char*)>>
+      lost_callback_;
 
   static constexpr int kMaxAllowedConsoleWarnings = 500;
   int allowed_console_warnings_remaining_ = kMaxAllowedConsoleWarnings;
diff --git a/third_party/blink/renderer/modules/webid/DIR_METADATA b/third_party/blink/renderer/modules/webid/DIR_METADATA
index 48342130..136e07617 100644
--- a/third_party/blink/renderer/modules/webid/DIR_METADATA
+++ b/third_party/blink/renderer/modules/webid/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>Identity>WebID"
-}
\ No newline at end of file
+mixins: "//content/browser/webid/COMMON_METADATA"
diff --git a/third_party/blink/renderer/modules/webtransport/COMMON_METADATA b/third_party/blink/renderer/modules/webtransport/COMMON_METADATA
new file mode 100644
index 0000000..d6e9ab34
--- /dev/null
+++ b/third_party/blink/renderer/modules/webtransport/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Network>WebTransport"
+}
+team_email: "blink-network-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/webtransport/DIR_METADATA b/third_party/blink/renderer/modules/webtransport/DIR_METADATA
index d6e9ab34..cf2ab2d 100644
--- a/third_party/blink/renderer/modules/webtransport/DIR_METADATA
+++ b/third_party/blink/renderer/modules/webtransport/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Network>WebTransport"
-}
-team_email: "blink-network-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/webtransport/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 04bc65ba..5a6ddb7 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -437,6 +437,8 @@
     "bindings/no_alloc_direct_call_exception_state.h",
     "bindings/no_alloc_direct_call_host.cc",
     "bindings/no_alloc_direct_call_host.h",
+    "bindings/observable_array_base.cc",
+    "bindings/observable_array_base.h",
     "bindings/origin_trial_features.cc",
     "bindings/origin_trial_features.h",
     "bindings/parkable_string.cc",
diff --git a/third_party/blink/renderer/platform/animation/DIR_METADATA b/third_party/blink/renderer/platform/animation/DIR_METADATA
index 8146e606..8689198 100644
--- a/third_party/blink/renderer/platform/animation/DIR_METADATA
+++ b/third_party/blink/renderer/platform/animation/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Animation"
-}
-team_email: "animations-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/core/animation/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/bindings/DIR_METADATA b/third_party/blink/renderer/platform/bindings/DIR_METADATA
index 148e0eb..bfa202e 100644
--- a/third_party/blink/renderer/platform/bindings/DIR_METADATA
+++ b/third_party/blink/renderer/platform/bindings/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Bindings"
-}
-team_email: "blink-reviews-bindings@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/bindings/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/bindings/observable_array_base.cc b/third_party/blink/renderer/platform/bindings/observable_array_base.cc
new file mode 100644
index 0000000..d27a03e
--- /dev/null
+++ b/third_party/blink/renderer/platform/bindings/observable_array_base.cc
@@ -0,0 +1,35 @@
+// 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 "third_party/blink/renderer/platform/bindings/observable_array_base.h"
+
+namespace blink {
+
+namespace bindings {
+
+ObservableArrayBase::ObservableArrayBase(
+    ScriptWrappable* platform_object,
+    ObservableArrayExoticObject* observable_array_exotic_object)
+    : platform_object_(platform_object),
+      observable_array_exotic_object_(observable_array_exotic_object) {}
+
+void ObservableArrayBase::Trace(Visitor* visitor) const {
+  ScriptWrappable::Trace(visitor);
+  visitor->Trace(platform_object_);
+  visitor->Trace(observable_array_exotic_object_);
+}
+
+}  // namespace bindings
+
+ObservableArrayExoticObject::ObservableArrayExoticObject(
+    bindings::ObservableArrayBase* observable_array_backing_list_object)
+    : observable_array_backing_list_object_(
+          observable_array_backing_list_object) {}
+
+void ObservableArrayExoticObject::Trace(Visitor* visitor) const {
+  ScriptWrappable::Trace(visitor);
+  visitor->Trace(observable_array_backing_list_object_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/bindings/observable_array_base.h b/third_party/blink/renderer/platform/bindings/observable_array_base.h
new file mode 100644
index 0000000..f50bb91
--- /dev/null
+++ b/third_party/blink/renderer/platform/bindings/observable_array_base.h
@@ -0,0 +1,113 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_OBSERVABLE_ARRAY_BASE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_OBSERVABLE_ARRAY_BASE_H_
+
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+// Overview of Blink implementation of Web IDL observable arrays
+//
+// Observable arrays are implemented with two objects:
+// 1) backing list object
+// https://heycam.github.io/webidl/#observable-array-attribute-backing-list
+// and 2) exotic object.
+// https://heycam.github.io/webidl/#backing-observable-array-exotic-object
+// As DOM objects are implemented with a ScriptWrappable and its V8 wrappers,
+// there are a ScriptWrappable of a backing list object and its V8 wrappers,
+// also a ScriptWrappable of a exotic object and its (pseudo) V8 wrappers.
+//
+// By definition, observable array exotic object is a JS Proxy in ECMAScript
+// binding.
+//
+//   let exotic_object = new Proxy(backing_list_object, handler_object);
+//
+// For web developers, the JS Proxy object is the only visible object.  Web
+// developers cannot access the backing list object directly.
+//
+// For Blink developers, the backing list object looks the primary object.
+// However, when exposing an observable array to web developers, the exotic
+// object must be exposed instead of the backing list object.
+//
+//   class MyIdlInterface : public ScriptWrappable {
+//    public:
+//     ObservableArrayExoticObject* myAttr() const {
+//       // Expose the exotic object to web developers.
+//       return my_observable_array_->GetExoticObject();
+//     }
+//    private:
+//     // my_observable_array_ is a backing list object.
+//     Member<V8ObservableArrayNode> my_observable_array_;
+//   };
+//
+// Class hierarchy and relationship:
+//   bindings::ObservableArrayBase -- the base class of backing list objects
+//   +-- bindings::ObservableArrayImplHelper<T> -- just a helper
+//       +-- V8ObservableArrayNode -- generated implementation of IDL
+//               ObservableArray<Node>.  Bindings code generator produces this
+//               class from *.idl files.
+//   ObservableArrayExoticObject -- the base class of exotic objects
+//   +-- bindings::ObservableArrayExoticObjectImpl -- the implementation class
+//
+//   v8_exotic_object (= JS Proxy)
+//       --(proxy target)--> v8_backing_list_object
+//       --(internal field)--> blink_backing_list_object
+//       --(data member)--> blink_exotic_object
+//       --(ToV8Traits)--> v8_exotic_object
+
+namespace blink {
+
+class ObservableArrayExoticObject;
+
+namespace bindings {
+
+// ObservableArrayBase is the common base class of all the observable array
+// classes, and represents the backing list for an IDL attribute of an
+// observable array type (but the actual implementation lives in
+// bindings/core/v8/).
+// https://heycam.github.io/webidl/#observable-array-attribute-backing-list
+class PLATFORM_EXPORT ObservableArrayBase : public ScriptWrappable {
+ public:
+  explicit ObservableArrayBase(
+      ScriptWrappable* platform_object,
+      ObservableArrayExoticObject* observable_array_exotic_object);
+  ~ObservableArrayBase() override = default;
+
+  // Returns the observable array exotic object, which is the value to be
+  // returned as the IDL attribute value.  Do not use `this` object (= the
+  // observable array backing list object) as the IDL attribute value.
+  ObservableArrayExoticObject* GetExoticObject() const {
+    return observable_array_exotic_object_.Get();
+  }
+
+  void Trace(Visitor* visitor) const override;
+
+ private:
+  Member<ScriptWrappable> platform_object_;  // IDL attribute owner
+  Member<ObservableArrayExoticObject> observable_array_exotic_object_;
+};
+
+}  // namespace bindings
+
+// Represents a backing observable array exotic object.
+// https://heycam.github.io/webidl/#backing-observable-array-exotic-object
+class PLATFORM_EXPORT ObservableArrayExoticObject : public ScriptWrappable {
+ public:
+  explicit ObservableArrayExoticObject(
+      bindings::ObservableArrayBase* observable_array_backing_list_object);
+  ~ObservableArrayExoticObject() override = default;
+
+  bindings::ObservableArrayBase* GetBackingListObject() const {
+    return observable_array_backing_list_object_.Get();
+  }
+
+  void Trace(Visitor* visitor) const override;
+
+ private:
+  Member<bindings::ObservableArrayBase> observable_array_backing_list_object_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_OBSERVABLE_ARRAY_BASE_H_
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
index 5f51dd7..ad8af44 100644
--- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
+++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.cc
@@ -37,6 +37,12 @@
       v8_template = v8::FunctionTemplate::New(
           isolate, V8ObjectConstructor::IsValidConstructorMode);
       break;
+    case kIdlBufferSourceType:
+      NOTREACHED();
+      break;
+    case kIdlObservableArray:
+      v8_template = v8::FunctionTemplate::New(isolate);
+      break;
     case kCustomWrappableKind:
       v8_template = v8::FunctionTemplate::New(isolate);
       break;
diff --git a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
index f38ff5e..0dca2c9 100644
--- a/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
+++ b/third_party/blink/renderer/platform/bindings/wrapper_type_info.h
@@ -67,7 +67,11 @@
   };
 
   enum WrapperClassId {
-    kNodeClassId = 1,  // NodeClassId must be smaller than ObjectClassId.
+    // kNoInternalFieldClassId is used for the pseudo wrapper objects which do
+    // not have any internal field pointing to a Blink object.
+    kNoInternalFieldClassId = 0,
+    // NodeClassId must be smaller than ObjectClassId, also must be non-zero.
+    kNodeClassId = 1,
     kObjectClassId,
     kCustomWrappableId,
   };
@@ -82,6 +86,7 @@
     kIdlNamespace,
     kIdlCallbackInterface,
     kIdlBufferSourceType,
+    kIdlObservableArray,
     kCustomWrappableKind,
   };
 
@@ -103,7 +108,8 @@
   }
 
   void ConfigureWrapper(v8::TracedReference<v8::Object>* wrapper) const {
-    wrapper->SetWrapperClassId(wrapper_class_id);
+    if (wrapper_class_id != kNoInternalFieldClassId)
+      wrapper->SetWrapperClassId(wrapper_class_id);
   }
 
   // Returns a v8::Template of interface object, namespace object, or the
diff --git a/third_party/blink/renderer/platform/blob/DIR_METADATA b/third_party/blink/renderer/platform/blob/DIR_METADATA
index 08cf7a5..688b3c4 100644
--- a/third_party/blink/renderer/platform/blob/DIR_METADATA
+++ b/third_party/blink/renderer/platform/blob/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>Storage>FileAPI"
-}
+mixins: "//storage/browser/blob/COMMON_METADATA"
 team_email: "storage-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/platform/exported/mediastream/DIR_METADATA b/third_party/blink/renderer/platform/exported/mediastream/DIR_METADATA
index 02d2785..ec075d8b 100644
--- a/third_party/blink/renderer/platform/exported/mediastream/DIR_METADATA
+++ b/third_party/blink/renderer/platform/exported/mediastream/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>GetUserMedia"
-}
-team_email: "webrtc-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/common/mediastream/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/instrumentation/resource_coordinator/DIR_METADATA b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/DIR_METADATA
new file mode 100644
index 0000000..f87b987
--- /dev/null
+++ b/third_party/blink/renderer/platform/instrumentation/resource_coordinator/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//services/resource_coordinator/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/media/DIR_METADATA b/third_party/blink/renderer/platform/media/DIR_METADATA
new file mode 100644
index 0000000..41e8f64
--- /dev/null
+++ b/third_party/blink/renderer/platform/media/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//media/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/media_capabilities/DIR_METADATA b/third_party/blink/renderer/platform/media_capabilities/DIR_METADATA
new file mode 100644
index 0000000..8b8bc4321
--- /dev/null
+++ b/third_party/blink/renderer/platform/media_capabilities/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/media_capabilities/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/mediastream/DIR_METADATA b/third_party/blink/renderer/platform/mediastream/DIR_METADATA
index 02d2785..ec075d8b 100644
--- a/third_party/blink/renderer/platform/mediastream/DIR_METADATA
+++ b/third_party/blink/renderer/platform/mediastream/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>GetUserMedia"
-}
-team_email: "webrtc-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/common/mediastream/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/peerconnection/DIR_METADATA b/third_party/blink/renderer/platform/peerconnection/DIR_METADATA
index 7fdbb5e..7c8a8e8 100644
--- a/third_party/blink/renderer/platform/peerconnection/DIR_METADATA
+++ b/third_party/blink/renderer/platform/peerconnection/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebRTC"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/modules/peerconnection/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/privacy_budget/DIR_METADATA b/third_party/blink/renderer/platform/privacy_budget/DIR_METADATA
index 0644197..6d362b2 100644
--- a/third_party/blink/renderer/platform/privacy_budget/DIR_METADATA
+++ b/third_party/blink/renderer/platform/privacy_budget/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Privacy>Fingerprinting"
-}
-team_email: "privacy-sandbox-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/public/common/privacy_budget/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/scheduler/COMMON_METADATA b/third_party/blink/renderer/platform/scheduler/COMMON_METADATA
new file mode 100644
index 0000000..bba4e872
--- /dev/null
+++ b/third_party/blink/renderer/platform/scheduler/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail {
+  component: "Blink>Scheduling"
+}
+team_email: "scheduler-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/platform/scheduler/DIR_METADATA b/third_party/blink/renderer/platform/scheduler/DIR_METADATA
index bba4e872..99b25bc 100644
--- a/third_party/blink/renderer/platform/scheduler/DIR_METADATA
+++ b/third_party/blink/renderer/platform/scheduler/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Blink>Scheduling"
-}
-team_email: "scheduler-dev@chromium.org"
\ No newline at end of file
+mixins: "//third_party/blink/renderer/platform/scheduler/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/video_capture/COMMON_METADATA b/third_party/blink/renderer/platform/video_capture/COMMON_METADATA
new file mode 100644
index 0000000..84de928
--- /dev/null
+++ b/third_party/blink/renderer/platform/video_capture/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Blink>GetUserMedia>Webcam"
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/platform/video_capture/DIR_METADATA b/third_party/blink/renderer/platform/video_capture/DIR_METADATA
index 84de928..4bc84a2 100644
--- a/third_party/blink/renderer/platform/video_capture/DIR_METADATA
+++ b/third_party/blink/renderer/platform/video_capture/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>GetUserMedia>Webcam"
-}
\ No newline at end of file
+mixins: "//third_party/blink/renderer/platform/video_capture/COMMON_METADATA"
diff --git a/third_party/blink/renderer/platform/webrtc/DIR_METADATA b/third_party/blink/renderer/platform/webrtc/DIR_METADATA
index 7fdbb5e..58da5fd 100644
--- a/third_party/blink/renderer/platform/webrtc/DIR_METADATA
+++ b/third_party/blink/renderer/platform/webrtc/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
-  component: "Blink>WebRTC"
-}
\ No newline at end of file
+mixins: "//third_party/blink/public/platform/modules/webrtc/COMMON_METADATA"
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 8f3dd23..6b6675bf 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6739,13 +6739,6 @@
 crbug.com/1241860 http/tests/inspector-protocol/issues/cors-issues.js [ Skip ]
 crbug.com/1241860 http/tests/inspector-protocol/issues/renderer-cors-issues.js [ Skip ]
 
-# Temporarily disable to update DevTools Application Panel
-crbug.com/1110752 http/tests/devtools/application-panel/resources-panel-iframe-idb.js [ Failure Pass ]
-crbug.com/1110752 http/tests/devtools/application-panel/resources-panel-on-navigation.js [ Failure Pass ]
-crbug.com/1110752 http/tests/devtools/application-panel/resources-panel-resource-preview.js [ Failure Pass ]
-crbug.com/1110752 http/tests/devtools/application-panel/resources-panel-selection-on-reload.js [ Failure Pass ]
-crbug.com/1110752 http/tests/devtools/application-panel/resources-panel-websql.js [ Failure Pass ]
-
 # Credentials in same-origin Reporting-API reports are currently not implemented.
 crbug.com/1163645 external/wpt/reporting/same-origin-report-credentials.https.sub.html [ Failure ]
 
diff --git a/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations b/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations
index b9031211..03a7fda9 100644
--- a/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations
+++ b/third_party/blink/web_tests/android/WebLayerWPTOverrideExpectations
@@ -819,6 +819,7 @@
 crbug.com/1050754 external/wpt/external/wpt/payment-request/rejects_if_not_active.https.html [ Timeout ]
 crbug.com/1050754 external/wpt/external/wpt/resize-observer/observe.html [ Failure ]
 crbug.com/1050754 external/wpt/external/wpt/resize-observer/svg.html [ Failure ]
+crbug.com/1050754 external/wpt/external/wpt/storage-access-api/requestStorageAccess.sub.window.html [ Failure ]
 crbug.com/1050754 external/wpt/external/wpt/streams/piping/pipe-through.any.html [ Failure ]
 crbug.com/1050754 external/wpt/external/wpt/streams/piping/pipe-through.any.sharedworker.html [ Failure ]
 crbug.com/1050754 external/wpt/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html [ Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 35fce63..8baf1d5 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -368,6 +368,13 @@
         {}
        ]
       ],
+      "slot-content-visibility-14-crash.html": [
+       "0f36a7afee2e23621ad6213f0f2a0445a6697e4e",
+       [
+        null,
+        {}
+       ]
+      ],
       "slot-content-visibility-2-crash.html": [
        "47b7962ae0ba76f4387a1d8c35b782b64dc86a6b",
        [
@@ -2567,6 +2574,20 @@
      ]
     },
     "display-override-member": {
+     "display-override-member-app-region-window-controls-overlay-manual.tentative.html": [
+      "c802ba67fa4d89ae19d1d2dd52f0b57fcc7a832d",
+      [
+       null,
+       {}
+      ]
+     ],
+     "display-override-member-css-environment-variables-window-controls-overlay-manual.tentative.html": [
+      "2f06c5d6c7cbe7a8552f7b42315fa349de8f169f",
+      [
+       null,
+       {}
+      ]
+     ],
      "display-override-member-media-feature-browser-manual.tentative.html": [
       "d13d0986ad0c6d7aa193c0f8e26f193941ae98e7",
       [
@@ -2601,6 +2622,13 @@
        null,
        {}
       ]
+     ],
+     "display-override-member-media-feature-window-controls-overlay-overrides-browser-manual.tentative.html": [
+      "0929b43dec89c0ad50fd733fa48eb68177e9b8fa",
+      [
+       null,
+       {}
+      ]
      ]
     },
     "file_handlers-member": {
@@ -2665,7 +2693,7 @@
     },
     "name-member": {
      "name-member-manual.html": [
-      "8ba4110bd07a82e3a19e3c82d76ba543832a0cf1",
+      "577c821c3b7aa37b6aa3f7a88acbcf97397341eb",
       [
        null,
        {}
@@ -2674,14 +2702,14 @@
     },
     "orientation-member": {
      "orientation-member-landscape-manual.html": [
-      "acd22c00cd2f1808d8fd649933cbdf5fcceb0db8",
+      "8df111796494a84dbf89ea52ab1bf6f3b5f5836a",
       [
        null,
        {}
       ]
      ],
      "orientation-member-portrait-manual.html": [
-      "2c7c996e2a0b4421996cf9ff5f3e009cb77f8a60",
+      "ed866f3561d874ed7f5740d275c46bd58ac5f92a",
       [
        null,
        {}
@@ -2699,7 +2727,7 @@
     },
     "short_name-member": {
      "short_name-member-manual.html": [
-      "2ccb68cf0a7007c58b8a6c3e32fddc85690b2b86",
+      "ce5f8029fe3e1e68bb0cb021faf6bb6ff189549b",
       [
        null,
        {}
@@ -214672,10 +214700,26 @@
     },
     "display-override-member": {
      "display-override-member-media-feature-service-worker.js": [
-      "eec0d9972d00be2dd853bbd6ca952883f7ffe054",
+      "02818dc6650f78cc388872ffb47cb0d3d3e143af",
       []
      ],
      "resources": {
+      "display-override-member-app-region-window-controls-overlay.webmanifest": [
+       "a5f3af06b7ecd50db5822cba2980a01aa665db09",
+       []
+      ],
+      "display-override-member-app-region-window-controls-overlay.webmanifest.headers": [
+       "2bab061d43ab9e533b0160ca506231939886cd89",
+       []
+      ],
+      "display-override-member-css-environment-variables-window-controls-overlay.webmanifest": [
+       "ebfc0a0bd93f3c32f74ba9c25e814515355bff31",
+       []
+      ],
+      "display-override-member-css-environment-variables-window-controls-overlay.webmanifest.headers": [
+       "2bab061d43ab9e533b0160ca506231939886cd89",
+       []
+      ],
       "display-override-member-media-feature-browser.webmanifest": [
        "a384f6f2c89560484acb9300cc0e2358da304b92",
        []
@@ -214720,6 +214764,14 @@
        "2bab061d43ab9e533b0160ca506231939886cd89",
        []
       ],
+      "display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest": [
+       "75e91eaf877a2a520ff0baee6d96c49e3e138e7b",
+       []
+      ],
+      "display-override-member-media-feature-window-controls-overlay-overrides-browser.webmanifest.headers": [
+       "2bab061d43ab9e533b0160ca506231939886cd89",
+       []
+      ],
       "icon.png": [
        "637cc8daf463d1fcebe14cadb7d5eae90a5b67fe",
        []
@@ -214831,40 +214883,68 @@
      }
     },
     "name-member": {
-     "name-member-fail.webmanifest": [
-      "2fbf8809696490911cfe7eff8d83f620bc218a7a",
+     "name-member-service-worker.js": [
+      "5733f35636444d6be76eca6a3a72b78faf79e40c",
       []
      ],
-     "name-member-fail.webmanifest.headers": [
-      "23f36ea27ced7bba400a60e8e618757e5701cd88",
-      []
-     ],
-     "name-member.webmanifest": [
-      "c51d155a24cfb94322640e761803bb06ad19c9d4",
-      []
-     ],
-     "name-member.webmanifest.headers": [
-      "23f36ea27ced7bba400a60e8e618757e5701cd88",
-      []
-     ]
+     "resources": {
+      "icon.png": [
+       "6a06550023d202e03466d514f39efc39097ed753",
+       []
+      ],
+      "name-member-fail.webmanifest": [
+       "e1b29792071675c30f77c31da3ea66a59f91abef",
+       []
+      ],
+      "name-member-fail.webmanifest.headers": [
+       "23f36ea27ced7bba400a60e8e618757e5701cd88",
+       []
+      ],
+      "name-member-manual.js": [
+       "042b94f85b9db36c56e7a6ff35e028950bbd025b",
+       []
+      ],
+      "name-member.webmanifest": [
+       "366044f09ea12e50bde67b2c202107a1f22a1798",
+       []
+      ],
+      "name-member.webmanifest.headers": [
+       "23f36ea27ced7bba400a60e8e618757e5701cd88",
+       []
+      ]
+     }
     },
     "orientation-member": {
-     "orientation-member-landscape.webmanifest": [
-      "911b02a2f09a813e8f2f9faa7443a2a437c760ed",
+     "orientation-member-service-worker.js": [
+      "26f53c9816a5cfc9ffa5ea1fc36d8878192ffc58",
       []
      ],
-     "orientation-member-landscape.webmanifest.headers": [
-      "2bab061d43ab9e533b0160ca506231939886cd89",
-      []
-     ],
-     "orientation-member-portrait.webmanifest": [
-      "352489eff76ed9e6d0ec7b01500fd2869f0752ff",
-      []
-     ],
-     "orientation-member-portrait.webmanifest.headers": [
-      "2bab061d43ab9e533b0160ca506231939886cd89",
-      []
-     ]
+     "resources": {
+      "icon.png": [
+       "fecb1d2da4624763ac6dad48137d2c12b4b98e61",
+       []
+      ],
+      "orientation-member-landscape.webmanifest": [
+       "c930d292e58272c78d988ce6641ef72c7d2bb52c",
+       []
+      ],
+      "orientation-member-landscape.webmanifest.headers": [
+       "2bab061d43ab9e533b0160ca506231939886cd89",
+       []
+      ],
+      "orientation-member-manual.js": [
+       "6929c997a4c975befe0e962149689ee3449dcedb",
+       []
+      ],
+      "orientation-member-portrait.webmanifest": [
+       "7ddf0851ac746cd1e3023b1321b49f7026c59069",
+       []
+      ],
+      "orientation-member-portrait.webmanifest.headers": [
+       "2bab061d43ab9e533b0160ca506231939886cd89",
+       []
+      ]
+     }
     },
     "protocol_handlers-member": {
      "protocol_handlers-member-service-worker.js": [
@@ -214891,12 +214971,26 @@
      }
     },
     "short_name-member": {
-     "short_name-member.webmanifest": [
-      "66f357e294cb810a90e6b39f9d87a7a45ab8029d",
-      []
-     ],
-     "short_name-member.webmanifest.headers": [
-      "23f36ea27ced7bba400a60e8e618757e5701cd88",
+     "resources": {
+      "icon.png": [
+       "1798a17481ba41ade5a220284c9d6b2e78abd3ab",
+       []
+      ],
+      "short_name-member-manual.js": [
+       "7420e66c31079058b66ba2fdaace4717934685de",
+       []
+      ],
+      "short_name-member.webmanifest": [
+       "e456f55d601e2c864185e4ec94425a73b390ceeb",
+       []
+      ],
+      "short_name-member.webmanifest.headers": [
+       "23f36ea27ced7bba400a60e8e618757e5701cd88",
+       []
+      ]
+     },
+     "short_name-member-service-worker.js": [
+      "ed8cadb9af324313fe7c12374f9e07dbf9ae4db2",
       []
      ]
     },
@@ -288294,6 +288388,10 @@
      "973e380f7808eec4d031e62130107ec97297c6f5",
      []
     ],
+    "MediaDevices-produceCropId.https.html": [
+     "682caad7e7de5e79bae3a5b8d2b0da1bdfbb498f",
+     []
+    ],
     "MediaStream-MediaElement-firstframe.https-expected.txt": [
      "19c548627bb73155b5c0667321a7d939fcd54163",
      []
@@ -297025,6 +297123,14 @@
      []
     ],
     "resources": {
+     "hasStorageAccess-iframe.html": [
+      "3dfb80a7232f347517006d8994da827c4b6a6294",
+      []
+     ],
+     "requestStorageAccess-iframe.html": [
+      "f2cbcff86f894d84a657425180d00a5789407cb3",
+      []
+     ],
      "set-cookie.py": [
       "019697a4a8608943e0258664138ce9a7b6ae6876",
       []
@@ -479378,7 +479484,7 @@
    },
    "storage-access-api": {
     "hasStorageAccess.sub.window.js": [
-     "21400e68619a051bb25a4989d3b981504db7c5d9",
+     "16b32cdd09b9fe552ef2cbd031ec7f5662e8d9a2",
      [
       "storage-access-api/hasStorageAccess.sub.window.html",
       {
@@ -479414,7 +479520,7 @@
      ]
     ],
     "requestStorageAccess.sub.window.js": [
-     "35e5be9922ed828388ab07a03e5a385418efc37f",
+     "23d190f76a135b17e03edd4fd8b6c9c198c577eb",
      [
       "storage-access-api/requestStorageAccess.sub.window.html",
       {
diff --git a/third_party/blink/web_tests/external/wpt/beacon/DIR_METADATA b/third_party/blink/web_tests/external/wpt/beacon/DIR_METADATA
new file mode 100644
index 0000000..d0a05961
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/beacon/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/beacon/COMMON_METADATA"
diff --git a/third_party/blink/web_tests/external/wpt/bluetooth/DIR_METADATA b/third_party/blink/web_tests/external/wpt/bluetooth/DIR_METADATA
index 42da16d..c7987cd 100644
--- a/third_party/blink/web_tests/external/wpt/bluetooth/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/bluetooth/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Bluetooth"
-}
-team_email: "web-bluetooth@chromium.org"
+mixins: "//content/browser/bluetooth/COMMON_METADATA"
 
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-blocks-wasm.any.js b/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-blocks-wasm.any.js
new file mode 100644
index 0000000..15e9d87
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-blocks-wasm.any.js
@@ -0,0 +1,8 @@
+// META: global=window,worker
+
+promise_test(t => {
+  return promise_rejects_js(
+      t, WebAssembly.CompileError,
+      WebAssembly.instantiate(
+          new Uint8Array([0, 0x61, 0x73, 0x6d, 0x1, 0, 0, 0])));
+});
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-blocks-wasm.any.js.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-blocks-wasm.any.js.headers
new file mode 100644
index 0000000..de46ceb5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-blocks-wasm.any.js.headers
@@ -0,0 +1 @@
+Content-Security-Policy: script-src 'self' 'unsafe-inline'
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-unsafe-eval-allows-wasm.any.js b/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-unsafe-eval-allows-wasm.any.js
new file mode 100644
index 0000000..68a145c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-unsafe-eval-allows-wasm.any.js
@@ -0,0 +1,6 @@
+// META: global=window,worker
+
+promise_test(t => {
+  return WebAssembly.instantiate(
+      new Uint8Array([0, 0x61, 0x73, 0x6d, 0x1, 0, 0, 0]));
+});
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-unsafe-eval-allows-wasm.any.js.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-unsafe-eval-allows-wasm.any.js.headers
new file mode 100644
index 0000000..c0ce20d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/wasm-unsafe-eval/script-src-unsafe-eval-allows-wasm.any.js.headers
@@ -0,0 +1 @@
+Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval'
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-propagation-display-contents-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-propagation-display-contents-ref.html
new file mode 100644
index 0000000..1bbdafa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/reference/text-decoration-propagation-display-contents-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<body>
+<p style="text-decoration: overline; text-decoration-color: #44cc44;">
+  <span>Should have</span>
+  only overline.
+</p>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-propagation-display-contents.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-propagation-display-contents.html
new file mode 100644
index 0000000..70e839a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/text-decoration-propagation-display-contents.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-text-decor/#line-decoration">
+<!--
+Note: Line decorations are propagated through the box tree, not through
+inheritance, and thus have no effect on descendants when specified on an
+element with display: contents.
+-->
+<link rel="match" href="reference/text-decoration-propagation-display-contents-ref.html">
+<body>
+<p style="text-decoration: overline; text-decoration-color: #44cc44;">
+ <span style="text-decoration: underline; text-decoration-color: red; display: contents">
+  <span>Should have</span>
+  only overline.
+ </span>
+</p>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/mediasession/DIR_METADATA b/third_party/blink/web_tests/external/wpt/mediasession/DIR_METADATA
index f3bc0741..d5b96f9 100644
--- a/third_party/blink/web_tests/external/wpt/mediasession/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/mediasession/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>Media>Session"
-}
-team_email: "media-dev@chromium.org"
+mixins: "//third_party/blink/renderer/modules/mediasession/COMMON_METADATA"
 
diff --git a/third_party/blink/web_tests/external/wpt/netinfo/DIR_METADATA b/third_party/blink/web_tests/external/wpt/netinfo/DIR_METADATA
new file mode 100644
index 0000000..6396aff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/netinfo/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/netinfo/COMMON_METADATA"
diff --git a/third_party/blink/web_tests/external/wpt/notifications/DIR_METADATA b/third_party/blink/web_tests/external/wpt/notifications/DIR_METADATA
index e1461bf..1f97e23a 100644
--- a/third_party/blink/web_tests/external/wpt/notifications/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/notifications/DIR_METADATA
@@ -1,7 +1,4 @@
-monorail {
-  component: "UI>Notifications"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//third_party/blink/renderer/modules/notifications/COMMON_METADATA"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/hasStorageAccess.sub.window.js b/third_party/blink/web_tests/external/wpt/storage-access-api/hasStorageAccess.sub.window.js
index 21400e6..16b32cdd 100644
--- a/third_party/blink/web_tests/external/wpt/storage-access-api/hasStorageAccess.sub.window.js
+++ b/third_party/blink/web_tests/external/wpt/storage-access-api/hasStorageAccess.sub.window.js
@@ -52,16 +52,16 @@
   // of various iFrames
 
   // Create a test with a single-child same-origin iframe.
-  RunTestsInIFrame("hasStorageAccess.sub.window.html?testCase=same-origin-frame&rootdocument=false");
+  RunTestsInIFrame("resources/hasStorageAccess-iframe.html?testCase=same-origin-frame&rootdocument=false");
 
   // Create a test with a single-child cross-origin iframe.
-  RunTestsInIFrame("http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/hasStorageAccess.sub.window.html?testCase=cross-origin-frame&rootdocument=false");
+  RunTestsInIFrame("http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/resources/hasStorageAccess-iframe.html?testCase=cross-origin-frame&rootdocument=false");
 
   // Validate the nested-iframe scenario where the same-origin frame containing
   // the tests is not the first child.
-  RunTestsInNestedIFrame("hasStorageAccess.sub.window.html?testCase=nested-same-origin-frame&rootdocument=false");
+  RunTestsInNestedIFrame("resources/hasStorageAccess-iframe.html?testCase=nested-same-origin-frame&rootdocument=false");
 
   // Validate the nested-iframe scenario where the cross-origin frame containing
   //  the tests is not the first child.
-  RunTestsInNestedIFrame("http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/hasStorageAccess.sub.window.html?testCase=nested-cross-origin-frame&rootdocument=false");
+  RunTestsInNestedIFrame("http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/resources/hasStorageAccess-iframe.html?testCase=nested-cross-origin-frame&rootdocument=false");
 }
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess.sub.window.js b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess.sub.window.js
index 35e5be9..23d190f7 100644
--- a/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess.sub.window.js
+++ b/third_party/blink/web_tests/external/wpt/storage-access-api/requestStorageAccess.sub.window.js
@@ -42,18 +42,18 @@
   // of various iFrames
 
   // Create a test with a single-child same-origin iframe.
-  RunTestsInIFrame("requestStorageAccess.sub.window.html?testCase=same-origin-frame&rootdocument=false");
+  RunTestsInIFrame("resources/requestStorageAccess-iframe.html?testCase=same-origin-frame&rootdocument=false");
 
   // Create a test with a single-child cross-origin iframe.
-  RunTestsInIFrame("http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/requestStorageAccess.sub.window.html?testCase=cross-origin-frame&rootdocument=false");
+  RunTestsInIFrame("http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/resources/requestStorageAccess-iframe.html?testCase=cross-origin-frame&rootdocument=false");
 
   // Validate the nested-iframe scenario where the same-origin frame containing
   // the tests is not the first child.
-  RunTestsInNestedIFrame("requestStorageAccess.sub.window.html?testCase=nested-same-origin-frame&rootdocument=false");
+  RunTestsInNestedIFrame("resources/requestStorageAccess-iframe.html?testCase=nested-same-origin-frame&rootdocument=false");
 
   // Validate the nested-iframe scenario where the cross-origin frame containing
   //  the tests is not the first child.
-  RunTestsInNestedIFrame("http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/requestStorageAccess.sub.window.html?testCase=nested-cross-origin-frame&rootdocument=false");
+  RunTestsInNestedIFrame("http://{{domains[www]}}:{{ports[http][0]}}/storage-access-api/resources/requestStorageAccess-iframe.html?testCase=nested-cross-origin-frame&rootdocument=false");
 
   promise_test(async t => {
     await test_driver.set_permission({ name: 'storage-access' }, 'granted');
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/resources/hasStorageAccess-iframe.html b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/hasStorageAccess-iframe.html
new file mode 100644
index 0000000..3dfb80a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/hasStorageAccess-iframe.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<script src="/resources/testharness.js"></script>
+<!-- no testharnessreport.js -->
+<script src="../helpers.js"></script>
+<div id=log></div>
+<script src="/storage-access-api/hasStorageAccess.sub.window.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/storage-access-api/resources/requestStorageAccess-iframe.html b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/requestStorageAccess-iframe.html
new file mode 100644
index 0000000..f2cbcff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/storage-access-api/resources/requestStorageAccess-iframe.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<script src="/resources/testharness.js"></script>
+<!-- no testharnessreport.js -->
+<script src="../helpers.js"></script>
+<div id=log></div>
+<script src="/storage-access-api/requestStorageAccess.sub.window.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/DIR_METADATA b/third_party/blink/web_tests/external/wpt/webgpu/DIR_METADATA
index 8d42944..579c17b 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/webgpu/DIR_METADATA
@@ -1,6 +1,4 @@
-monorail {
-  component: "Blink>WebGPU"
-}
+mixins: "//third_party/blink/renderer/modules/webgpu/COMMON_METADATA"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-iframe-idb-expected.txt b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-iframe-idb-expected.txt
index c839cf8..d84616b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-iframe-idb-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-iframe-idb-expected.txt
@@ -24,7 +24,7 @@
  Trust Tokens
 Cache
  Cache Storage
- Application Cache
+ Back-forward Cache
 Background Services
  Background Fetch
  Background Sync
@@ -58,7 +58,7 @@
  Trust Tokens
 Cache
  Cache Storage
- Application Cache
+ Back-forward Cache
 Background Services
  Background Fetch
  Background Sync
@@ -94,7 +94,7 @@
  Trust Tokens
 Cache
  Cache Storage
- Application Cache
+ Back-forward Cache
 Background Services
  Background Fetch
  Background Sync
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-on-navigation-expected.txt b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-on-navigation-expected.txt
index 3d91fa2..29ed961 100644
--- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-on-navigation-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-on-navigation-expected.txt
@@ -19,7 +19,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
@@ -50,7 +50,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-resource-preview-expected.txt b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-resource-preview-expected.txt
index cfd44549..b630681 100644
--- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-resource-preview-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-resource-preview-expected.txt
@@ -17,7 +17,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
@@ -50,7 +50,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
@@ -83,7 +83,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
@@ -116,7 +116,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-selection-on-reload-expected.txt b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-selection-on-reload-expected.txt
index 3e28286a..f45a381 100644
--- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-selection-on-reload-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-selection-on-reload-expected.txt
@@ -19,7 +19,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
@@ -51,7 +51,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-websql-expected.txt b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-websql-expected.txt
index 0be6b5d..5353e6c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-websql-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-websql-expected.txt
@@ -17,7 +17,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
@@ -49,7 +49,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
@@ -81,7 +81,7 @@
   Trust Tokens
 Cache
   Cache Storage
-  Application Cache
+  Back-forward Cache
 Background Services
   Background Fetch
   Background Sync
diff --git a/third_party/blink/web_tests/http/tests/usb/DIR_METADATA b/third_party/blink/web_tests/http/tests/usb/DIR_METADATA
index 5a176d6..a29da86 100644
--- a/third_party/blink/web_tests/http/tests/usb/DIR_METADATA
+++ b/third_party/blink/web_tests/http/tests/usb/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink>USB"
-}
-team_email: "webusb@chromium.org"
+mixins: "//chrome/browser/usb/COMMON_METADATA"
 
diff --git a/third_party/blink/web_tests/virtual/presentation/DIR_METADATA b/third_party/blink/web_tests/virtual/presentation/DIR_METADATA
new file mode 100644
index 0000000..6e954ec
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/presentation/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/presentation/COMMON_METADATA"
diff --git a/third_party/blink/web_tests/wpt_internal/presentation/DIR_METADATA b/third_party/blink/web_tests/wpt_internal/presentation/DIR_METADATA
new file mode 100644
index 0000000..6e954ec
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/presentation/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/renderer/modules/presentation/COMMON_METADATA"
diff --git a/third_party/blink/web_tests/wpt_internal/serial/DIR_METADATA b/third_party/blink/web_tests/wpt_internal/serial/DIR_METADATA
index 7e587b65..6e8c2dcc 100644
--- a/third_party/blink/web_tests/wpt_internal/serial/DIR_METADATA
+++ b/third_party/blink/web_tests/wpt_internal/serial/DIR_METADATA
@@ -1,4 +1,2 @@
-monorail {
-  component: "Blink>Serial"
-}
+mixins: "//content/browser/serial/COMMON_METADATA"
 
diff --git a/third_party/win_build_output/midl/chrome/updater/DIR_METADATA b/third_party/win_build_output/midl/chrome/updater/DIR_METADATA
index cd0202c..593a8a1 100644
--- a/third_party/win_build_output/midl/chrome/updater/DIR_METADATA
+++ b/third_party/win_build_output/midl/chrome/updater/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Updater"
-}
+mixins: "//chrome/updater/COMMON_METADATA"
diff --git a/tools/accessibility/DIR_METADATA b/tools/accessibility/DIR_METADATA
index 8dd4f6f..da0b9fc52 100644
--- a/tools/accessibility/DIR_METADATA
+++ b/tools/accessibility/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Internals>Accessibility"
-}
-team_email: "chromium-accessibility@chromium.org"
\ No newline at end of file
+mixins: "//ui/accessibility/COMMON_METADATA"
diff --git a/tools/aggregation_service/DIR_METADATA b/tools/aggregation_service/DIR_METADATA
index 4f8aa58..e5ef722 100644
--- a/tools/aggregation_service/DIR_METADATA
+++ b/tools/aggregation_service/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>ConversionMeasurement"
-}
-team_email: "privacy-sandbox-dev@chromium.org"
+mixins: "//content/browser/aggregation_service/COMMON_METADATA"
diff --git a/tools/fuchsia/DIR_METADATA b/tools/fuchsia/DIR_METADATA
index 11f5ec9..5b3985ec 100644
--- a/tools/fuchsia/DIR_METADATA
+++ b/tools/fuchsia/DIR_METADATA
@@ -6,8 +6,5 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Fuchsia"
-}
-team_email: "cr-fuchsia@chromium.org"
+mixins: "//build/fuchsia/COMMON_METADATA"
 os: FUCHSIA
\ No newline at end of file
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml
index a753b086..655b5f2 100644
--- a/tools/metrics/histograms/metadata/ios/histograms.xml
+++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -1075,7 +1075,7 @@
 </histogram>
 
 <histogram name="IOS.RestoreNavigationItemCount" units="rank"
-    expires_after="2021-11-07">
+    expires_after="2022-09-12">
   <owner>gambard@chromium.org</owner>
   <owner>justincohen@chromium.org</owner>
   <summary>
@@ -1089,7 +1089,7 @@
 </histogram>
 
 <histogram name="IOS.RestoreNavigationTime" units="ms"
-    expires_after="2021-11-07">
+    expires_after="2022-09-12">
   <owner>gambard@chromium.org</owner>
   <owner>justincohen@chromium.org</owner>
   <summary>
@@ -1103,7 +1103,7 @@
 </histogram>
 
 <histogram name="IOS.SafeBrowsing.RedirectedRequestResponseHostsMatch"
-    enum="BooleanMatched" expires_after="2021-11-06">
+    enum="BooleanMatched" expires_after="2022-11-06">
   <owner>ajuma@chromium.org</owner>
   <owner>gambard@chromium.org</owner>
   <summary>
diff --git a/tools/origin_trials/DIR_METADATA b/tools/origin_trials/DIR_METADATA
new file mode 100644
index 0000000..14641a38
--- /dev/null
+++ b/tools/origin_trials/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//third_party/blink/common/origin_trials/COMMON_METADATA"
diff --git a/tools/origin_trials/third_party/ed25519/DIR_METADATA b/tools/origin_trials/third_party/ed25519/DIR_METADATA
deleted file mode 100644
index b21fcd9..0000000
--- a/tools/origin_trials/third_party/ed25519/DIR_METADATA
+++ /dev/null
@@ -1,12 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>OriginTrials"
-}
-team_email: "experimentation-dev@chromium.org"
\ No newline at end of file
diff --git a/tools/privacy_budget/DIR_METADATA b/tools/privacy_budget/DIR_METADATA
index fe6ef77..6d362b2 100644
--- a/tools/privacy_budget/DIR_METADATA
+++ b/tools/privacy_budget/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Privacy>Fingerprinting"
-}
-team_email: "privacy-sandbox-dev@chromium.org"
+mixins: "//third_party/blink/public/common/privacy_budget/COMMON_METADATA"
diff --git a/ui/accessibility/COMMON_METADATA b/ui/accessibility/COMMON_METADATA
new file mode 100644
index 0000000..fe89fde6
--- /dev/null
+++ b/ui/accessibility/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "Internals>Accessibility"
+}
+team_email: "chromium-accessibility@chromium.org"
diff --git a/ui/accessibility/DIR_METADATA b/ui/accessibility/DIR_METADATA
index fe89fde6..36b12b6 100644
--- a/ui/accessibility/DIR_METADATA
+++ b/ui/accessibility/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Internals>Accessibility"
-}
-team_email: "chromium-accessibility@chromium.org"
+mixins: "//ui/accessibility/COMMON_METADATA"
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/COMMON_METADATA b/ui/android/java/src/org/chromium/ui/modaldialog/COMMON_METADATA
new file mode 100644
index 0000000..835d044e
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Mobile>Messages"
+}
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/DIR_METADATA b/ui/android/java/src/org/chromium/ui/modaldialog/DIR_METADATA
index 99e96ee..8602f7e 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/DIR_METADATA
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "UI>Browser>Mobile>Messages"
-}
+mixins: "//ui/android/java/src/org/chromium/ui/modaldialog/COMMON_METADATA"
diff --git a/ui/base/ime/ash/input_method_util.cc b/ui/base/ime/ash/input_method_util.cc
index 1be32af5..14a48d6 100644
--- a/ui/base/ime/ash/input_method_util.cc
+++ b/ui/base/ime/ash/input_method_util.cc
@@ -437,10 +437,8 @@
   return input_method_id;
 }
 
-bool InputMethodUtil::TranslateStringInternal(
-    const std::string& english_string,
-    std::u16string* out_string) const {
-  DCHECK(out_string);
+std::u16string InputMethodUtil::TranslateString(
+    const std::string& english_string) const {
   // |english_string| could be an input method id. So legacy xkb id is required
   // to get the translated string.
   std::string key_string = MaybeGetLegacyXkbId(english_string);
@@ -452,20 +450,10 @@
     // ID array (crosbug.com/4572).
     LOG(ERROR) << "Resource ID is not found for: " << english_string
                << ", " << key_string;
-    return false;
+    return base::UTF8ToUTF16(english_string);
   }
 
-  *out_string = delegate_->GetLocalizedString(iter->second);
-  return true;
-}
-
-std::u16string InputMethodUtil::TranslateString(
-    const std::string& english_string) const {
-  std::u16string localized_string;
-  if (TranslateStringInternal(english_string, &localized_string)) {
-    return localized_string;
-  }
-  return base::UTF8ToUTF16(english_string);
+  return delegate_->GetLocalizedString(iter->second);
 }
 
 bool InputMethodUtil::IsValidInputMethodId(
diff --git a/ui/base/ime/fuchsia/DIR_METADATA b/ui/base/ime/fuchsia/DIR_METADATA
new file mode 100644
index 0000000..210aa6a
--- /dev/null
+++ b/ui/base/ime/fuchsia/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//build/fuchsia/COMMON_METADATA"
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index 73360a5..a23e92e 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -54,7 +54,7 @@
     "//base",
   ]
 
-  if (is_win || is_mac || use_ozone || use_x11) {
+  if (is_win || is_mac || use_ozone) {
     public += [ "keycodes/dom/dom_keyboard_layout_map.h" ]
 
     sources += [
@@ -171,7 +171,7 @@
     deps += [ "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.input3" ]
   }
 
-  if (use_x11 || ozone_platform_x11) {
+  if (ozone_platform_x11) {
     public_deps += [ "//ui/events/keycodes:x11" ]
 
     # TODO(https://crbug.com/1076277): This dependency on //ui/gfx/x
@@ -289,7 +289,7 @@
   # template which generates different target names on different platforms.
   friend = [ ":*" ]
 
-  if (use_x11 || ozone_platform_x11) {
+  if (ozone_platform_x11) {
     public += [ "x/x11_event_translation.h" ]
     sources += [ "x/x11_event_translation.cc" ]
     deps += [
@@ -305,7 +305,7 @@
     configs += [ "//build/config/linux:glib" ]
   }
 
-  if (use_ozone || use_x11) {
+  if (use_ozone) {
     sources += [ "events_default.cc" ]
   }
 
@@ -337,7 +337,7 @@
     deps += [ "//build:chromeos_buildflags" ]
   }
 
-  if (is_win || is_mac || use_x11 || use_ozone) {
+  if (is_win || is_mac || use_ozone) {
     sources -= [ "events_stub.cc" ]
   }
 
@@ -420,25 +420,6 @@
     sources += [ "mac/keyboard_hook_mac.mm" ]
   }
 
-  if (use_x11) {
-    sources += [
-      "x/keyboard_hook_x11.cc",
-      "x/keyboard_hook_x11.h",
-    ]
-    deps += [
-      "//ui/base/x",
-      "//ui/gfx/x",
-    ]
-  }
-
-  if (use_ozone || use_x11) {
-    if (is_linux || is_chromeos) {
-      # TODO(https://crbug.com/1099225): refactor X11 kbd hook and implement
-      # that for Ozone.
-      sources += [ "keyboard_hook_linux.cc" ]
-    }
-  }
-
   if (use_ozone) {
     public += [ "ozone/keyboard_hook_ozone.h" ]
     sources += [ "ozone/keyboard_hook_ozone.cc" ]
@@ -582,7 +563,7 @@
     frameworks = [ "Carbon.framework" ]
   }
 
-  if (use_x11 || ozone_platform_x11) {
+  if (ozone_platform_x11) {
     sources += [
       "test/events_test_utils_x11.cc",
       "test/events_test_utils_x11.h",
@@ -685,7 +666,7 @@
       data_deps = [ "//third_party/mesa_headers" ]
     }
 
-    if (use_x11 || use_ozone) {
+    if (use_ozone) {
       sources += [ "devices/device_data_manager_unittest.cc" ]
     }
 
diff --git a/ui/events/blink/BUILD.gn b/ui/events/blink/BUILD.gn
index bfe2424..39e317c 100644
--- a/ui/events/blink/BUILD.gn
+++ b/ui/events/blink/BUILD.gn
@@ -45,10 +45,6 @@
     "//ui/latency",
   ]
 
-  if (use_x11) {
-    deps += [ "//ui/gfx/x" ]
-  }
-
   if (is_win) {
     sources += [
       "web_input_event_builders_win.cc",
diff --git a/ui/events/blink/web_input_event.cc b/ui/events/blink/web_input_event.cc
index cae38e2..a6b8059 100644
--- a/ui/events/blink/web_input_event.cc
+++ b/ui/events/blink/web_input_event.cc
@@ -17,9 +17,6 @@
 #include "ui/events/blink/web_input_event_builders_win.h"
 #endif
 
-#if defined(USE_X11)
-#endif
-
 namespace ui {
 
 namespace {
diff --git a/ui/events/devices/x11/BUILD.gn b/ui/events/devices/x11/BUILD.gn
index 6db5a39..221e503 100644
--- a/ui/events/devices/x11/BUILD.gn
+++ b/ui/events/devices/x11/BUILD.gn
@@ -5,7 +5,7 @@
 import("//build/config/ozone.gni")
 import("//build/config/ui.gni")
 
-assert(use_x11 || ozone_platform_x11)
+assert(ozone_platform_x11)
 
 component("x11") {
   output_name = "events_devices_x11"
diff --git a/ui/events/event.cc b/ui/events/event.cc
index 5da7c44..b43d4c0 100644
--- a/ui/events/event.cc
+++ b/ui/events/event.cc
@@ -341,11 +341,9 @@
   ComputeEventLatencyOS(native_event);
 
 #if defined(USE_OZONE)
-  if (features::IsUsingOzonePlatform()) {
     source_device_id_ = native_event->source_device_id();
     if (auto* properties = native_event->properties())
       properties_ = std::make_unique<Properties>(*properties);
-  }
 #endif
 }
 
@@ -827,7 +825,7 @@
 
 // static
 KeyEvent* KeyEvent::last_key_event_ = nullptr;
-#if defined(USE_X11) || defined(USE_OZONE)
+#if defined(USE_OZONE)
 KeyEvent* KeyEvent::last_ibus_key_event_ = nullptr;
 #endif
 
@@ -938,7 +936,7 @@
   if (synthesize_key_repeat_enabled_ && IsRepeated(GetLastKeyEvent()))
     set_flags(flags() | EF_IS_REPEAT);
 
-#if defined(USE_X11)
+#if defined(OS_LINUX)
   NormalizeFlags();
 #elif defined(OS_WIN)
   // Only Windows has native character events.
@@ -972,8 +970,7 @@
 
   KeyboardCode dummy_key_code;
 #if defined(USE_OZONE)
-  if (features::IsUsingOzonePlatform() &&
-      KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
+  if (KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()->Lookup(
           code, flags(), &key_, &dummy_key_code)) {
     return;
   }
@@ -1052,7 +1049,7 @@
 }
 
 KeyEvent** KeyEvent::GetLastKeyEvent() {
-#if defined(USE_X11) || defined(USE_OZONE)
+#if defined(USE_OZONE)
   // Use a different static variable for key events that have non standard
   // state masks as it may be reposted by an IME. IBUS-GTK and fcitx-GTK uses
   // this field to detect the re-posted event for example. crbug.com/385873.
diff --git a/ui/events/event.h b/ui/events/event.h
index 296227d..2dba364a 100644
--- a/ui/events/event.h
+++ b/ui/events/event.h
@@ -935,7 +935,7 @@
   mutable DomKey key_ = DomKey::NONE;
 
   static KeyEvent* last_key_event_;
-#if defined(USE_X11) || defined(USE_OZONE)
+#if defined(USE_OZONE)
   static KeyEvent* last_ibus_key_event_;
 #endif
 
diff --git a/ui/events/event_switches.cc b/ui/events/event_switches.cc
index 0bdb883..301b39a 100644
--- a/ui/events/event_switches.cc
+++ b/ui/events/event_switches.cc
@@ -26,7 +26,7 @@
 const char kPenDevices[] = "pen-devices";
 #endif
 
-#if defined(USE_X11) || defined(USE_OZONE)
+#if defined(USE_OZONE)
 // Tells Chrome to do edge touch filtering. Useful for convertible tablet.
 const char kEdgeTouchFiltering[] = "edge-touch-filtering";
 
diff --git a/ui/events/event_switches.h b/ui/events/event_switches.h
index 7e6d7360..f23c159 100644
--- a/ui/events/event_switches.h
+++ b/ui/events/event_switches.h
@@ -18,7 +18,7 @@
 EVENTS_BASE_EXPORT extern const char kPenDevices[];
 #endif
 
-#if defined(USE_X11) || defined(USE_OZONE)
+#if defined(USE_OZONE)
 EVENTS_BASE_EXPORT extern const char kEdgeTouchFiltering[];
 EVENTS_BASE_EXPORT extern const char kDisableCancelAllTouches[];
 #endif
diff --git a/ui/events/fuchsia/DIR_METADATA b/ui/events/fuchsia/DIR_METADATA
index 11f5ec9..5b3985ec 100644
--- a/ui/events/fuchsia/DIR_METADATA
+++ b/ui/events/fuchsia/DIR_METADATA
@@ -6,8 +6,5 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "Fuchsia"
-}
-team_email: "cr-fuchsia@chromium.org"
+mixins: "//build/fuchsia/COMMON_METADATA"
 os: FUCHSIA
\ No newline at end of file
diff --git a/ui/events/keyboard_hook_linux.cc b/ui/events/keyboard_hook_linux.cc
deleted file mode 100644
index 4f8c599..0000000
--- a/ui/events/keyboard_hook_linux.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/events/keyboard_hook.h"
-
-#include <memory>
-
-#include "base/callback.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "ui/events/keycodes/dom/dom_code.h"
-#include "ui/gfx/native_widget_types.h"
-
-#if defined(USE_X11)
-#include "ui/events/x/keyboard_hook_x11.h"
-#endif
-
-#if defined(USE_OZONE)
-#include "ui/base/ui_base_features.h"
-#include "ui/events/ozone/keyboard_hook_ozone.h"
-#include "ui/ozone/public/platform_keyboard_hook.h"
-#endif
-
-namespace ui {
-
-// static
-std::unique_ptr<KeyboardHook> KeyboardHook::CreateModifierKeyboardHook(
-    absl::optional<base::flat_set<DomCode>> dom_codes,
-    gfx::AcceleratedWidget accelerated_widget,
-    KeyEventCallback callback) {
-#if defined(USE_OZONE)
-  if (features::IsUsingOzonePlatform()) {
-    return std::make_unique<KeyboardHookOzone>(
-        PlatformKeyboardHookTypes::kModifier, std::move(callback),
-        std::move(dom_codes), accelerated_widget);
-  }
-#endif
-#if defined(USE_X11)
-  auto keyboard_hook_x11 = std::make_unique<KeyboardHookX11>(
-      std::move(dom_codes), accelerated_widget, std::move(callback));
-  if (!keyboard_hook_x11->RegisterHook())
-    return nullptr;
-  return keyboard_hook_x11;
-#else
-  NOTREACHED();
-  return nullptr;
-#endif
-}
-
-// static
-std::unique_ptr<KeyboardHook> KeyboardHook::CreateMediaKeyboardHook(
-    KeyEventCallback callback) {
-  return nullptr;
-}
-
-}  // namespace ui
diff --git a/ui/events/keycodes/BUILD.gn b/ui/events/keycodes/BUILD.gn
index 86bbf620..c7fe1117 100644
--- a/ui/events/keycodes/BUILD.gn
+++ b/ui/events/keycodes/BUILD.gn
@@ -26,7 +26,7 @@
   ]
 }
 
-if (use_x11 || ozone_platform_x11) {
+if (ozone_platform_x11) {
   component("x11") {
     output_name = "keycodes_x11"
 
diff --git a/ui/events/ozone/keyboard_hook_ozone.cc b/ui/events/ozone/keyboard_hook_ozone.cc
index bb07560..668e1fb 100644
--- a/ui/events/ozone/keyboard_hook_ozone.cc
+++ b/ui/events/ozone/keyboard_hook_ozone.cc
@@ -34,7 +34,6 @@
   return platform_keyboard_hook_->IsKeyLocked(dom_code);
 }
 
-#if !defined(OS_LINUX) && !defined(OS_CHROMEOS)
 // static
 std::unique_ptr<KeyboardHook> KeyboardHook::CreateModifierKeyboardHook(
     absl::optional<base::flat_set<DomCode>> dom_codes,
@@ -50,6 +49,5 @@
     KeyEventCallback callback) {
   return nullptr;
 }
-#endif
 
 }  // namespace ui
diff --git a/ui/events/ozone/layout/BUILD.gn b/ui/events/ozone/layout/BUILD.gn
index c7a5230b..c7f42d6 100644
--- a/ui/events/ozone/layout/BUILD.gn
+++ b/ui/events/ozone/layout/BUILD.gn
@@ -5,8 +5,7 @@
 import("//build/config/linux/pkg_config.gni")
 import("//ui/base/ui_features.gni")
 
-# Chromedriver uses this in X11 builds for StubKeyboardLayoutEngine.
-assert(use_ozone || use_x11)
+assert(use_ozone)
 
 if (use_xkbcommon) {
   pkg_config("xkbcommon") {
@@ -81,7 +80,8 @@
 
   sources = [
     "keyboard_layout_engine_test_utils.cc",
-    "keyboard_layout_engine_test_utils.h", ]
+    "keyboard_layout_engine_test_utils.h",
+  ]
 
   deps = [
     ":layout",
diff --git a/ui/events/ozone/layout/keyboard_layout_engine_test_utils.cc b/ui/events/ozone/layout/keyboard_layout_engine_test_utils.cc
index 09c73ba..f85a39f 100644
--- a/ui/events/ozone/layout/keyboard_layout_engine_test_utils.cc
+++ b/ui/events/ozone/layout/keyboard_layout_engine_test_utils.cc
@@ -6,7 +6,6 @@
 
 #include "base/callback.h"
 #include "base/run_loop.h"
-#include "ui/base/ui_base_features.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 
@@ -16,8 +15,6 @@
 // sets up XkbKeyboardLayoutEngine differently. When that is fixed, remove the
 // workaround function below.
 void WaitUntilLayoutEngineIsReadyForTest() {
-  if (!features::IsUsingOzonePlatform())
-    return;
   // The platform may set the keyboard layout asynchronously.  We need the
   // layout when handling key events, so wait until it is ready.
   //
diff --git a/ui/events/platform/BUILD.gn b/ui/events/platform/BUILD.gn
index 64efb0bb..b1d2da4 100644
--- a/ui/events/platform/BUILD.gn
+++ b/ui/events/platform/BUILD.gn
@@ -24,8 +24,4 @@
     "//base",
     "//ui/events:platform_event",
   ]
-
-  if (use_x11) {
-    sources -= [ "platform_event_source_stub.cc" ]
-  }
 }
diff --git a/ui/events/platform/x11/BUILD.gn b/ui/events/platform/x11/BUILD.gn
index 46ccb75..ea79548 100644
--- a/ui/events/platform/x11/BUILD.gn
+++ b/ui/events/platform/x11/BUILD.gn
@@ -6,7 +6,7 @@
 import("//build/config/ozone.gni")
 import("//build/config/ui.gni")
 
-assert(use_x11 || ozone_platform_x11)
+assert(ozone_platform_x11)
 
 component("x11") {
   output_name = "x11_events_platform"
@@ -50,7 +50,6 @@
     ]
     configs += [ "//build/config/linux:glib" ]
   } else {
-    assert(ozone_platform_x11)
     sources += [
       "x11_event_watcher_fdwatch.cc",
       "x11_event_watcher_fdwatch.h",
diff --git a/ui/events/platform/x11/x11_event_source.cc b/ui/events/platform/x11/x11_event_source.cc
index 723a101..a90fe44 100644
--- a/ui/events/platform/x11/x11_event_source.cc
+++ b/ui/events/platform/x11/x11_event_source.cc
@@ -38,10 +38,6 @@
 #include "ui/events/ozone/chromeos/cursor_controller.h"
 #endif
 
-#if defined(USE_OZONE)
-#include "ui/base/ui_base_features.h"
-#endif
-
 namespace ui {
 
 namespace {
@@ -302,15 +298,4 @@
   }
 }
 
-// static
-#if defined(USE_X11)
-std::unique_ptr<PlatformEventSource> PlatformEventSource::CreateDefault() {
-#if defined(USE_OZONE)
-  if (features::IsUsingOzonePlatform())
-    return nullptr;
-#endif
-  return std::make_unique<X11EventSource>(x11::Connection::Get());
-}
-#endif
-
 }  // namespace ui
diff --git a/ui/events/platform_event.h b/ui/events/platform_event.h
index 7c39dc8..a298459 100644
--- a/ui/events/platform_event.h
+++ b/ui/events/platform_event.h
@@ -24,7 +24,7 @@
 namespace ui {
 
 // Cross platform typedefs for native event types.
-#if defined(USE_OZONE) || defined(USE_X11)
+#if defined(USE_OZONE)
 using PlatformEvent = ui::Event*;
 #elif defined(OS_WIN)
 using PlatformEvent = CHROME_MSG;
diff --git a/ui/events/test/event_generator.cc b/ui/events/test/event_generator.cc
index 8803a8d..0f77c94 100644
--- a/ui/events/test/event_generator.cc
+++ b/ui/events/test/event_generator.cc
@@ -24,11 +24,6 @@
 #include "ui/events/test/events_test_utils.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
 
-#if defined(USE_X11)
-#include "ui/events/test/events_test_utils_x11.h"
-#include "ui/events/x/events_x_utils.h"
-#endif
-
 #if defined(OS_WIN)
 #include <windows.h>
 
diff --git a/ui/events/test/keyboard_layout.cc b/ui/events/test/keyboard_layout.cc
index 0fe61f6..09e1442 100644
--- a/ui/events/test/keyboard_layout.cc
+++ b/ui/events/test/keyboard_layout.cc
@@ -8,7 +8,6 @@
 #include "base/notreached.h"
 
 #if defined(USE_OZONE)
-#include "ui/base/ui_base_features.h"  // nogncheck
 #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"  // nogncheck
 #endif
 
@@ -16,13 +15,10 @@
 
 ScopedKeyboardLayout::ScopedKeyboardLayout(KeyboardLayout layout) {
 #if defined(USE_OZONE)
-  if (features::IsUsingOzonePlatform()) {
-    CHECK_EQ(layout, KEYBOARD_LAYOUT_ENGLISH_US);
-    auto keyboard_layout_engine = std::make_unique<StubKeyboardLayoutEngine>();
-    scoped_keyboard_layout_engine_ =
-        std::make_unique<ScopedKeyboardLayoutEngine>(
-            std::move(keyboard_layout_engine));
-  }
+  CHECK_EQ(layout, KEYBOARD_LAYOUT_ENGLISH_US);
+  auto keyboard_layout_engine = std::make_unique<StubKeyboardLayoutEngine>();
+  scoped_keyboard_layout_engine_ = std::make_unique<ScopedKeyboardLayoutEngine>(
+      std::move(keyboard_layout_engine));
 #elif defined(OS_WIN) || defined(OS_MAC)
   original_layout_ = GetActiveLayout();
   ActivateLayout(GetPlatformKeyboardLayout(layout));
diff --git a/ui/events/x/x11_event_translation.cc b/ui/events/x/x11_event_translation.cc
index 2fe1bf34..6f41ebb 100644
--- a/ui/events/x/x11_event_translation.cc
+++ b/ui/events/x/x11_event_translation.cc
@@ -21,10 +21,6 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/x/xproto.h"
 
-#if defined(USE_OZONE)
-#include "ui/base/ui_base_features.h"
-#endif
-
 namespace ui {
 
 namespace {
@@ -172,12 +168,10 @@
       type, EventLocationFromXEvent(xev), EventTimeFromXEvent(xev),
       GetTouchPointerDetailsFromXEvent(xev));
 #if defined(USE_OZONE)
-  if (features::IsUsingOzonePlatform()) {
     // Touch events don't usually have |root_location| set differently than
     // |location|, since there is a touch device to display association, but
     // this doesn't happen in Ozone X11.
     event->set_root_location(EventSystemLocationFromXEvent(xev));
-  }
 #endif
   return event;
 }
diff --git a/ui/file_manager/COMMON_METADATA b/ui/file_manager/COMMON_METADATA
new file mode 100644
index 0000000..5345fc2
--- /dev/null
+++ b/ui/file_manager/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail: {
+  component: "Platform>Apps>FileManager"
+}
diff --git a/ui/file_manager/DIR_METADATA b/ui/file_manager/DIR_METADATA
index 5345fc2..e9400b87 100644
--- a/ui/file_manager/DIR_METADATA
+++ b/ui/file_manager/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Platform>Apps>FileManager"
-}
+mixins: "//ui/file_manager/COMMON_METADATA"
diff --git a/ui/gtk/printing/DIR_METADATA b/ui/gtk/printing/DIR_METADATA
index ee7161a6..2413ed4 100644
--- a/ui/gtk/printing/DIR_METADATA
+++ b/ui/gtk/printing/DIR_METADATA
@@ -1,3 +1 @@
-monorail: {
-  component: "Internals>Printing"
-}
+mixins: "//printing/COMMON_METADATA"
diff --git a/ui/message_center/COMMON_METADATA b/ui/message_center/COMMON_METADATA
new file mode 100644
index 0000000..b3b636b3
--- /dev/null
+++ b/ui/message_center/COMMON_METADATA
@@ -0,0 +1,4 @@
+monorail: {
+  component: "UI>Notifications"
+}
+team_email: "platform-capabilities@chromium.org"
diff --git a/ui/message_center/DIR_METADATA b/ui/message_center/DIR_METADATA
index b3b636b3..fab36ae 100644
--- a/ui/message_center/DIR_METADATA
+++ b/ui/message_center/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Notifications"
-}
-team_email: "platform-capabilities@chromium.org"
+mixins: "//ui/message_center/COMMON_METADATA"
diff --git a/ui/message_center/vector_icons/DIR_METADATA b/ui/message_center/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/ui/message_center/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index bd5d34f..4953e8b 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_pump_type.h"
 #include "base/no_destructor.h"
@@ -19,6 +20,7 @@
 #include "ui/base/dragdrop/os_exchange_data_provider_factory_ozone.h"
 #include "ui/base/ime/linux/input_method_auralinux.h"
 #include "ui/base/ui_base_features.h"
+#include "ui/display/display_switches.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/event.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
@@ -83,6 +85,16 @@
       : old_synthesize_key_repeat_enabled_(
             KeyEvent::IsSynthesizeKeyRepeatEnabled()) {
     CHECK(features::IsUsingOzonePlatform());
+
+    // Forcing the device scale factor on Wayland is not fully/well supported
+    // and is provided for test purposes only.
+    // See https://crbug.com/1241546
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    if (command_line->HasSwitch(switches::kForceDeviceScaleFactor)) {
+      LOG(WARNING) << "--" << switches::kForceDeviceScaleFactor
+                   << " on Wayland is TEST ONLY.  Use it at your own risk.";
+    }
+
     // Disable key-repeat flag synthesizing. On Wayland, key repeat events are
     // generated inside Chrome, and the flag is properly set.
     // See also WaylandEventSource.
diff --git a/ui/views/accessibility/DIR_METADATA b/ui/views/accessibility/DIR_METADATA
index 6849a4f8..173f7e6 100644
--- a/ui/views/accessibility/DIR_METADATA
+++ b/ui/views/accessibility/DIR_METADATA
@@ -1,4 +1,4 @@
+mixins: "//ui/accessibility/COMMON_METADATA"
 monorail: {
   component: "UI>Accessibility"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/ui/views/vector_icons/DIR_METADATA b/ui/views/vector_icons/DIR_METADATA
new file mode 100644
index 0000000..54e77e3
--- /dev/null
+++ b/ui/views/vector_icons/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//components/vector_icons/COMMON_METADATA"
diff --git a/ui/webui/resources/cr_components/chromeos/DIR_METADATA b/ui/webui/resources/cr_components/chromeos/DIR_METADATA
index b39cd583..d682410 100644
--- a/ui/webui/resources/cr_components/chromeos/DIR_METADATA
+++ b/ui/webui/resources/cr_components/chromeos/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "OS>Systems>Settings"
-}
\ No newline at end of file
+mixins: "//chrome/browser/resources/settings/chromeos/COMMON_METADATA"
diff --git a/ui/webui/resources/cr_components/customize_themes/COMMON_METADATA b/ui/webui/resources/cr_components/customize_themes/COMMON_METADATA
new file mode 100644
index 0000000..6b904ae5
--- /dev/null
+++ b/ui/webui/resources/cr_components/customize_themes/COMMON_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "UI>Browser>Themes"
+}
\ No newline at end of file
diff --git a/ui/webui/resources/cr_components/customize_themes/DIR_METADATA b/ui/webui/resources/cr_components/customize_themes/DIR_METADATA
index ae3b64b..718c311 100644
--- a/ui/webui/resources/cr_components/customize_themes/DIR_METADATA
+++ b/ui/webui/resources/cr_components/customize_themes/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "UI>Browser>Themes"
-}
\ No newline at end of file
+mixins: "//ui/webui/resources/cr_components/customize_themes/COMMON_METADATA"
diff --git a/ui/webui/resources/cr_components/omnibox/DIR_METADATA b/ui/webui/resources/cr_components/omnibox/DIR_METADATA
index ac4fcdaf..a342411 100644
--- a/ui/webui/resources/cr_components/omnibox/DIR_METADATA
+++ b/ui/webui/resources/cr_components/omnibox/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "UI>Browser>Omnibox"
-}
\ No newline at end of file
+mixins: "//components/omnibox/COMMON_METADATA"
diff --git a/ui/webui/resources/cr_elements/chromeos/DIR_METADATA b/ui/webui/resources/cr_elements/chromeos/DIR_METADATA
index b39cd583..d682410 100644
--- a/ui/webui/resources/cr_elements/chromeos/DIR_METADATA
+++ b/ui/webui/resources/cr_elements/chromeos/DIR_METADATA
@@ -6,6 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "OS>Systems>Settings"
-}
\ No newline at end of file
+mixins: "//chrome/browser/resources/settings/chromeos/COMMON_METADATA"
diff --git a/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html b/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html
index e3695ae..8dea09e 100644
--- a/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html
+++ b/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html
@@ -24,7 +24,7 @@
     <paper-tooltip id="tooltip"
         for="indicator" position="[[tooltipPosition]]"
         fit-to-visible-bounds part="tooltip">
-      <slot>[[tooltipText]]</slot>
+      <slot name="tooltip-text">[[tooltipText]]</slot>
     </paper-tooltip>
   </template>
   <script src="cr_tooltip_icon.js"></script>
diff --git a/ui/webui/resources/js/ios/DIR_METADATA b/ui/webui/resources/js/ios/DIR_METADATA
index c0019a0..a782e3ed 100644
--- a/ui/webui/resources/js/ios/DIR_METADATA
+++ b/ui/webui/resources/js/ios/DIR_METADATA
@@ -6,5 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-team_email: "ios-directory-owners@chromium.org"
-os: IOS
\ No newline at end of file
+mixins: "//ios/COMMON_METADATA"
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/payments/DIR_METADATA b/weblayer/browser/java/org/chromium/weblayer_private/payments/DIR_METADATA
index 2b4b65c..c933c59 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/payments/DIR_METADATA
+++ b/weblayer/browser/java/org/chromium/weblayer_private/payments/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail: {
-  component: "Blink>Payments"
-}
-team_email: "payments-dev@chromium.org"
+mixins: "//components/payments/COMMON_METADATA"
 os: ANDROID