diff --git a/DEPS b/DEPS
index 0a86db3..273600e 100644
--- a/DEPS
+++ b/DEPS
@@ -181,11 +181,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'edae1b3e044e5755a7b05a9776525fc6a00f0f7b',
+  'skia_revision': '12b2c270383875438a06c0a51140ee3dd0e9bac9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '3d04bd15b02d40f716b49dbb1cb97bb13c40741a',
+  'v8_revision': 'bffadc06da505a4107e53211321f677893ab8a21',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -193,11 +193,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '54d0d539593317eee954eaec1b4aca003032a360',
+  'angle_revision': '683dd1d6a8631e6969918bfca777af7c8f0d74c4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '488d35ac0b1c66c79a6a8511111ad5b6296a2ffb',
+  'swiftshader_revision': '9f1e03b61de8e67e1bce5b0dd25c5a7f54fb1e3e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -244,7 +244,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '25614ff33a6262865cd487ca40ddab809bf9b681',
+  'catapult_revision': '13d8a54a705c1571819c1064380443048a0b79f0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -316,7 +316,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': '1378a942692b9e6ff35b29198e0b18c6269f5b17',
+  'quiche_revision': '1f4fe2d7c33b70394c99e540d00d1e309147e982',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -879,7 +879,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '57766ec208686ea167d4930d7accffa49da6dde5',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '872b953d195526ed6bad0fe37bb67bcead9b8a4d',
       'condition': 'checkout_linux',
   },
 
@@ -1297,7 +1297,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'eac62c294ee1c23bc76059efaf8e16859ed58866',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f2839ae905e755f34be2de89f7c20ffb586c9b67',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc
index 65a5a00..c14ed8c 100644
--- a/android_webview/browser/aw_contents_io_thread_client.cc
+++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -344,7 +344,7 @@
 // Used to specify what kind of url was intercepted by the embedded
 // using shouldIntercepterRequest callback.
 // Note: these values are persisted in UMA logs, so they should never be
-// renumbered nor reused.
+// renumbered or reused.
 enum class InterceptionType {
   kNoIntercept,
   kOther,
diff --git a/android_webview/browser/gfx/browser_view_renderer_unittest.cc b/android_webview/browser/gfx/browser_view_renderer_unittest.cc
index a3242fd..fa79552 100644
--- a/android_webview/browser/gfx/browser_view_renderer_unittest.cc
+++ b/android_webview/browser/gfx/browser_view_renderer_unittest.cc
@@ -679,7 +679,7 @@
     gfx::Vector2dF total_scroll_offset = kTotalScrollOffset;
     gfx::Vector2dF total_max_scroll_offset = kTotalMaxScrollOffset;
     gfx::SizeF scrollable_size = kScrollableSize;
-    // When --use-zoom-for-dsf is enabled, these value are in physical pixel.
+    // When --use-zoom-for-dsf is enabled, these values are in physical pixels.
     if (content::IsUseZoomForDSFEnabled()) {
       total_scroll_offset.Scale(kDipScale);
       total_max_scroll_offset.Scale(kDipScale);
diff --git a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.h b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.h
index 8b85543..a6caa15 100644
--- a/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.h
+++ b/android_webview/browser/safe_browsing/aw_safe_browsing_blocking_page.h
@@ -39,7 +39,7 @@
   // Used to specify which BaseSafeBrowsingErrorUI to instantiate, and
   // parameters they require.
   // Note: these values are persisted in UMA logs, so they should never be
-  // renumbered nor reused.
+  // renumbered or reused.
   // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.android_webview
   enum class ErrorUiType { LOUD, QUIET_SMALL, QUIET_GIANT, COUNT };
 
diff --git a/android_webview/common/BUILD.gn b/android_webview/common/BUILD.gn
index c4f4c5af2..01deaa9 100644
--- a/android_webview/common/BUILD.gn
+++ b/android_webview/common/BUILD.gn
@@ -6,9 +6,7 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("common_mojom") {
-  sources = [
-    "js_java_interaction/interfaces.mojom",
-  ]
+  sources = [ "js_java_interaction/interfaces.mojom" ]
 
   public_deps = [
     "//mojo/public/mojom/base",
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java
index f159b8d..8fe2100 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromium.java
@@ -129,8 +129,8 @@
         sRecordWholeDocumentEnabledByApi = true;
     }
 
-    // Used to record the UMA histogram WebView.WebViewApiCall. Since these value are persisted to
-    // logs, they should never be renumbered nor reused.
+    // Used to record the UMA histogram WebView.WebViewApiCall. Since these values are persisted to
+    // logs, they should never be renumbered or reused.
     @IntDef({ApiCall.ADD_JAVASCRIPT_INTERFACE, ApiCall.AUTOFILL, ApiCall.CAN_GO_BACK,
             ApiCall.CAN_GO_BACK_OR_FORWARD, ApiCall.CAN_GO_FORWARD, ApiCall.CAN_ZOOM_IN,
             ApiCall.CAN_ZOOM_OUT, ApiCall.CAPTURE_PICTURE, ApiCall.CLEAR_CACHE,
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 860c59d..fae9ef9 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -179,7 +179,7 @@
     }
 
     // Used to record the UMA histogram Android.WebView.LoadDataWithBaseUrl.HistoryUrl. Since these
-    // values are persisted to logs, they should never be renumbered nor reused.
+    // values are persisted to logs, they should never be renumbered or reused.
     @IntDef({HistoryUrl.EMPTY, HistoryUrl.BASEURL, HistoryUrl.DIFFERENT, HistoryUrl.COUNT})
     @interface HistoryUrl {
         int EMPTY = 0;
@@ -189,7 +189,7 @@
     }
 
     // Used to record the UMA histogram Android.WebView.LoadDataWithBaseUrl.UrlScheme. Since these
-    // values are persisted to logs, they should never be renumbered nor reused.
+    // values are persisted to logs, they should never be renumbered or reused.
     @VisibleForTesting
     @IntDef({UrlScheme.EMPTY, UrlScheme.UNKNOWN_SCHEME, UrlScheme.HTTP_SCHEME,
             UrlScheme.HTTPS_SCHEME, UrlScheme.FILE_SCHEME, UrlScheme.FTP_SCHEME,
diff --git a/android_webview/java/src/org/chromium/android_webview/safe_browsing/AwSafeBrowsingConfigHelper.java b/android_webview/java/src/org/chromium/android_webview/safe_browsing/AwSafeBrowsingConfigHelper.java
index 87ae3bb..1b9cb320 100644
--- a/android_webview/java/src/org/chromium/android_webview/safe_browsing/AwSafeBrowsingConfigHelper.java
+++ b/android_webview/java/src/org/chromium/android_webview/safe_browsing/AwSafeBrowsingConfigHelper.java
@@ -35,7 +35,7 @@
     private static volatile boolean sEnabledByManifest;
 
     // Used to record the UMA histogram SafeBrowsing.WebView.AppOptIn. Since these values are
-    // persisted to logs, they should never be renumbered nor reused.
+    // persisted to logs, they should never be renumbered or reused.
     @IntDef({AppOptIn.NO_PREFERENCE, AppOptIn.OPT_IN, AppOptIn.OPT_OUT})
     @interface AppOptIn {
         int NO_PREFERENCE = 0;
@@ -46,7 +46,7 @@
     }
 
     // Used to record the UMA histogram SafeBrowsing.WebView.UserOptIn. Since these values are
-    // persisted to logs, they should never be renumbered nor reused.
+    // persisted to logs, they should never be renumbered or reused.
     @IntDef({UserOptIn.UNABLE_TO_DETERMINE, UserOptIn.OPT_IN, UserOptIn.OPT_OUT})
     @interface UserOptIn {
         int OPT_OUT = 0;
diff --git a/android_webview/renderer/BUILD.gn b/android_webview/renderer/BUILD.gn
index 6ceb223..88b25c6 100644
--- a/android_webview/renderer/BUILD.gn
+++ b/android_webview/renderer/BUILD.gn
@@ -40,6 +40,7 @@
     "//android_webview/common",
     "//android_webview/common:common_mojom",
     "//base",
+    "//components/android_system_error_page",
     "//components/autofill/content/renderer",
     "//components/cdm/renderer",
     "//components/content_capture/common",
diff --git a/android_webview/renderer/DEPS b/android_webview/renderer/DEPS
index 4694021..b30bfc3 100644
--- a/android_webview/renderer/DEPS
+++ b/android_webview/renderer/DEPS
@@ -4,6 +4,7 @@
   "+android_webview/renderer",
   "+android_webview/grit",
 
+  "+components/android_system_error_page",
   "+components/autofill/content/renderer",
   "+components/cdm/renderer",
   "+components/page_load_metrics/renderer",
diff --git a/android_webview/renderer/aw_content_renderer_client.cc b/android_webview/renderer/aw_content_renderer_client.cc
index c498145..bc23390 100644
--- a/android_webview/renderer/aw_content_renderer_client.cc
+++ b/android_webview/renderer/aw_content_renderer_client.cc
@@ -25,11 +25,9 @@
 #include "base/i18n/rtl.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/grit/components_resources.h"
+#include "components/android_system_error_page/error_page_populator.h"
 #include "components/page_load_metrics/renderer/metrics_render_frame_observer.h"
 #include "components/printing/renderer/print_render_frame_helper.h"
-#include "components/strings/grit/components_strings.h"
 #include "components/visitedlink/renderer/visitedlink_reader.h"
 #include "content/public/child/child_thread.h"
 #include "content/public/common/url_constants.h"
@@ -38,18 +36,13 @@
 #include "content/public/renderer/render_thread.h"
 #include "content/public/renderer/render_view.h"
 #include "mojo/public/cpp/bindings/binder_map.h"
-#include "net/base/escape.h"
-#include "net/base/net_errors.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/public/platform/web_url_error.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/web/web_frame.h"
 #include "third_party/blink/public/web/web_navigation_type.h"
 #include "third_party/blink/public/web/web_security_policy.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
 
@@ -62,12 +55,6 @@
 
 namespace android_webview {
 
-namespace {
-constexpr char kThrottledErrorDescription[] =
-    "Request throttled. Visit http://dev.chromium.org/throttling for more "
-    "information.";
-}  // namespace
-
 AwContentRendererClient::AwContentRendererClient() = default;
 
 AwContentRendererClient::~AwContentRendererClient() = default;
@@ -217,45 +204,7 @@
   AwSafeBrowsingErrorPageControllerDelegateImpl::Get(render_frame)
       ->PrepareForErrorPage();
 
-  std::string err;
-  if (error.reason() == net::ERR_TEMPORARILY_THROTTLED)
-    err = kThrottledErrorDescription;
-  else
-    err = net::ErrorToString(error.reason());
-
-  if (!error_html)
-    return;
-
-  // Create the error page based on the error reason.
-  GURL gurl(error.url());
-  std::string url_string = gurl.possibly_invalid_spec();
-  int reason_id = IDS_ANDROID_ERROR_PAGE_WEBPAGE_CAN_NOT_BE_LOADED;
-
-  if (err.empty())
-    reason_id = IDS_ANDROID_ERROR_PAGE_WEBPAGE_TEMPORARILY_DOWN;
-
-  std::string escaped_url = net::EscapeForHTML(url_string);
-  std::vector<std::string> replacements;
-  replacements.push_back(
-      l10n_util::GetStringUTF8(IDS_ANDROID_ERROR_PAGE_WEBPAGE_NOT_AVAILABLE));
-  replacements.push_back(
-      l10n_util::GetStringFUTF8(reason_id, base::UTF8ToUTF16(escaped_url)));
-
-  // Having chosen the base reason, chose what extra information to add.
-  if (reason_id == IDS_ANDROID_ERROR_PAGE_WEBPAGE_TEMPORARILY_DOWN) {
-    replacements.push_back(l10n_util::GetStringUTF8(
-        IDS_ANDROID_ERROR_PAGE_WEBPAGE_TEMPORARILY_DOWN_SUGGESTIONS));
-  } else {
-    replacements.push_back(err);
-  }
-  if (base::i18n::IsRTL())
-    replacements.push_back("direction: rtl;");
-  else
-    replacements.push_back("");
-  *error_html = base::ReplaceStringPlaceholders(
-      ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
-          IDR_ANDROID_ERROR_PAGE_LOAD_ERROR_HTML),
-      replacements, nullptr);
+  android_system_error_page::PopulateErrorPageHtml(error, error_html);
 }
 
 uint64_t AwContentRendererClient::VisitedLinkHash(const char* canonical_url,
diff --git a/android_webview/support_library/boundary_interfaces/BUILD.gn b/android_webview/support_library/boundary_interfaces/BUILD.gn
index 0180db39..e3ed180 100644
--- a/android_webview/support_library/boundary_interfaces/BUILD.gn
+++ b/android_webview/support_library/boundary_interfaces/BUILD.gn
@@ -41,9 +41,7 @@
   # build when we mirror this into AndroidX. We are only permitted to depend on
   # core Android classes and other AndroidX classes (must be in the androidx.*
   # package name).
-  deps = [
-    "//third_party/android_deps:androidx_annotation_annotation_java",
-  ]
+  deps = [ "//third_party/android_deps:androidx_annotation_annotation_java" ]
 
   # This is to verify the boundary interfaces compile and lint correctly against
   # the minSdkVersion of the webkit support library module. As the minSdkVersion
diff --git a/android_webview/test/embedded_test_server/BUILD.gn b/android_webview/test/embedded_test_server/BUILD.gn
index fa8c6b4..e9807d7 100644
--- a/android_webview/test/embedded_test_server/BUILD.gn
+++ b/android_webview/test/embedded_test_server/BUILD.gn
@@ -37,9 +37,7 @@
     "aw_embedded_test_server.cc",
     "aw_test_entry_point.cc",
   ]
-  deps = [
-    "//net:test_support",
-  ]
+  deps = [ "//net:test_support" ]
   public_deps = [
     ":aw_net_jni_headers",
     "//net:net_test_jni_headers",
diff --git a/android_webview/tools/system_webview_shell/BUILD.gn b/android_webview/tools/system_webview_shell/BUILD.gn
index dc7d6d13..183b87a 100644
--- a/android_webview/tools/system_webview_shell/BUILD.gn
+++ b/android_webview/tools/system_webview_shell/BUILD.gn
@@ -47,18 +47,14 @@
 android_resources("system_webview_shell_apk_resources") {
   resource_dirs = [ "apk/res" ]
   custom_package = "org.chromium.webview_shell"
-  deps = [
-    "//third_party/android_deps:android_support_v7_appcompat_java",
-  ]
+  deps = [ "//third_party/android_deps:android_support_v7_appcompat_java" ]
 }
 
 instrumentation_test_apk("system_webview_shell_page_cycler_apk") {
   apk_name = "SystemWebViewShellPageCycler"
   apk_under_test = ":system_webview_shell_apk"
   android_manifest = "page_cycler/AndroidManifest.xml"
-  sources = [
-    "page_cycler/src/org/chromium/webview_shell/page_cycler/PageCyclerTest.java",
-  ]
+  sources = [ "page_cycler/src/org/chromium/webview_shell/page_cycler/PageCyclerTest.java" ]
   deps = [
     "//base:base_java",
     "//base:base_java_test_support",
diff --git a/android_webview/tools/webview_log_verbosifier/BUILD.gn b/android_webview/tools/webview_log_verbosifier/BUILD.gn
index aca6466..a6d9dfd 100644
--- a/android_webview/tools/webview_log_verbosifier/BUILD.gn
+++ b/android_webview/tools/webview_log_verbosifier/BUILD.gn
@@ -7,9 +7,7 @@
 android_apk("webview_log_verbosifier_apk") {
   apk_name = "WebViewLogVerbosifier"
   android_manifest = "AndroidManifest.xml"
-  deps = [
-    ":webview_log_verbosifier_resources",
-  ]
+  deps = [ ":webview_log_verbosifier_resources" ]
   min_sdk_version = 21
   target_sdk_version = 28
 }
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index 6a5b38e..1b0c73f 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -33,6 +33,7 @@
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/multi_profile_uma.h"
 #include "ash/public/cpp/ash_features.h"
+#include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/new_window_delegate.h"
 #include "ash/public/cpp/notification_utils.h"
@@ -1150,37 +1151,61 @@
                                                            false /* by_user */);
 }
 
-void SetDockedMagnifierEnabled(bool enabled) {
-  Shell::Get()->docked_magnifier_controller()->SetEnabled(enabled);
+// Return false if the accessibility shortcuts have been disabled, or if
+// the accessibility feature itself associated with |accessibility_pref_name|
+// is being enforced by the administrator.
+bool IsAccessibilityShortcutEnabled(
+    const std::string& accessibility_pref_name) {
+  Shell* shell = Shell::Get();
+  return shell->accessibility_controller()->accessibility_shortcuts_enabled() &&
+         !shell->session_controller()
+              ->GetActivePrefService()
+              ->IsManagedPreference(accessibility_pref_name);
+}
 
-  // We need to show the notification only if the state actually changed.
-  const bool actual_enabled =
-      Shell::Get()->docked_magnifier_controller()->GetEnabled();
+void SetDockedMagnifierEnabled(bool enabled) {
+  Shell* shell = Shell::Get();
+  // Check that the attempt to change the value of the accessibility feature
+  // will be done only when the accessibility shortcuts are enabled, and
+  // the feature isn't being enforced by the administrator.
+  DCHECK(IsAccessibilityShortcutEnabled(prefs::kDockedMagnifierEnabled));
+
+  shell->docked_magnifier_controller()->SetEnabled(enabled);
+
   RemoveStickyNotitification(kDockedMagnifierToggleAccelNotificationId);
-  if (enabled && actual_enabled) {
+  if (shell->docked_magnifier_controller()->GetEnabled()) {
     CreateAndShowStickyNotification(IDS_DOCKED_MAGNIFIER_ACCEL_TITLE,
                                     IDS_DOCKED_MAGNIFIER_ACCEL_MSG,
                                     kDockedMagnifierToggleAccelNotificationId);
-  } else if (enabled != actual_enabled) {
-    NotifyAccessibilityFeatureDisabledByAdmin(
-        IDS_ASH_DOCKED_MAGNIFIER_SHORTCUT_DISABLED, actual_enabled,
-        kDockedMagnifierToggleAccelNotificationId);
   }
 }
 
 void HandleToggleDockedMagnifier() {
   base::RecordAction(UserMetricsAction("Accel_Toggle_Docked_Magnifier"));
 
+  Shell* shell = Shell::Get();
+
+  RemoveStickyNotitification(kDockedMagnifierToggleAccelNotificationId);
+  if (!IsAccessibilityShortcutEnabled(prefs::kDockedMagnifierEnabled)) {
+    NotifyAccessibilityFeatureDisabledByAdmin(
+        IDS_ASH_DOCKED_MAGNIFIER_SHORTCUT_DISABLED,
+        shell->docked_magnifier_controller()->GetEnabled(),
+        kDockedMagnifierToggleAccelNotificationId);
+    return;
+  }
+
   DockedMagnifierControllerImpl* docked_magnifier_controller =
-      Shell::Get()->docked_magnifier_controller();
+      shell->docked_magnifier_controller();
+  AccessibilityControllerImpl* accessibility_controller =
+      shell->accessibility_controller();
+
   const bool current_enabled = docked_magnifier_controller->GetEnabled();
   const bool dialog_ever_accepted =
-      Shell::Get()
-          ->accessibility_controller()
+      accessibility_controller
           ->HasDockedMagnifierAcceleratorDialogBeenAccepted();
 
   if (!current_enabled && !dialog_ever_accepted) {
-    Shell::Get()->accelerator_controller()->MaybeShowConfirmationDialog(
+    shell->accelerator_controller()->MaybeShowConfirmationDialog(
         IDS_ASH_DOCKED_MAGNIFIER_TITLE, IDS_ASH_DOCKED_MAGNIFIER_BODY,
         base::BindOnce([]() {
           Shell::Get()
@@ -1199,54 +1224,63 @@
   // Necessary to make magnification controller in ash observe changes to the
   // prefs iteself.
   Shell* shell = Shell::Get();
+  // Check that the attempt to change the value of the accessibility feature
+  // will be done only when the accessibility shortcuts are enabled, and
+  // the feature isn't being enforced by the administrator.
+  DCHECK(IsAccessibilityShortcutEnabled(
+      prefs::kAccessibilityScreenMagnifierEnabled));
+
   shell->accessibility_controller()->SetFullscreenMagnifierEnabled(enabled);
 
-  // We need to show the notification only if the state actually changed.
-  const bool actual_enabled =
-      Shell::Get()->magnification_controller()->IsEnabled();
   RemoveStickyNotitification(kFullscreenMagnifierToggleAccelNotificationId);
-  if (enabled && actual_enabled) {
+  if (shell->magnification_controller()->IsEnabled()) {
     CreateAndShowStickyNotification(
         IDS_FULLSCREEN_MAGNIFIER_ACCEL_TITLE,
         IDS_FULLSCREEN_MAGNIFIER_ACCEL_MSG,
         kFullscreenMagnifierToggleAccelNotificationId);
-  } else if (enabled != actual_enabled) {
-    NotifyAccessibilityFeatureDisabledByAdmin(
-        IDS_ASH_FULLSCREEN_MAGNIFIER_SHORTCUT_DISABLED, actual_enabled,
-        kFullscreenMagnifierToggleAccelNotificationId);
   }
 }
 
 void SetHighContrastEnabled(bool enabled) {
-  AccessibilityControllerImpl* accessibility_controller =
-      Shell::Get()->accessibility_controller();
-  accessibility_controller->SetHighContrastEnabled(enabled);
-  // Value could differ from one that were set because of higher-priority pref
-  // source, eg. policy. See crbug.com/953245.
-  const bool actual_enabled = accessibility_controller->high_contrast_enabled();
+  Shell* shell = Shell::Get();
+  // Check that the attempt to change the value of the accessibility feature
+  // will be done only when the accessibility shortcuts are enabled, and
+  // the feature isn't being enforced by the administrator.
+  DCHECK(
+      IsAccessibilityShortcutEnabled(prefs::kAccessibilityHighContrastEnabled));
+
+  shell->accessibility_controller()->SetHighContrastEnabled(enabled);
+
   RemoveStickyNotitification(kHighContrastToggleAccelNotificationId);
-  if (enabled && actual_enabled) {
+  if (shell->accessibility_controller()->high_contrast_enabled()) {
     CreateAndShowStickyNotification(IDS_HIGH_CONTRAST_ACCEL_TITLE,
                                     IDS_HIGH_CONTRAST_ACCEL_MSG,
                                     kHighContrastToggleAccelNotificationId);
-  } else if (enabled != actual_enabled) {
-    NotifyAccessibilityFeatureDisabledByAdmin(
-        IDS_ASH_HIGH_CONTRAST_SHORTCUT_DISABLED, actual_enabled,
-        kHighContrastToggleAccelNotificationId);
   }
 }
 
 void HandleToggleHighContrast() {
   base::RecordAction(UserMetricsAction("Accel_Toggle_High_Contrast"));
 
-  AccessibilityControllerImpl* controller =
-      Shell::Get()->accessibility_controller();
+  Shell* shell = Shell::Get();
+
+  RemoveStickyNotitification(kHighContrastToggleAccelNotificationId);
+  if (!IsAccessibilityShortcutEnabled(
+          prefs::kAccessibilityHighContrastEnabled)) {
+    NotifyAccessibilityFeatureDisabledByAdmin(
+        IDS_ASH_HIGH_CONTRAST_SHORTCUT_DISABLED,
+        shell->accessibility_controller()->high_contrast_enabled(),
+        kHighContrastToggleAccelNotificationId);
+    return;
+  }
+
+  AccessibilityControllerImpl* controller = shell->accessibility_controller();
   const bool current_enabled = controller->high_contrast_enabled();
   const bool dialog_ever_accepted =
       controller->HasHighContrastAcceleratorDialogBeenAccepted();
 
   if (!current_enabled && !dialog_ever_accepted) {
-    Shell::Get()->accelerator_controller()->MaybeShowConfirmationDialog(
+    shell->accelerator_controller()->MaybeShowConfirmationDialog(
         IDS_ASH_HIGH_CONTRAST_TITLE, IDS_ASH_HIGH_CONTRAST_BODY,
         base::BindOnce([]() {
           Shell::Get()
@@ -1263,15 +1297,30 @@
 void HandleToggleFullscreenMagnifier() {
   base::RecordAction(UserMetricsAction("Accel_Toggle_Fullscreen_Magnifier"));
 
-  MagnificationController* controller =
-      Shell::Get()->magnification_controller();
-  const bool current_enabled = controller->IsEnabled();
+  Shell* shell = Shell::Get();
+
+  RemoveStickyNotitification(kFullscreenMagnifierToggleAccelNotificationId);
+  if (!IsAccessibilityShortcutEnabled(
+          prefs::kAccessibilityScreenMagnifierEnabled)) {
+    NotifyAccessibilityFeatureDisabledByAdmin(
+        IDS_ASH_FULLSCREEN_MAGNIFIER_SHORTCUT_DISABLED,
+        shell->magnification_controller()->IsEnabled(),
+        kFullscreenMagnifierToggleAccelNotificationId);
+    return;
+  }
+
+  MagnificationController* magnification_controller =
+      shell->magnification_controller();
+  AccessibilityControllerImpl* accessibility_controller =
+      shell->accessibility_controller();
+
+  const bool current_enabled = magnification_controller->IsEnabled();
   const bool dialog_ever_accepted =
-      Shell::Get()
-          ->accessibility_controller()
+      accessibility_controller
           ->HasScreenMagnifierAcceleratorDialogBeenAccepted();
+
   if (!current_enabled && !dialog_ever_accepted) {
-    Shell::Get()->accelerator_controller()->MaybeShowConfirmationDialog(
+    shell->accelerator_controller()->MaybeShowConfirmationDialog(
         IDS_ASH_SCREEN_MAGNIFIER_TITLE, IDS_ASH_SCREEN_MAGNIFIER_BODY,
         base::BindOnce([]() {
           Shell::Get()
@@ -1288,20 +1337,21 @@
 void HandleToggleSpokenFeedback() {
   base::RecordAction(UserMetricsAction("Accel_Toggle_Spoken_Feedback"));
 
-  AccessibilityControllerImpl* controller =
-      Shell::Get()->accessibility_controller();
-  bool old_value = controller->spoken_feedback_enabled();
-  controller->SetSpokenFeedbackEnabled(!controller->spoken_feedback_enabled(),
-                                       A11Y_NOTIFICATION_SHOW);
-  // If we tried to enable it and didn't succeed — show disabled by policy
-  // toast.
+  Shell* shell = Shell::Get();
+  const bool old_value =
+      shell->accessibility_controller()->spoken_feedback_enabled();
+
   RemoveStickyNotitification(kSpokenFeedbackToggleAccelNotificationId);
-  if (!controller->spoken_feedback_enabled() && !old_value) {
+  if (!IsAccessibilityShortcutEnabled(
+          prefs::kAccessibilitySpokenFeedbackEnabled)) {
     NotifyAccessibilityFeatureDisabledByAdmin(
-        IDS_ASH_SPOKEN_FEEDBACK_SHORTCUT_DISABLED,
-        controller->spoken_feedback_enabled(),
+        IDS_ASH_SPOKEN_FEEDBACK_SHORTCUT_DISABLED, old_value,
         kSpokenFeedbackToggleAccelNotificationId);
+    return;
   }
+
+  shell->accessibility_controller()->SetSpokenFeedbackEnabled(
+      !old_value, A11Y_NOTIFICATION_SHOW);
 }
 
 // Percent by which the volume should be changed when a volume key is pressed.
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 41e5883..65a61a5 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -2108,6 +2108,108 @@
   RemoveAllNotifications();
 }
 
+class AccessibilityAcceleratorTester : public MagnifiersAcceleratorsTester {
+ public:
+  AccessibilityAcceleratorTester() = default;
+  ~AccessibilityAcceleratorTester() override = default;
+
+  AccessibilityAcceleratorTester(const AccessibilityAcceleratorTester&) =
+      delete;
+  AccessibilityAcceleratorTester& operator=(
+      const AccessibilityAcceleratorTester&) = delete;
+
+  bool ContainsAccessibilityNotification(
+      const std::string& notification_id) const {
+    return nullptr !=
+           message_center()->FindVisibleNotificationById(notification_id);
+  }
+
+  void TestAccessibilityAcceleratorControlledByPref(
+      const std::string& pref_name,
+      const char* notification_id,
+      const ui::Accelerator& accelerator) {
+    // Verify that the initial state for the accessibility feature will be
+    // disabled, and for accessibility accelerators controller pref
+    // |kAccessibilityShortcutsEnabled| is enabled. And neither of that
+    // accessibility feature notification id, nor its confirmation dialog have
+    // appeared.
+    EXPECT_FALSE(user_pref_service()->GetBoolean(pref_name));
+    EXPECT_TRUE(
+        user_pref_service()->GetBoolean(prefs::kAccessibilityShortcutsEnabled));
+    EXPECT_FALSE(IsConfirmationDialogOpen());
+    if (notification_id)
+      EXPECT_FALSE(ContainsAccessibilityNotification(notification_id));
+
+    // Verify that after disabling the accessibility accelerators, the
+    // confirmation dialog won't appear for that accessibility feature. And its
+    // corresponding pref won't be enabled. But a notification should appear,
+    // which shows that the shortcut for that feature has been disabled.
+    user_pref_service()->SetBoolean(prefs::kAccessibilityShortcutsEnabled,
+                                    false);
+    EXPECT_TRUE(ProcessInController(accelerator));
+    EXPECT_FALSE(IsConfirmationDialogOpen());
+    if (notification_id)
+      EXPECT_TRUE(ContainsAccessibilityNotification(notification_id));
+    EXPECT_FALSE(user_pref_service()->GetBoolean(pref_name));
+
+    // Verify that if the accessibility accelerators are enabled, then
+    // it will show the confirmation dialog for the first time only when
+    // toggling its value. And the coressponding pref will be chanaged
+    // accordingly.
+    user_pref_service()->SetBoolean(prefs::kAccessibilityShortcutsEnabled,
+                                    true);
+    EXPECT_TRUE(ProcessInController(accelerator));
+    if (notification_id)
+      AcceptConfirmationDialog();
+    base::RunLoop().RunUntilIdle();
+    message_center::NotificationList::Notifications notifications =
+        message_center()->GetVisibleNotifications();
+    ASSERT_EQ(1u, notifications.size());
+    EXPECT_TRUE(user_pref_service()->GetBoolean(pref_name));
+    if (notification_id)
+      EXPECT_TRUE(ContainsAccessibilityNotification(notification_id));
+
+    // Verify that the notification id, won't be shown if the accessibility
+    // feature is going to be disabled.
+    EXPECT_TRUE(ProcessInController(accelerator));
+    if (notification_id)
+      EXPECT_FALSE(ContainsAccessibilityNotification(notification_id));
+    EXPECT_FALSE(user_pref_service()->GetBoolean(pref_name));
+
+    // Remove all the current notifications, to get the initial state again.
+    RemoveAllNotifications();
+  }
+};
+
+TEST_F(AccessibilityAcceleratorTester, DisableAccessibilityAccelerators) {
+  struct PrefToAcceleratorEntry {
+    const char* pref_name;
+    // If |notification_id| has been set to nullptr, then no notification is
+    // expected.
+    const char* notification_id;
+    const ui::Accelerator accelerator;
+  };
+  const PrefToAcceleratorEntry kAccessibilityAcceleratorMap[] = {
+      {prefs::kAccessibilityHighContrastEnabled,
+       kHighContrastToggleAccelNotificationId,
+       ui::Accelerator(ui::VKEY_H, ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN)},
+      {prefs::kDockedMagnifierEnabled,
+       kDockedMagnifierToggleAccelNotificationId,
+       ui::Accelerator(ui::VKEY_D, ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN)},
+      {prefs::kAccessibilitySpokenFeedbackEnabled, nullptr,
+       ui::Accelerator(ui::VKEY_Z, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)},
+      {prefs::kAccessibilityScreenMagnifierEnabled,
+       kFullscreenMagnifierToggleAccelNotificationId,
+       ui::Accelerator(ui::VKEY_M, ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN)},
+  };
+  FakeMagnificationManager manager;
+  manager.SetPrefs(user_pref_service());
+  for (const auto& test_data : kAccessibilityAcceleratorMap) {
+    TestAccessibilityAcceleratorControlledByPref(
+        test_data.pref_name, test_data.notification_id, test_data.accelerator);
+  }
+}
+
 namespace {
 
 struct MediaSessionAcceleratorTestConfig {
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index 695a5d7..ff9e097 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -88,6 +88,7 @@
     prefs::kAccessibilitySelectToSpeakEnabled,
     prefs::kAccessibilitySpokenFeedbackEnabled,
     prefs::kAccessibilityStickyKeysEnabled,
+    prefs::kAccessibilityShortcutsEnabled,
     prefs::kAccessibilitySwitchAccessEnabled,
     prefs::kAccessibilityVirtualKeyboardEnabled,
     prefs::kDockedMagnifierEnabled,
@@ -369,6 +370,9 @@
       prefs::kAccessibilityStickyKeysEnabled, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   registry->RegisterBooleanPref(
+      prefs::kAccessibilityShortcutsEnabled, true,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
+  registry->RegisterBooleanPref(
       prefs::kAccessibilitySwitchAccessEnabled, false,
       user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
   registry->RegisterListPref(
@@ -1175,6 +1179,11 @@
           &AccessibilityControllerImpl::UpdateSelectToSpeakFromPref,
           base::Unretained(this)));
   pref_change_registrar_->Add(
+      prefs::kAccessibilityShortcutsEnabled,
+      base::BindRepeating(
+          &AccessibilityControllerImpl::UpdateShortcutsEnabledFromPref,
+          base::Unretained(this)));
+  pref_change_registrar_->Add(
       prefs::kAccessibilityStickyKeysEnabled,
       base::BindRepeating(
           &AccessibilityControllerImpl::UpdateStickyKeysFromPref,
@@ -1240,6 +1249,7 @@
   UpdateStickyKeysFromPref();
   UpdateSwitchAccessFromPref();
   UpdateVirtualKeyboardFromPref();
+  UpdateShortcutsEnabledFromPref();
 }
 
 void AccessibilityControllerImpl::UpdateAutoclickFromPref() {
@@ -1654,6 +1664,19 @@
   UpdateSwitchAccessKeyCodesFromPref(SwitchAccessCommand::kPrevious);
 }
 
+void AccessibilityControllerImpl::UpdateShortcutsEnabledFromPref() {
+  DCHECK(active_user_prefs_);
+  const bool enabled =
+      active_user_prefs_->GetBoolean(prefs::kAccessibilityShortcutsEnabled);
+
+  if (shortcuts_enabled_ == enabled)
+    return;
+
+  shortcuts_enabled_ = enabled;
+
+  NotifyAccessibilityStatusChanged();
+}
+
 void AccessibilityControllerImpl::UpdateVirtualKeyboardFromPref() {
   DCHECK(active_user_prefs_);
   const bool enabled = active_user_prefs_->GetBoolean(
diff --git a/ash/accessibility/accessibility_controller_impl.h b/ash/accessibility/accessibility_controller_impl.h
index d46403a..9fb8630 100644
--- a/ash/accessibility/accessibility_controller_impl.h
+++ b/ash/accessibility/accessibility_controller_impl.h
@@ -167,6 +167,9 @@
 
   bool dictation_active() const { return dictation_active_; }
 
+  // Returns true if accessibility shortcuts have been disabled.
+  bool accessibility_shortcuts_enabled() const { return shortcuts_enabled_; }
+
   // Triggers an accessibility alert to give the user feedback.
   void TriggerAccessibilityAlert(AccessibilityAlert alert);
 
@@ -292,6 +295,7 @@
   void UpdateSwitchAccessAutoScanKeyboardSpeedFromPref();
   void UpdateVirtualKeyboardFromPref();
   void UpdateAccessibilityHighlightingFromPrefs();
+  void UpdateShortcutsEnabledFromPref();
 
   void MaybeCreateSelectToSpeakEventHandler();
   void MaybeCreateSwitchAccessEventHandler();
@@ -321,6 +325,7 @@
   bool switch_access_enabled_ = false;
   bool virtual_keyboard_enabled_ = false;
   bool dictation_active_ = false;
+  bool shortcuts_enabled_ = true;
 
   SelectToSpeakState select_to_speak_state_ =
       SelectToSpeakState::kSelectToSpeakStateInactive;
diff --git a/ash/accessibility/accessibility_controller_unittest.cc b/ash/accessibility/accessibility_controller_unittest.cc
index fcab59d..7dd0e4a 100644
--- a/ash/accessibility/accessibility_controller_unittest.cc
+++ b/ash/accessibility/accessibility_controller_unittest.cc
@@ -68,6 +68,7 @@
   EXPECT_TRUE(
       prefs->FindPreference(prefs::kAccessibilitySpokenFeedbackEnabled));
   EXPECT_TRUE(prefs->FindPreference(prefs::kAccessibilityStickyKeysEnabled));
+  EXPECT_TRUE(prefs->FindPreference(prefs::kAccessibilityShortcutsEnabled));
   EXPECT_TRUE(
       prefs->FindPreference(prefs::kAccessibilityVirtualKeyboardEnabled));
 }
diff --git a/ash/home_screen/drag_window_from_shelf_controller_unittest.cc b/ash/home_screen/drag_window_from_shelf_controller_unittest.cc
index fe7531f..a7b3989 100644
--- a/ash/home_screen/drag_window_from_shelf_controller_unittest.cc
+++ b/ash/home_screen/drag_window_from_shelf_controller_unittest.cc
@@ -182,8 +182,8 @@
   EXPECT_FALSE(window2->IsVisible());
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
-  DragWindowFromShelfControllerTestApi test_api;
-  test_api.WaitUntilOverviewIsShown(window_drag_controller());
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   EndDrag(gfx::Point(200, 200), base::nullopt);
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_TRUE(overview_controller->overview_session()->IsWindowInOverview(
@@ -219,8 +219,8 @@
   StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   // Drag it far enough so overview should be open behind the dragged window.
   Drag(gfx::Point(200, 200), 0.f, 1.f);
-  DragWindowFromShelfControllerTestApi test_api;
-  test_api.WaitUntilOverviewIsShown(window_drag_controller());
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_TRUE(window1->IsVisible());
@@ -286,8 +286,8 @@
   Drag(gfx::Point(200, 200), 0.f, 1.f);
   EXPECT_FALSE(window->layer()->GetTargetTransform().IsIdentity());
   EXPECT_TRUE(overview_controller->InOverviewSession());
-  DragWindowFromShelfControllerTestApi test_api;
-  test_api.WaitUntilOverviewIsShown(window_drag_controller());
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   EndDrag(
       gfx::Point(
           200,
@@ -316,8 +316,7 @@
 
 // Test if overview is active and splitview is not active, fling in overview may
 // or may not head to the home screen.
-// TODO(https://crbug.com/1019080) This test is flaky.
-TEST_F(DragWindowFromShelfControllerTest, DISABLED_FlingInOverview) {
+TEST_F(DragWindowFromShelfControllerTest, FlingInOverview) {
   UpdateDisplay("400x400");
   const gfx::Rect shelf_bounds =
       Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
@@ -327,6 +326,8 @@
   // where the window should go based on the release position.
   StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f, 1.f);
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EndDrag(
@@ -456,8 +457,8 @@
 
   StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.5f, 0.5f);
-  DragWindowFromShelfControllerTestApi test_api;
-  test_api.WaitUntilOverviewIsShown(window_drag_controller());
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
   // We test the visibility of overview by testing the drop target widget's
@@ -476,8 +477,8 @@
   EXPECT_EQ(drop_target_item->GetWindow()->layer()->GetTargetOpacity(), 0.f);
 
   Drag(gfx::Point(200, 200), 0.5f, 0.5f);
-  DragWindowFromShelfControllerTestApi test_api2;
-  test_api2.WaitUntilOverviewIsShown(window_drag_controller());
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   EndDrag(gfx::Point(200, 200),
           /*velocity_y=*/base::nullopt);
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -488,9 +489,8 @@
 }
 
 // Check the split view drag indicators window dragging states.
-// Flaky on ChromeOS. https://crbug.com/1022320
 TEST_F(DragWindowFromShelfControllerTest,
-       DISABLED_SplitViewDragIndicatorsWindowDraggingStates) {
+       SplitViewDragIndicatorsWindowDraggingStates) {
   UpdateDisplay("400x400");
   const gfx::Rect shelf_bounds =
       Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
@@ -498,6 +498,8 @@
 
   StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.5f, 0.5f);
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
   OverviewSession* overview_session = overview_controller->overview_session();
@@ -550,8 +552,7 @@
 
 // Test that if drag is cancelled, overview should be dismissed and other
 // hidden windows should restore to its previous visibility state.
-// TODO(crbug.com/1022319): flaky.
-TEST_F(DragWindowFromShelfControllerTest, DISABLED_CancelDragDismissOverview) {
+TEST_F(DragWindowFromShelfControllerTest, CancelDragDismissOverview) {
   const gfx::Rect shelf_bounds =
       Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window3 = CreateTestWindow();
@@ -563,6 +564,8 @@
 
   StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.5f, 0.5f);
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_TRUE(window1->IsVisible());
@@ -576,14 +579,14 @@
   EXPECT_TRUE(window3->IsVisible());
 }
 
-// TODO(https://crbug.com/1018498) This test is flaky.
-TEST_F(DragWindowFromShelfControllerTest,
-       DISABLED_CancelDragIfWindowDestroyed) {
+TEST_F(DragWindowFromShelfControllerTest, CancelDragIfWindowDestroyed) {
   const gfx::Rect shelf_bounds =
       Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window = CreateTestWindow();
   StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.5f, 0.5f);
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   EXPECT_EQ(window_drag_controller()->dragged_window(), window.get());
   EXPECT_TRUE(window_drag_controller()->drag_started());
   window.reset();
@@ -698,8 +701,8 @@
 
   StartDrag(window.get(), shelf_bounds.left_center(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f, 10.f);
-  DragWindowFromShelfControllerTestApi test_api;
-  test_api.WaitUntilOverviewIsShown(window_drag_controller());
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   // End drag without any fling, the window should be added to overview.
   EndDrag(gfx::Point(200, 200), base::nullopt);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
@@ -732,8 +735,8 @@
   EXPECT_EQ(window->GetProperty(kBackdropWindowMode),
             BackdropWindowMode::kDisabled);
   Drag(gfx::Point(200, 200), 0.f, 1.f);
-  DragWindowFromShelfControllerTestApi test_api;
-  test_api.WaitUntilOverviewIsShown(window_drag_controller());
+  DragWindowFromShelfControllerTestApi().WaitUntilOverviewIsShown(
+      window_drag_controller());
   EndDrag(gfx::Point(200, 200), base::nullopt);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index d90ba15c..5dd8de3 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -85,7 +85,7 @@
 // Date time format containing only the day of the week, for example: "Tuesday".
 constexpr char kDayOfWeekOnlyTimeFormat[] = "EEEE";
 
-constexpr int kFingerprintIconSizeDp = 32;
+constexpr int kFingerprintIconSizeDp = 28;
 constexpr int kResetToDefaultIconDelayMs = 1300;
 constexpr int kFingerprintIconTopSpacingDp = 20;
 constexpr int kSpacingBetweenFingerprintIconAndLabelDp = 15;
@@ -466,7 +466,7 @@
     if (success) {
       icon_->SetImage(gfx::CreateVectorIcon(kLockScreenFingerprintSuccessIcon,
                                             kFingerprintIconSizeDp,
-                                            gfx::kGoogleGreenDark500));
+                                            gfx::kGoogleGreen300));
     } else {
       SetIcon(FingerprintState::DISABLED_FROM_ATTEMPTS);
       // base::Unretained is safe because reset_state_ is owned by |this|.
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index 2bf1b22..afb2b71dd 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -45,6 +45,9 @@
 const char kAccessibilityMonoAudioEnabled[] = "settings.a11y.mono_audio";
 // A boolean pref which determines whether autoclick is enabled.
 const char kAccessibilityAutoclickEnabled[] = "settings.a11y.autoclick";
+// A boolean pref which determines whether the accessibility shortcuts are
+// enabled or not.
+const char kAccessibilityShortcutsEnabled[] = "settings.a11y.shortcuts_enabled";
 // An integer pref which determines time in ms between when the mouse cursor
 // stops and when an autoclick event is triggered.
 const char kAccessibilityAutoclickDelayMs[] =
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index cf69b42..994d927 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -22,6 +22,7 @@
 ASH_PUBLIC_EXPORT extern const char kAccessibilityVirtualKeyboardEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityMonoAudioEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityAutoclickEnabled[];
+ASH_PUBLIC_EXPORT extern const char kAccessibilityShortcutsEnabled[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityAutoclickDelayMs[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityAutoclickEventType[];
 ASH_PUBLIC_EXPORT extern const char kAccessibilityAutoclickRevertToLeftClick[];
diff --git a/ash/public/cpp/shelf_model.cc b/ash/public/cpp/shelf_model.cc
index 9d7daad..8054144 100644
--- a/ash/public/cpp/shelf_model.cc
+++ b/ash/public/cpp/shelf_model.cc
@@ -144,15 +144,28 @@
   return item;
 }
 
-bool ShelfModel::Swap(int index, bool with_next) {
+bool ShelfModel::CanSwap(int index, bool with_next) const {
   const int target_index = with_next ? index + 1 : index - 1;
 
+  // Out of bounds issues, or trying to swap the first item with the previous
+  // one, or the last item with the next one.
   if (index < 0 || target_index >= item_count() || target_index < 0)
     return false;
 
-  // Only allow swapping two pinned apps or two unpinned apps.
-  if (!SamePinState(items()[index].type, items()[target_index].type))
+  const ShelfItem source_item = items()[index];
+  const ShelfItem target_item = items()[target_index];
+  // Trying to swap two items of different pin states.
+  if (!SamePinState(source_item.type, target_item.type))
     return false;
+
+  return true;
+}
+
+bool ShelfModel::Swap(int index, bool with_next) {
+  if (!CanSwap(index, with_next))
+    return false;
+
+  const int target_index = with_next ? index + 1 : index - 1;
   Move(index, target_index);
   return true;
 }
diff --git a/ash/public/cpp/shelf_model.h b/ash/public/cpp/shelf_model.h
index a7201db..6111671 100644
--- a/ash/public/cpp/shelf_model.h
+++ b/ash/public/cpp/shelf_model.h
@@ -84,6 +84,13 @@
   std::unique_ptr<ShelfItemDelegate> RemoveItemAndTakeShelfItemDelegate(
       const ShelfID& shelf_id);
 
+  // Returns whether the item with the given index can be swapped with the
+  // next (or previous) item. Example cases when a swap cannot happen are:
+  // trying to swap the first item with the previous one, trying to swap
+  // the last item with the next one, trying to swap a pinned item with an
+  // unpinned item.
+  bool CanSwap(int index, bool with_next) const;
+
   // Swaps the item at the given index with the next one if |with_next| is
   // true, or with the previous one if |with_next| is false. Returns true
   // if the requested swap has happened, and false otherwise.
diff --git a/ash/resources/vector_icons/lock_screen_caps_lock.icon b/ash/resources/vector_icons/lock_screen_caps_lock.icon
index 01342b0..895db6d 100644
--- a/ash/resources/vector_icons/lock_screen_caps_lock.icon
+++ b/ash/resources/vector_icons/lock_screen_caps_lock.icon
@@ -2,56 +2,31 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 40,
-MOVE_TO, 9, 5,
-LINE_TO, 31, 5,
-CUBIC_TO, 33.21f, 5, 35, 6.79f, 35, 9,
-LINE_TO, 35, 31,
-CUBIC_TO, 35, 33.21f, 33.21f, 35, 31, 35,
-LINE_TO, 9, 35,
-CUBIC_TO, 6.79f, 35, 5, 33.21f, 5, 31,
-LINE_TO, 5, 9,
-LINE_TO, 5, 9,
-CUBIC_TO, 5, 6.79f, 6.79f, 5, 9, 5,
-LINE_TO, 9, 5,
-CLOSE,
-MOVE_TO, 20, 14.95f,
-LINE_TO, 27.65f, 23,
-LINE_TO, 30, 20.53f,
-LINE_TO, 20, 10,
-LINE_TO, 10, 20.53f,
-LINE_TO, 12.35f, 23,
-LINE_TO, 20, 14.95f,
-CLOSE,
-MOVE_TO, 10, 30,
-LINE_TO, 30, 30,
-LINE_TO, 30, 27,
-LINE_TO, 10, 27,
-LINE_TO, 10, 30,
-CLOSE
 
 CANVAS_DIMENSIONS, 20,
-MOVE_TO, 2.5f, 4.49f,
-CUBIC_TO, 2.5f, 3.39f, 3.39f, 2.5f, 4.49f, 2.5f,
-LINE_TO, 15.51f, 2.5f,
-CUBIC_TO, 16.61f, 2.5f, 17.5f, 3.39f, 17.5f, 4.49f,
-LINE_TO, 17.5f, 15.51f,
-CUBIC_TO, 17.5f, 16.61f, 16.61f, 17.5f, 15.51f, 17.5f,
-LINE_TO, 4.49f, 17.5f,
-CUBIC_TO, 3.39f, 17.5f, 2.5f, 16.61f, 2.5f, 15.51f,
-LINE_TO, 2.5f, 4.49f,
+MOVE_TO, 16, 2,
+R_CUBIC_TO, 1.1f, 0, 2, 0.9f, 2, 2,
+R_V_LINE_TO, 12,
+R_CUBIC_TO, 0, 1.1f, -0.9f, 2, -2, 2,
+H_LINE_TO, 4,
+R_CUBIC_TO, -1.1f, 0, -2, -0.9f, -2, -2,
+V_LINE_TO, 4,
+R_CUBIC_TO, 0, -1.1f, 0.9f, -2, 2, -2,
 CLOSE,
-MOVE_TO, 10, 7.47f,
-LINE_TO, 13.83f, 11.5f,
-LINE_TO, 15, 10.26f,
-LINE_TO, 10, 5,
-LINE_TO, 5, 10.26f,
-LINE_TO, 6.18f, 11.5f,
-LINE_TO, 10, 7.47f,
+R_MOVE_TO, 0, 2,
+H_LINE_TO, 4,
+R_V_LINE_TO, 12,
+R_H_LINE_TO, 12,
 CLOSE,
-MOVE_TO, 5, 15,
-LINE_TO, 15, 15,
-LINE_TO, 15, 13.5f,
-LINE_TO, 5, 13.5f,
-LINE_TO, 5, 15,
+R_MOVE_TO, -2, 8,
+R_V_LINE_TO, 2,
+H_LINE_TO, 6,
+R_V_LINE_TO, -2,
+CLOSE,
+R_MOVE_TO, -4, -6.91f,
+R_LINE_TO, 4.21f, 4.21f,
+R_LINE_TO, -1.41f, 1.41f,
+LINE_TO, 10, 7.91f,
+LINE_TO, 7.21f, 10.71f,
+LINE_TO, 5.79f, 9.29f,
 CLOSE
diff --git a/ash/resources/vector_icons/lock_screen_fingerprint_success.icon b/ash/resources/vector_icons/lock_screen_fingerprint_success.icon
index f7e74d8..b1bdaee 100644
--- a/ash/resources/vector_icons/lock_screen_fingerprint_success.icon
+++ b/ash/resources/vector_icons/lock_screen_fingerprint_success.icon
@@ -2,44 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-CANVAS_DIMENSIONS, 56,
-MOVE_TO, 28, 4,
-CUBIC_TO, 14.8f, 4, 4, 14.8f, 4, 28,
-R_CUBIC_TO, 0, 13.2f, 10.8f, 24, 24, 24,
-R_CUBIC_TO, 13.2f, 0, 24, -10.8f, 24, -24,
-CUBIC_TO_SHORTHAND, 41.2f, 4, 28, 4,
-CLOSE,
-R_MOVE_TO, 0, 43.2f,
-CUBIC_TO, 17.4f, 47.2f, 8.8f, 38.6f, 8.8f, 28,
-CUBIC_TO_SHORTHAND, 17.4f, 8.8f, 28, 8.8f,
-CUBIC_TO_SHORTHAND, 47.2f, 17.4f, 47.2f, 28,
-CUBIC_TO_SHORTHAND, 38.6f, 47.2f, 28, 47.2f,
-CLOSE,
-MOVE_TO, 37.4f, 19,
-LINE_TO, 24.6f, 31.6f,
-R_LINE_TO, -5, -5,
-R_LINE_TO, -2.6f, 2.8f,
-R_LINE_TO, 7.6f, 7.6f,
-LINE_TO, 40, 21.6f,
-CLOSE
-
 CANVAS_DIMENSIONS, 28,
-MOVE_TO, 14, 2,
-CUBIC_TO, 7.4f, 2, 2, 7.4f, 2, 14,
-R_CUBIC_TO, 0, 6.6f, 5.4f, 12, 12, 12,
-R_CUBIC_TO, 6.6f, 0, 12, -5.4f, 12, -12,
-CUBIC_TO_SHORTHAND, 20.6f, 2, 14, 2,
+MOVE_TO, 14, 4,
+CUBIC_TO, 8.48f, 4, 4, 8.48f, 4, 14,
+R_CUBIC_TO, 0, 5.52f, 4.48f, 10, 10, 10,
+R_CUBIC_TO, 5.52f, 0, 10, -4.48f, 10, -10,
+CUBIC_TO_SHORTHAND, 19.52f, 4, 14, 4,
 CLOSE,
-R_MOVE_TO, 0, 21.6f,
-R_CUBIC_TO, -5.3f, 0, -9.6f, -4.3f, -9.6f, -9.6f,
-CUBIC_TO_SHORTHAND, 8.7f, 4.4f, 14, 4.4f,
-R_CUBIC_TO, 5.3f, 0, 9.6f, 4.3f, 9.6f, 9.6f,
-R_CUBIC_TO, 0, 5.3f, -4.3f, 9.6f, -9.6f, 9.6f,
+R_MOVE_TO, 0, 18,
+R_CUBIC_TO, -4.41f, 0, -8, -3.59f, -8, -8,
+R_CUBIC_TO, 0, -4.41f, 3.59f, -8, 8, -8,
+R_CUBIC_TO, 4.41f, 0, 8, 3.59f, 8, 8,
+R_CUBIC_TO, 0, 4.41f, -3.59f, 8, -8, 8,
 CLOSE,
-MOVE_TO, 18.7f, 9.5f,
-R_LINE_TO, -6.4f, 6.3f,
-R_LINE_TO, -2.5f, -2.5f,
-R_LINE_TO, -1.3f, 1.4f,
-R_LINE_TO, 3.8f, 3.8f,
-R_LINE_TO, 7.7f, -7.7f,
-CLOSE
\ No newline at end of file
+R_MOVE_TO, -2, -5.8f,
+R_LINE_TO, -2.6f, -2.6f,
+LINE_TO, 8, 15,
+R_LINE_TO, 4, 4,
+R_LINE_TO, 8, -8,
+R_LINE_TO, -1.4f, -1.4f,
+CLOSE
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 90b62f4..a54d240 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2158,7 +2158,7 @@
 
   flags = [
     "CLANG_COVERAGE=$use_clang_coverage",
-    "CLANG_COVERAGE_INSIDE_SANDBOX=$use_clang_coverage_inside_sandbox"
+    "CLANG_COVERAGE_INSIDE_SANDBOX=$use_clang_coverage_inside_sandbox",
   ]
 }
 
@@ -2184,9 +2184,7 @@
       "win/static_constants.h",
     ]
 
-    public_deps = [
-      "//base/win:pe_image",
-    ]
+    public_deps = [ "//base/win:pe_image" ]
 
     # Disable sanitizer coverage in win/pe_image.cc. It is called by the sandbox
     # before sanitizer coverage can initialize. http://crbug.com/484711
@@ -2311,9 +2309,7 @@
 }
 
 test("base_i18n_perftests") {
-  sources = [
-    "i18n/streaming_utf8_validator_perftest.cc",
-  ]
+  sources = [ "i18n/streaming_utf8_validator_perftest.cc" ]
   deps = [
     ":base",
     ":i18n",
@@ -2325,9 +2321,7 @@
 
 if (!is_ios) {
   executable("build_utf8_validator_tables") {
-    sources = [
-      "i18n/build_utf8_validator_tables.cc",
-    ]
+    sources = [ "i18n/build_utf8_validator_tables.cc" ]
     deps = [
       ":base",
       "//build/win:default_exe_manifest",
@@ -2336,9 +2330,7 @@
   }
 
   executable("check_example") {
-    sources = [
-      "check_example.cc",
-    ]
+    sources = [ "check_example.cc" ]
     deps = [
       ":base",
       "//build/win:default_exe_manifest",
@@ -2350,9 +2342,7 @@
   # Target to manually rebuild pe_image_test.dll which is checked into
   # base/test/data/pe_image.
   shared_library("pe_image_test") {
-    sources = [
-      "win/pe_image_test.cc",
-    ]
+    sources = [ "win/pe_image_test.cc" ]
     ldflags = [
       "/DELAYLOAD:cfgmgr32.dll",
       "/DELAYLOAD:shell32.dll",
@@ -2365,9 +2355,7 @@
   }
 
   loadable_module("scoped_handle_test_dll") {
-    sources = [
-      "win/scoped_handle_test_dll.cc",
-    ]
+    sources = [ "win/scoped_handle_test_dll.cc" ]
     deps = [
       ":base",
       "//base/win:base_win_buildflags",
@@ -2379,9 +2367,7 @@
   if (current_cpu == "x64" || (current_cpu == "arm64" && is_win)) {
     # Must be a shared library so that it can be unloaded during testing.
     shared_library("base_profiler_test_support_library") {
-      sources = [
-        "profiler/test_support_library.cc",
-      ]
+      sources = [ "profiler/test_support_library.cc" ]
     }
   }
 }
@@ -2425,10 +2411,8 @@
     "test/data/serializer_test.json",
     "test/data/serializer_test_nowhitespace.json",
   ]
-  outputs = [
-    "{{bundle_resources_dir}}/" +
-        "{{source_root_relative_dir}}/{{source_file_part}}",
-  ]
+  outputs = [ "{{bundle_resources_dir}}/" +
+              "{{source_root_relative_dir}}/{{source_file_part}}" ]
 }
 
 if (is_ios || is_mac) {
@@ -2450,9 +2434,7 @@
   fidl_library("testfidl") {
     namespace = "base.fuchsia"
 
-    sources = [
-      "fuchsia/test.fidl",
-    ]
+    sources = [ "fuchsia/test.fidl" ]
   }
 
   source_set("test_interface_impl") {
@@ -2474,9 +2456,7 @@
     "task/test_task_traits_extension.cc",
     "task/test_task_traits_extension.h",
   ]
-  deps = [
-    ":base",
-  ]
+  deps = [ ":base" ]
 }
 
 test("base_unittests") {
@@ -2804,9 +2784,7 @@
     deps += [ ":base_unittests_arc" ]
   }
 
-  public_deps = [
-    ":base_unittests_bundle_data",
-  ]
+  public_deps = [ ":base_unittests_bundle_data" ]
 
   data = [
     "test/data/",
@@ -3128,9 +3106,7 @@
 action("build_date") {
   script = "//build/write_build_date_header.py"
 
-  outputs = [
-    "$target_gen_dir/generated_build_date.h",
-  ]
+  outputs = [ "$target_gen_dir/generated_build_date.h" ]
 
   args = [
     rebase_path("$target_gen_dir/generated_build_date.h", root_build_dir),
@@ -3153,6 +3129,7 @@
       "metrics/histogram_unittest.nc",
       "observer_list_unittest.nc",
       "optional_unittest.nc",
+      "sequence_checker_unittest.nc",
       "strings/string16_unittest.nc",
       "task/task_traits_extension_unittest.nc",
       "task/task_traits_unittest.nc",
@@ -3212,9 +3189,7 @@
       "android/java/src/org/chromium/base/task/TaskRunnerImpl.java",
     ]
 
-    public_deps = [
-      ":android_runtime_jni_headers",
-    ]
+    public_deps = [ ":android_runtime_jni_headers" ]
   }
 
   generate_jar_jni("android_runtime_jni_headers") {
@@ -3450,16 +3425,12 @@
       ":base",
       ":base_javatests_jni_headers",
     ]
-    sources = [
-      "test/library_loader/early_native_test_helper.cc",
-    ]
+    sources = [ "test/library_loader/early_native_test_helper.cc" ]
   }
 
   generate_jni("base_javatests_jni_headers") {
     testonly = true
-    sources = [
-      "android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java",
-    ]
+    sources = [ "android/javatests/src/org/chromium/base/library_loader/EarlyNativeTest.java" ]
   }
 
   android_library("base_java_test_support") {
@@ -3556,9 +3527,7 @@
       ":base_java",
       ":base_java_test_support",
     ]
-    sources = [
-      "test/android/javatests/src/org/chromium/base/test/TestChildProcessConnection.java",
-    ]
+    sources = [ "test/android/javatests/src/org/chromium/base/test/TestChildProcessConnection.java" ]
   }
 
   android_library("base_junit_test_support") {
@@ -3650,9 +3619,7 @@
 
   android_library("base_java_unittest_support") {
     testonly = true
-    deps = [
-      ":base_java",
-    ]
+    deps = [ ":base_java" ]
     sources = [
       "test/android/java/src/org/chromium/base/ContentUriTestUtils.java",
       "test/android/java/src/org/chromium/base/JavaHandlerThreadHelpers.java",
@@ -3662,50 +3629,30 @@
 
 # Keep the list of fuzzer_tests in alphabetical order.
 fuzzer_test("base64_decode_fuzzer") {
-  sources = [
-    "base64_decode_fuzzer.cc",
-  ]
-  deps = [
-    "//base",
-  ]
+  sources = [ "base64_decode_fuzzer.cc" ]
+  deps = [ "//base" ]
 }
 
 fuzzer_test("base64_encode_fuzzer") {
-  sources = [
-    "base64_encode_fuzzer.cc",
-  ]
-  deps = [
-    "//base",
-  ]
+  sources = [ "base64_encode_fuzzer.cc" ]
+  deps = [ "//base" ]
 }
 
 fuzzer_test("base_json_correctness_fuzzer") {
-  sources = [
-    "json/json_correctness_fuzzer.cc",
-  ]
-  deps = [
-    ":base",
-  ]
+  sources = [ "json/json_correctness_fuzzer.cc" ]
+  deps = [ ":base" ]
   dict = "//testing/libfuzzer/fuzzers/dicts/json.dict"
 }
 
 fuzzer_test("base_json_reader_fuzzer") {
-  sources = [
-    "json/json_reader_fuzzer.cc",
-  ]
-  deps = [
-    "//base",
-  ]
+  sources = [ "json/json_reader_fuzzer.cc" ]
+  deps = [ "//base" ]
   dict = "//testing/libfuzzer/fuzzers/dicts/json.dict"
 }
 
 fuzzer_test("base_json_string_escape_fuzzer") {
-  sources = [
-    "json/string_escape_fuzzer.cc",
-  ]
-  deps = [
-    "//base",
-  ]
+  sources = [ "json/string_escape_fuzzer.cc" ]
+  deps = [ "//base" ]
 }
 
 if (is_mac) {
@@ -3714,9 +3661,7 @@
       "test/data/mach_port_rendezvous_fuzz/dead_name.textproto",
       "test/data/mach_port_rendezvous_fuzz/send.textproto",
     ]
-    inputs = [
-      "//testing/libfuzzer/fuzzers/mach/mach_message.proto",
-    ]
+    inputs = [ "//testing/libfuzzer/fuzzers/mach/mach_message.proto" ]
     output_pattern = "$target_gen_dir/base_mach_port_rendezvous_corpus/{{source_name_part}}.binarypb"
     args = [
       "--encode=mach_fuzzer.MachMessage",
@@ -3726,9 +3671,7 @@
     ]
   }
   fuzzer_test("base_mach_port_rendezvous_fuzzer") {
-    sources = [
-      "mac/mach_port_rendezvous_fuzzer.cc",
-    ]
+    sources = [ "mac/mach_port_rendezvous_fuzzer.cc" ]
     deps = [
       "//base",
       "//testing/libfuzzer/fuzzers/mach:converter",
@@ -3740,36 +3683,22 @@
 }
 
 fuzzer_test("string_number_conversions_fuzzer") {
-  sources = [
-    "strings/string_number_conversions_fuzzer.cc",
-  ]
-  deps = [
-    "//base",
-  ]
+  sources = [ "strings/string_number_conversions_fuzzer.cc" ]
+  deps = [ "//base" ]
 }
 
 fuzzer_test("string_tokenizer_fuzzer") {
-  sources = [
-    "strings/string_tokenizer_fuzzer.cc",
-  ]
-  deps = [
-    "//base",
-  ]
+  sources = [ "strings/string_tokenizer_fuzzer.cc" ]
+  deps = [ "//base" ]
 }
 
 fuzzer_test("utf_string_conversions_fuzzer") {
-  sources = [
-    "strings/utf_string_conversions_fuzzer.cc",
-  ]
-  deps = [
-    "//base",
-  ]
+  sources = [ "strings/utf_string_conversions_fuzzer.cc" ]
+  deps = [ "//base" ]
 }
 
 fuzzer_test("pickle_fuzzer") {
-  sources = [
-    "pickle_fuzzer.cc",
-  ]
+  sources = [ "pickle_fuzzer.cc" ]
   deps = [
     "//base",
     "//base/test:test_support",
diff --git a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
index 990b717..f763aca 100644
--- a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
+++ b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
@@ -432,15 +432,25 @@
         // JniStaticTestMocker<ClassNameJni> TEST_HOOKS = new JniStaticTestMocker<>() {
         //      @Override
         //      public static setInstanceForTesting(ClassNameJni instance) {
+        //          if (!GEN_JNI.TESTING_ENABLED) {
+        //              throw new RuntimeException($mocksNotEnabledExceptionString);
+        //          }
         //          testInstance = instance;
         //      }
         // }
-        MethodSpec testHookMockerMethod = MethodSpec.methodBuilder("setInstanceForTesting")
-                                                  .addModifiers(Modifier.PUBLIC)
-                                                  .addAnnotation(Override.class)
-                                                  .addParameter(nativeInterfaceType, "instance")
-                                                  .addStatement("$N = instance", testTarget)
-                                                  .build();
+        String mocksNotEnabledExceptionString =
+                "Tried to set a JNI mock when mocks aren't enabled!";
+        MethodSpec testHookMockerMethod =
+                MethodSpec.methodBuilder("setInstanceForTesting")
+                        .addModifiers(Modifier.PUBLIC)
+                        .addAnnotation(Override.class)
+                        .addParameter(nativeInterfaceType, "instance")
+                        .beginControlFlow("if (!$T.$N)", mNativeClassName, NATIVE_TEST_FIELD_NAME)
+                        .addStatement(
+                                "throw new RuntimeException($S)", mocksNotEnabledExceptionString)
+                        .endControlFlow()
+                        .addStatement("$N = instance", testTarget)
+                        .build();
 
         // Make the anonymous TEST_HOOK class.
         ParameterizedTypeName genericMockerInterface = ParameterizedTypeName.get(
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
index 357e6cb..e009847 100644
--- a/base/json/json_parser.cc
+++ b/base/json/json_parser.cc
@@ -248,11 +248,12 @@
 }
 
 bool JSONParser::EatComment() {
-  Optional<StringPiece> comment_start = ConsumeChars(2);
+  Optional<StringPiece> comment_start = PeekChars(2);
   if (!comment_start)
     return false;
 
   if (comment_start == "//") {
+    ConsumeChars(2);
     // Single line comment, read to newline.
     while (Optional<char> c = PeekChar()) {
       if (c == '\n' || c == '\r')
@@ -260,6 +261,7 @@
       ConsumeChar();
     }
   } else if (comment_start == "/*") {
+    ConsumeChars(2);
     char previous_char = '\0';
     // Block comment, read until end marker.
     while (Optional<char> c = PeekChar()) {
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
index c41b8a8..fe0b9d0 100644
--- a/base/json/json_reader_unittest.cc
+++ b/base/json/json_reader_unittest.cc
@@ -76,6 +76,9 @@
   ASSERT_TRUE(root);
   EXPECT_TRUE(root->is_int());
   EXPECT_EQ(44, root->GetInt());
+
+  // At one point, this parsed successfully as the value three.
+  EXPECT_FALSE(JSONReader::Read("/33"));
 }
 
 TEST(JSONReaderTest, Ints) {
diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc
index 0efcc44..da57943 100644
--- a/base/memory/weak_ptr.cc
+++ b/base/memory/weak_ptr.cc
@@ -25,8 +25,8 @@
 }
 
 bool WeakReference::Flag::IsValid() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_)
-      << "WeakPtrs must be checked on the same sequenced thread.";
+  // WeakPtrs must be checked on the same sequenced thread.
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return !invalidated_.IsSet();
 }
 
diff --git a/base/sequence_checker.h b/base/sequence_checker.h
index 8477dde..60ffd75 100644
--- a/base/sequence_checker.h
+++ b/base/sequence_checker.h
@@ -8,10 +8,12 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/sequence_checker_impl.h"
+#include "base/strings/string_piece.h"
 #include "build/build_config.h"
 
 // SequenceChecker is a helper class used to help verify that some methods of a
-// class are called sequentially (for thread-safety).
+// class are called sequentially (for thread-safety). It supports thread safety
+// annotations (see base/thread_annotations.h).
 //
 // Use the macros below instead of the SequenceChecker directly so that the
 // unused member doesn't result in an extra byte (four when padded) per
@@ -43,16 +45,36 @@
 //     void MyMethod() {
 //       DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
 //       ... (do stuff) ...
+//       MyOtherMethod();
+//     }
+//
+//     void MyOtherMethod()
+//         VALID_CONTEXT_REQUIRED(my_sequence_checker_) {
+//       foo_ = 42;
 //     }
 //
 //    private:
+//      // GUARDED_BY_CONTEXT() enforces that this member is only
+//      // accessed from a scope that invokes DCHECK_CALLED_ON_VALID_SEQUENCE()
+//      // or from a function annotated with VALID_CONTEXT_REQUIRED(). A
+//      // DCHECK build will not compile if the member is accessed and these
+//      // conditions are not met.
+//     int foo_ GUARDED_BY_CONTEXT(my_sequence_checker_);
+//
 //     SEQUENCE_CHECKER(my_sequence_checker_);
 //   }
 
+#define SEQUENCE_CHECKER_INTERNAL_CONCAT2(a, b) a##b
+#define SEQUENCE_CHECKER_INTERNAL_CONCAT(a, b) \
+  SEQUENCE_CHECKER_INTERNAL_CONCAT2(a, b)
+#define SEQUENCE_CHECKER_INTERNAL_UID(prefix) \
+  SEQUENCE_CHECKER_INTERNAL_CONCAT(prefix, __LINE__)
+
 #if DCHECK_IS_ON()
 #define SEQUENCE_CHECKER(name) base::SequenceChecker name
-#define DCHECK_CALLED_ON_VALID_SEQUENCE(name) \
-  DCHECK((name).CalledOnValidSequence())
+#define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...)                   \
+  base::ScopedValidateSequenceChecker SEQUENCE_CHECKER_INTERNAL_UID( \
+      scoped_validate_sequence_checker_)(name, ##__VA_ARGS__);
 #define DETACH_FROM_SEQUENCE(name) (name).DetachFromSequence()
 #else  // DCHECK_IS_ON()
 #if __OBJC__ && defined(OS_IOS) && !HAS_FEATURE(objc_cxx_static_assert)
@@ -61,7 +83,7 @@
 #else
 #define SEQUENCE_CHECKER(name) static_assert(true, "")
 #endif
-#define DCHECK_CALLED_ON_VALID_SEQUENCE(name) EAT_STREAM_PARAMETERS
+#define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...) EAT_STREAM_PARAMETERS
 #define DETACH_FROM_SEQUENCE(name)
 #endif  // DCHECK_IS_ON()
 
@@ -71,7 +93,9 @@
 //
 // Note: You should almost always use the SequenceChecker class (through the
 // above macros) to get the right version for your build configuration.
-class SequenceCheckerDoNothing {
+// Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
+// order to support thread_annotations.h.
+class LOCKABLE SequenceCheckerDoNothing {
  public:
   SequenceCheckerDoNothing() = default;
 
@@ -96,6 +120,24 @@
 };
 #endif  // DCHECK_IS_ON()
 
+class SCOPED_LOCKABLE ScopedValidateSequenceChecker {
+ public:
+  explicit ScopedValidateSequenceChecker(const SequenceChecker& checker)
+      EXCLUSIVE_LOCK_FUNCTION(checker) {
+    DCHECK(checker.CalledOnValidSequence());
+  }
+
+  explicit ScopedValidateSequenceChecker(const SequenceChecker& checker,
+                                         const StringPiece& msg)
+      EXCLUSIVE_LOCK_FUNCTION(checker) {
+    DCHECK(checker.CalledOnValidSequence()) << msg;
+  }
+
+  ~ScopedValidateSequenceChecker() UNLOCK_FUNCTION() {}
+
+ private:
+};
+
 }  // namespace base
 
 #endif  // BASE_SEQUENCE_CHECKER_H_
diff --git a/base/sequence_checker_impl.h b/base/sequence_checker_impl.h
index 3599fb8..ea0fbb5 100644
--- a/base/sequence_checker_impl.h
+++ b/base/sequence_checker_impl.h
@@ -21,7 +21,9 @@
 //
 // Note: You should almost always use the SequenceChecker class to get the right
 // version for your build configuration.
-class BASE_EXPORT SequenceCheckerImpl {
+// Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
+// order to support thread_annotations.h.
+class LOCKABLE BASE_EXPORT SequenceCheckerImpl {
  public:
   SequenceCheckerImpl();
   ~SequenceCheckerImpl();
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc
index 537facc..58c668d 100644
--- a/base/sequence_checker_unittest.cc
+++ b/base/sequence_checker_unittest.cc
@@ -230,27 +230,27 @@
       SequenceToken::Create());
   SEQUENCE_CHECKER(my_sequence_checker);
 
-  // Don't expect a DCHECK death when a SequenceChecker is used on the right
-  // sequence.
-  DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message.";
-
+  {
+    // Don't expect a DCHECK death when a SequenceChecker is used on the right
+    // sequence.
+    DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
+  }
   scope.reset();
 
 #if DCHECK_IS_ON()
   // Expect DCHECK death when used on a different sequence.
-  EXPECT_DCHECK_DEATH({
-    DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message.";
-  });
+  EXPECT_DCHECK_DEATH(
+      { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); });
 #else
     // Happily no-ops on non-dcheck builds.
-    DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message.";
+  DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
 #endif
 
   DETACH_FROM_SEQUENCE(my_sequence_checker);
 
   // Don't expect a DCHECK death when a SequenceChecker is used for the first
   // time after having been detached.
-  DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker) << "Error message.";
+  DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
 }
 
 // Owns a SequenceCheckerImpl, and asserts that CalledOnValidSequence() is valid
diff --git a/base/sequence_checker_unittest.nc b/base/sequence_checker_unittest.nc
new file mode 100644
index 0000000..61b6bf0
--- /dev/null
+++ b/base/sequence_checker_unittest.nc
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a "No Compile Test" suite.
+// https://dev.chromium.org/developers/testing/no-compile-tests
+
+#include "base/sequence_checker.h"
+
+namespace {
+
+class SequenceAffine {
+ public:
+  void BuggyIncrement();
+
+  void Increment() VALID_CONTEXT_REQUIRED(sequence_checker_) {
+    ++counter_;
+  }
+
+ private:
+  int counter_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+#if defined(NCTEST_ACCESS_WITHOUT_CHECK)  // [r"fatal error: writing variable 'counter_' requires holding mutex 'sequence_checker_' exclusively"]
+
+void SequenceAffine::BuggyIncrement() {
+  // Member access without sequence_checker_ assertion.
+  ++counter_;
+}
+
+#elif defined(NCTEST_CALL_WITHOUT_CHECK)  // [r"fatal error: calling function 'Increment' requires holding mutex 'sequence_checker_' exclusively"]
+
+void SequenceAffine::BuggyIncrement() {
+  // Function call without sequence_checker_ assertion.
+  Increment();
+}
+
+
+#endif
+
+}  // namespace
\ No newline at end of file
diff --git a/base/third_party/dynamic_annotations/BUILD.gn b/base/third_party/dynamic_annotations/BUILD.gn
index 0fc4bf7..251a1f00 100644
--- a/base/third_party/dynamic_annotations/BUILD.gn
+++ b/base/third_party/dynamic_annotations/BUILD.gn
@@ -7,9 +7,7 @@
   # dummy target in order for clients to not have to special-case the
   # dependency.
   source_set("dynamic_annotations") {
-    sources = [
-      "dynamic_annotations.h",
-    ]
+    sources = [ "dynamic_annotations.h" ]
   }
 } else {
   # Should be static library, see documentation on //base:base for discussion.
diff --git a/base/thread_annotations.h b/base/thread_annotations.h
index bba3ed7..fdd32f8 100644
--- a/base/thread_annotations.h
+++ b/base/thread_annotations.h
@@ -32,6 +32,7 @@
 #ifndef BASE_THREAD_ANNOTATIONS_H_
 #define BASE_THREAD_ANNOTATIONS_H_
 
+#include "base/logging.h"
 #include "build/build_config.h"
 
 #if defined(__clang__)
@@ -237,4 +238,27 @@
 
 }  // namespace thread_safety_analysis
 
+// The above is imported as-is from abseil-cpp. The following Chromium-specific
+// synonyms are added for Chromium concepts (SequenceChecker/ThreadChecker).
+#if DCHECK_IS_ON()
+
+// Equivalent to GUARDED_BY for SequenceChecker/ThreadChecker. Currently,
+// clang's error message "requires holding mutex" is misleading. Usage of this
+// macro is discouraged until the message is updated.
+// TODO(etiennep): Update comment above once clang's error message is updated.
+#define GUARDED_BY_CONTEXT(name) GUARDED_BY(name)
+
+// Equivalent to EXCLUSIVE_LOCKS_REQUIRED for SequenceChecker/ThreadChecker.
+// Currently, clang's error message "requires holding mutex" is misleading.
+// Usage of this macro is discouraged until the message is updated.
+// TODO(etiennep): Update comment above once clang's error message is updated.
+#define VALID_CONTEXT_REQUIRED(name) EXCLUSIVE_LOCKS_REQUIRED(name)
+
+#else  // DCHECK_IS_ON()
+
+#define GUARDED_BY_CONTEXT(name)
+#define VALID_CONTEXT_REQUIRED(name)
+
+#endif  // DCHECK_IS_ON()
+
 #endif  // BASE_THREAD_ANNOTATIONS_H_
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
index 5e3cb85..e149534 100644
--- a/base/threading/thread_checker.h
+++ b/base/threading/thread_checker.h
@@ -7,10 +7,13 @@
 
 #include "base/compiler_specific.h"
 #include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/thread_annotations.h"
 #include "base/threading/thread_checker_impl.h"
 
 // ThreadChecker is a helper class used to help verify that some methods of a
-// class are called from the same thread (for thread-affinity).
+// class are called from the same thread (for thread-affinity).  It supports
+// thread safety annotations (see base/thread_annotations.h).
 //
 // Use the macros below instead of the ThreadChecker directly so that the unused
 // member doesn't result in an extra byte (four when padded) per instance in
@@ -56,17 +59,32 @@
 //       ... (do stuff) ...
 //     }
 //
+//     void MyOtherMethod()
+//         VALID_CONTEXT_REQUIRED(thread_checker_) {
+//       foo_ = 42;
+//     }
+//
 //    private:
+//     int foo_ GUARDED_BY_CONTEXT(thread_checker_);
+//
 //     THREAD_CHECKER(thread_checker_);
 //   }
 
+#define THREAD_CHECKER_INTERNAL_CONCAT2(a, b) a##b
+#define THREAD_CHECKER_INTERNAL_CONCAT(a, b) \
+  THREAD_CHECKER_INTERNAL_CONCAT2(a, b)
+#define THREAD_CHECKER_INTERNAL_UID(prefix) \
+  THREAD_CHECKER_INTERNAL_CONCAT(prefix, __LINE__)
+
 #if DCHECK_IS_ON()
 #define THREAD_CHECKER(name) base::ThreadChecker name
-#define DCHECK_CALLED_ON_VALID_THREAD(name) DCHECK((name).CalledOnValidThread())
+#define DCHECK_CALLED_ON_VALID_THREAD(name, ...)                 \
+  base::ScopedValidateThreadChecker THREAD_CHECKER_INTERNAL_UID( \
+      scoped_validate_thread_checker_)(name, ##__VA_ARGS__);
 #define DETACH_FROM_THREAD(name) (name).DetachFromThread()
 #else  // DCHECK_IS_ON()
 #define THREAD_CHECKER(name) static_assert(true, "")
-#define DCHECK_CALLED_ON_VALID_THREAD(name) EAT_STREAM_PARAMETERS
+#define DCHECK_CALLED_ON_VALID_THREAD(name, ...) EAT_STREAM_PARAMETERS
 #define DETACH_FROM_THREAD(name)
 #endif  // DCHECK_IS_ON()
 
@@ -76,7 +94,9 @@
 //
 // Note: You should almost always use the ThreadChecker class (through the above
 // macros) to get the right version for your build configuration.
-class ThreadCheckerDoNothing {
+// Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
+// order to support thread_annotations.h.
+class LOCKABLE ThreadCheckerDoNothing {
  public:
   ThreadCheckerDoNothing() = default;
 
@@ -104,6 +124,25 @@
 };
 #endif  // DCHECK_IS_ON()
 
+class SCOPED_LOCKABLE ScopedValidateThreadChecker {
+ public:
+  explicit ScopedValidateThreadChecker(const ThreadChecker& checker)
+      EXCLUSIVE_LOCK_FUNCTION(checker) {
+    DCHECK(checker.CalledOnValidThread());
+  }
+
+  explicit ScopedValidateThreadChecker(const ThreadChecker& checker,
+                                       const StringPiece& msg)
+      EXCLUSIVE_LOCK_FUNCTION(checker) {
+    DCHECK(checker.CalledOnValidThread()) << msg;
+  }
+
+  ~ScopedValidateThreadChecker() UNLOCK_FUNCTION() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedValidateThreadChecker);
+};
+
 }  // namespace base
 
 #endif  // BASE_THREADING_THREAD_CHECKER_H_
diff --git a/base/threading/thread_checker_impl.h b/base/threading/thread_checker_impl.h
index e911cec..b325db6a 100644
--- a/base/threading/thread_checker_impl.h
+++ b/base/threading/thread_checker_impl.h
@@ -20,7 +20,9 @@
 //
 // Note: You should almost always use the ThreadChecker class to get the right
 // version for your build configuration.
-class BASE_EXPORT ThreadCheckerImpl {
+// Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
+// order to support thread_annotations.h.
+class LOCKABLE BASE_EXPORT ThreadCheckerImpl {
  public:
   ThreadCheckerImpl();
   ~ThreadCheckerImpl();
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc
index 5041baf..d195889 100644
--- a/base/threading/thread_checker_unittest.cc
+++ b/base/threading/thread_checker_unittest.cc
@@ -321,8 +321,6 @@
 
   void ExpectNoDeathOnOtherThreadAfterDetach() {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_)
-        << "Make sure it compiles when DCHECK is off";
   }
 
  protected:
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 09d00dd..4e416e6 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -581,9 +581,7 @@
     deps += [ "//gpu/vulkan/init" ]
   }
   if (!is_android) {
-    data_deps = [
-      "//third_party/mesa_headers",
-    ]
+    data_deps = [ "//third_party/mesa_headers" ]
   }
 }
 
@@ -743,9 +741,7 @@
   ]
 
   if (!is_android) {
-    data = [
-      "//components/viz/test/data/",
-    ]
+    data = [ "//components/viz/test/data/" ]
   }
 
   if (is_win) {
@@ -786,9 +782,7 @@
     "//ui/gl",
     "//ui/gl:test_support",
   ]
-  data_deps = [
-    "//third_party/mesa_headers",
-  ]
+  data_deps = [ "//third_party/mesa_headers" ]
 
   if (enable_vulkan) {
     deps += [
@@ -857,9 +851,7 @@
   # This target should not require the Chrome executable to run.
   assert_no_deps = [ "//chrome" ]
 
-  data = [
-    "//components/viz/test/data/",
-  ]
+  data = [ "//components/viz/test/data/" ]
 
   data_deps = [
     # Needed for isolate script to execute.
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc
index 30cc0b3..361f205 100644
--- a/cc/metrics/compositor_frame_reporter.cc
+++ b/cc/metrics/compositor_frame_reporter.cc
@@ -145,9 +145,11 @@
 
 CompositorFrameReporter::CompositorFrameReporter(
     const base::flat_set<FrameSequenceTrackerType>* active_trackers,
+    const viz::BeginFrameId& id,
     LatencyUkmReporter* latency_ukm_reporter,
     bool is_single_threaded)
-    : is_single_threaded_(is_single_threaded),
+    : frame_id_(id),
+      is_single_threaded_(is_single_threaded),
       active_trackers_(active_trackers),
       latency_ukm_reporter_(latency_ukm_reporter) {
   TRACE_EVENT_ASYNC_BEGIN1("cc,benchmark", "PipelineReporter", this,
diff --git a/cc/metrics/compositor_frame_reporter.h b/cc/metrics/compositor_frame_reporter.h
index 85c9d43..be72ea5 100644
--- a/cc/metrics/compositor_frame_reporter.h
+++ b/cc/metrics/compositor_frame_reporter.h
@@ -13,6 +13,7 @@
 #include "cc/cc_export.h"
 #include "cc/metrics/begin_main_frame_metrics.h"
 #include "cc/metrics/frame_sequence_tracker.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/frame_timing_details.h"
 
 namespace viz {
@@ -118,6 +119,7 @@
 
   CompositorFrameReporter(
       const base::flat_set<FrameSequenceTrackerType>* active_trackers,
+      const viz::BeginFrameId& id,
       LatencyUkmReporter* latency_ukm_reporter,
       bool is_single_threaded = false);
   ~CompositorFrameReporter();
@@ -126,6 +128,8 @@
   CompositorFrameReporter& operator=(const CompositorFrameReporter& reporter) =
       delete;
 
+  const viz::BeginFrameId frame_id_;
+
   void MissedSubmittedFrame();
 
   // Note that the started stage may be reported to UMA. If the histogram is
diff --git a/cc/metrics/compositor_frame_reporter_unittest.cc b/cc/metrics/compositor_frame_reporter_unittest.cc
index 18a67030..e6f2d137 100644
--- a/cc/metrics/compositor_frame_reporter_unittest.cc
+++ b/cc/metrics/compositor_frame_reporter_unittest.cc
@@ -19,6 +19,7 @@
   CompositorFrameReporterTest()
       : pipeline_reporter_(
             std::make_unique<CompositorFrameReporter>(&active_trackers,
+                                                      viz::BeginFrameId(),
                                                       nullptr)) {
     AdvanceNowByMs(1);
   }
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc
index 41d13a0b..022006c 100644
--- a/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -51,7 +51,8 @@
   return base::TimeTicks::Now();
 }
 
-void CompositorFrameReportingController::WillBeginImplFrame() {
+void CompositorFrameReportingController::WillBeginImplFrame(
+    const viz::BeginFrameId& id) {
   base::TimeTicks begin_time = Now();
   if (reporters_[PipelineStage::kBeginImplFrame]) {
     // If the the reporter is replaced in this stage, it means that Impl frame
@@ -61,19 +62,22 @@
         begin_time);
   }
   std::unique_ptr<CompositorFrameReporter> reporter =
-      std::make_unique<CompositorFrameReporter>(
-          &active_trackers_, latency_ukm_reporter_.get(), is_single_threaded_);
+      std::make_unique<CompositorFrameReporter>(&active_trackers_, id,
+                                                latency_ukm_reporter_.get(),
+                                                is_single_threaded_);
   reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
                        begin_time);
   reporters_[PipelineStage::kBeginImplFrame] = std::move(reporter);
 }
 
-void CompositorFrameReportingController::WillBeginMainFrame() {
+void CompositorFrameReportingController::WillBeginMainFrame(
+    const viz::BeginFrameId& id) {
   if (reporters_[PipelineStage::kBeginImplFrame]) {
     // We need to use .get() below because operator<< in std::unique_ptr is a
     // C++20 feature.
     DCHECK_NE(reporters_[PipelineStage::kBeginMainFrame].get(),
               reporters_[PipelineStage::kBeginImplFrame].get());
+    DCHECK_EQ(reporters_[PipelineStage::kBeginImplFrame]->frame_id_, id);
     reporters_[PipelineStage::kBeginImplFrame]->StartStage(
         StageType::kSendBeginMainFrameToCommit, Now());
     AdvanceReporterStage(PipelineStage::kBeginImplFrame,
@@ -83,7 +87,7 @@
     // beginMain frame before next BeginImplFrame (Not reached the ImplFrame
     // deadline yet). So will start a new reporter at BeginMainFrame.
     std::unique_ptr<CompositorFrameReporter> reporter =
-        std::make_unique<CompositorFrameReporter>(&active_trackers_,
+        std::make_unique<CompositorFrameReporter>(&active_trackers_, id,
                                                   latency_ukm_reporter_.get(),
                                                   is_single_threaded_);
     reporter->StartStage(StageType::kSendBeginMainFrameToCommit, Now());
@@ -91,9 +95,10 @@
   }
 }
 
-void CompositorFrameReportingController::BeginMainFrameAborted() {
+void CompositorFrameReportingController::BeginMainFrameAborted(
+    const viz::BeginFrameId& id) {
   DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
-
+  DCHECK_EQ(reporters_[PipelineStage::kBeginMainFrame]->frame_id_, id);
   auto& begin_main_reporter = reporters_[PipelineStage::kBeginMainFrame];
   begin_main_reporter->OnAbortBeginMainFrame();
 
@@ -145,7 +150,9 @@
 }
 
 void CompositorFrameReportingController::DidSubmitCompositorFrame(
-    uint32_t frame_token) {
+    uint32_t frame_token,
+    const viz::BeginFrameId& current_frame_id,
+    const viz::BeginFrameId& last_activated_frame_id) {
   // If there is no reporter in active stage and there exists a finished
   // BeginImplFrame reporter (i.e. if impl-frame has finished), then advance it
   // to the activate stage.
@@ -160,7 +167,6 @@
                            PipelineStage::kActivate);
     }
   }
-
   if (!reporters_[PipelineStage::kActivate])
     return;
 
@@ -172,10 +178,13 @@
                                             std::move(submitted_reporter));
 }
 
-void CompositorFrameReportingController::OnFinishImplFrame() {
+void CompositorFrameReportingController::OnFinishImplFrame(
+    const viz::BeginFrameId& id) {
   if (reporters_[PipelineStage::kBeginImplFrame]) {
+    DCHECK_EQ(reporters_[PipelineStage::kBeginImplFrame]->frame_id_, id);
     reporters_[PipelineStage::kBeginImplFrame]->OnFinishImplFrame(Now());
   } else if (reporters_[PipelineStage::kBeginMainFrame]) {
+    DCHECK_EQ(reporters_[PipelineStage::kBeginMainFrame]->frame_id_, id);
     auto& begin_main_reporter = reporters_[PipelineStage::kBeginMainFrame];
     begin_main_reporter->OnFinishImplFrame(Now());
 
diff --git a/cc/metrics/compositor_frame_reporting_controller.h b/cc/metrics/compositor_frame_reporting_controller.h
index 8848f43..3b1f43c 100644
--- a/cc/metrics/compositor_frame_reporting_controller.h
+++ b/cc/metrics/compositor_frame_reporting_controller.h
@@ -49,16 +49,19 @@
       const CompositorFrameReportingController&) = delete;
 
   // Events to signal Beginning/Ending of phases.
-  virtual void WillBeginImplFrame();
-  virtual void WillBeginMainFrame();
-  virtual void BeginMainFrameAborted();
+  virtual void WillBeginImplFrame(const viz::BeginFrameId& id);
+  virtual void WillBeginMainFrame(const viz::BeginFrameId& id);
+  virtual void BeginMainFrameAborted(const viz::BeginFrameId& id);
   virtual void WillInvalidateOnImplSide();
   virtual void WillCommit();
   virtual void DidCommit();
   virtual void WillActivate();
   virtual void DidActivate();
-  virtual void DidSubmitCompositorFrame(uint32_t frame_token);
-  virtual void OnFinishImplFrame();
+  virtual void DidSubmitCompositorFrame(
+      uint32_t frame_token,
+      const viz::BeginFrameId& current_frame_id,
+      const viz::BeginFrameId& last_activated_frame_id);
+  virtual void OnFinishImplFrame(const viz::BeginFrameId& id);
   virtual void DidPresentCompositorFrame(
       uint32_t frame_token,
       const viz::FrameTimingDetails& details);
@@ -89,6 +92,8 @@
  private:
   void AdvanceReporterStage(PipelineStage start, PipelineStage target);
 
+  viz::BeginFrameId last_submitted_frame_id_;
+
   // Used by the managed reporters to differentiate the histogram names when
   // reporting to UMA.
   const bool is_single_threaded_;
diff --git a/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
index 469550e..e35663d 100644
--- a/cc/metrics/compositor_frame_reporting_controller_unittest.cc
+++ b/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -45,11 +45,15 @@
 
 class CompositorFrameReportingControllerTest : public testing::Test {
  public:
-  CompositorFrameReportingControllerTest() : reporting_controller_(this) {}
+  CompositorFrameReportingControllerTest() : reporting_controller_(this) {
+    current_id_ = viz::BeginFrameId(1, 1);
+  }
 
   // The following functions simulate the actions that would
   // occur for each phase of the reporting controller.
-  void SimulateBeginImplFrame() { reporting_controller_.WillBeginImplFrame(); }
+  void SimulateBeginImplFrame() {
+    reporting_controller_.WillBeginImplFrame(current_id_);
+  }
 
   void SimulateBeginMainFrame() {
     if (!reporting_controller_.reporters()[CompositorFrameReportingController::
@@ -58,7 +62,7 @@
     CHECK(
         reporting_controller_.reporters()[CompositorFrameReportingController::
                                               PipelineStage::kBeginImplFrame]);
-    reporting_controller_.WillBeginMainFrame();
+    reporting_controller_.WillBeginMainFrame(current_id_);
   }
 
   void SimulateCommit(std::unique_ptr<BeginMainFrameMetrics> blink_breakdown) {
@@ -81,6 +85,7 @@
               [CompositorFrameReportingController::PipelineStage::kCommit]);
     reporting_controller_.WillActivate();
     reporting_controller_.DidActivate();
+    last_activated_id_ = viz::BeginFrameId(current_id_);
   }
 
   void SimulateSubmitCompositorFrame(uint32_t frame_token) {
@@ -89,7 +94,8 @@
       SimulateActivate();
     CHECK(reporting_controller_.reporters()
               [CompositorFrameReportingController::PipelineStage::kActivate]);
-    reporting_controller_.DidSubmitCompositorFrame(frame_token);
+    reporting_controller_.DidSubmitCompositorFrame(frame_token, current_id_,
+                                                   last_activated_id_);
   }
 
   void SimulatePresentCompositorFrame() {
@@ -102,6 +108,8 @@
 
  protected:
   TestCompositorFrameReportingController reporting_controller_;
+  viz::BeginFrameId current_id_;
+  viz::BeginFrameId last_activated_id_;
 
  private:
   viz::FrameTokenGenerator next_token_;
@@ -119,18 +127,18 @@
   // - 4 Simultaneous Reporters
 
   // BF
-  reporting_controller_.WillBeginImplFrame();
+  reporting_controller_.WillBeginImplFrame(current_id_);
   EXPECT_EQ(1, reporting_controller_.ActiveReporters());
 
   // BF -> BF
   // Should replace previous reporter.
-  reporting_controller_.WillBeginImplFrame();
+  reporting_controller_.WillBeginImplFrame(current_id_);
   EXPECT_EQ(1, reporting_controller_.ActiveReporters());
 
   // BF -> BMF -> BF
   // Should add new reporter.
-  reporting_controller_.WillBeginMainFrame();
-  reporting_controller_.WillBeginImplFrame();
+  reporting_controller_.WillBeginMainFrame(current_id_);
+  reporting_controller_.WillBeginImplFrame(current_id_);
   EXPECT_EQ(2, reporting_controller_.ActiveReporters());
 
   // BF -> BMF -> BF -> Commit
@@ -141,16 +149,18 @@
 
   // BF -> BMF -> BF -> Commit -> BMF -> Activate -> Commit -> Activation
   // Having two reporters at Activate phase should delete the older one.
-  reporting_controller_.WillBeginMainFrame();
+  reporting_controller_.WillBeginMainFrame(current_id_);
   reporting_controller_.WillActivate();
   reporting_controller_.DidActivate();
+  last_activated_id_ = viz::BeginFrameId(current_id_);
   reporting_controller_.WillCommit();
   reporting_controller_.DidCommit();
   reporting_controller_.WillActivate();
   reporting_controller_.DidActivate();
   EXPECT_EQ(1, reporting_controller_.ActiveReporters());
 
-  reporting_controller_.DidSubmitCompositorFrame(0);
+  reporting_controller_.DidSubmitCompositorFrame(0, current_id_,
+                                                 last_activated_id_);
   EXPECT_EQ(0, reporting_controller_.ActiveReporters());
 
   // 4 simultaneous reporters active.
@@ -242,11 +252,12 @@
 TEST_F(CompositorFrameReportingControllerTest, MainFrameAborted) {
   base::HistogramTester histogram_tester;
 
-  reporting_controller_.WillBeginImplFrame();
-  reporting_controller_.WillBeginMainFrame();
-  reporting_controller_.BeginMainFrameAborted();
-  reporting_controller_.OnFinishImplFrame();
-  reporting_controller_.DidSubmitCompositorFrame(1);
+  reporting_controller_.WillBeginImplFrame(current_id_);
+  reporting_controller_.WillBeginMainFrame(current_id_);
+  reporting_controller_.BeginMainFrameAborted(current_id_);
+  reporting_controller_.OnFinishImplFrame(current_id_);
+  reporting_controller_.DidSubmitCompositorFrame(1, current_id_,
+                                                 last_activated_id_);
 
   viz::FrameTimingDetails details = {};
   reporting_controller_.DidPresentCompositorFrame(1, details);
diff --git a/cc/metrics/compositor_timing_history.cc b/cc/metrics/compositor_timing_history.cc
index d2bf9e2..fdb8a44 100644
--- a/cc/metrics/compositor_timing_history.cc
+++ b/cc/metrics/compositor_timing_history.cc
@@ -710,7 +710,7 @@
   viz::BeginFrameArgs::BeginFrameArgsType frame_type = args.type;
   base::TimeTicks frame_time = args.frame_time;
 
-  compositor_frame_reporting_controller_->WillBeginImplFrame();
+  compositor_frame_reporting_controller_->WillBeginImplFrame(args.frame_id);
 
   // The check for whether a BeginMainFrame was sent anytime between two
   // BeginImplFrames protects us from not detecting a fast main thread that
@@ -729,11 +729,12 @@
   did_send_begin_main_frame_ = false;
 }
 
-void CompositorTimingHistory::WillFinishImplFrame(bool needs_redraw) {
+void CompositorTimingHistory::WillFinishImplFrame(bool needs_redraw,
+                                                  const viz::BeginFrameId& id) {
   if (!needs_redraw)
     SetCompositorDrawingContinuously(false);
 
-  compositor_frame_reporting_controller_->OnFinishImplFrame();
+  compositor_frame_reporting_controller_->OnFinishImplFrame(id);
 }
 
 void CompositorTimingHistory::BeginImplFrameNotExpectedSoon() {
@@ -743,16 +744,15 @@
 }
 
 void CompositorTimingHistory::WillBeginMainFrame(
-    bool on_critical_path,
-    base::TimeTicks main_frame_time) {
+    const viz::BeginFrameArgs& args) {
   DCHECK_EQ(base::TimeTicks(), begin_main_frame_sent_time_);
   DCHECK_EQ(base::TimeTicks(), begin_main_frame_frame_time_);
 
-  compositor_frame_reporting_controller_->WillBeginMainFrame();
+  compositor_frame_reporting_controller_->WillBeginMainFrame(args.frame_id);
 
-  begin_main_frame_on_critical_path_ = on_critical_path;
+  begin_main_frame_on_critical_path_ = args.on_critical_path;
   begin_main_frame_sent_time_ = Now();
-  begin_main_frame_frame_time_ = main_frame_time;
+  begin_main_frame_frame_time_ = args.frame_time;
 
   did_send_begin_main_frame_ = true;
   SetBeginMainFrameNeededContinuously(true);
@@ -765,8 +765,9 @@
   begin_main_frame_start_time_ = main_thread_start_time;
 }
 
-void CompositorTimingHistory::BeginMainFrameAborted() {
-  compositor_frame_reporting_controller_->BeginMainFrameAborted();
+void CompositorTimingHistory::BeginMainFrameAborted(
+    const viz::BeginFrameId& id) {
+  compositor_frame_reporting_controller_->BeginMainFrameAborted(id);
   SetBeginMainFrameCommittingContinuously(false);
   base::TimeTicks begin_main_frame_end_time = Now();
   DidBeginMainFrame(begin_main_frame_end_time);
@@ -1064,9 +1065,13 @@
   draw_start_time_ = base::TimeTicks();
 }
 
-void CompositorTimingHistory::DidSubmitCompositorFrame(uint32_t frame_token) {
+void CompositorTimingHistory::DidSubmitCompositorFrame(
+    uint32_t frame_token,
+    const viz::BeginFrameId& current_frame_id,
+    const viz::BeginFrameId& last_activated_frame_id) {
   DCHECK_EQ(base::TimeTicks(), submit_start_time_);
-  compositor_frame_reporting_controller_->DidSubmitCompositorFrame(frame_token);
+  compositor_frame_reporting_controller_->DidSubmitCompositorFrame(
+      frame_token, current_frame_id, last_activated_frame_id);
   submit_start_time_ = Now();
 }
 
diff --git a/cc/metrics/compositor_timing_history.h b/cc/metrics/compositor_timing_history.h
index 57b8c11..f6f8179 100644
--- a/cc/metrics/compositor_timing_history.h
+++ b/cc/metrics/compositor_timing_history.h
@@ -73,12 +73,11 @@
   void WillBeginImplFrame(const viz::BeginFrameArgs& args,
                           bool new_active_tree_is_likely,
                           base::TimeTicks now);
-  void WillFinishImplFrame(bool needs_redraw);
+  void WillFinishImplFrame(bool needs_redraw, const viz::BeginFrameId& id);
   void BeginImplFrameNotExpectedSoon();
-  void WillBeginMainFrame(bool on_critical_path,
-                          base::TimeTicks main_frame_time);
+  void WillBeginMainFrame(const viz::BeginFrameArgs& args);
   void BeginMainFrameStarted(base::TimeTicks main_thread_start_time);
-  void BeginMainFrameAborted();
+  void BeginMainFrameAborted(const viz::BeginFrameId& id);
   void NotifyReadyToCommit(std::unique_ptr<BeginMainFrameMetrics> details);
   void WillCommit();
   void DidCommit();
@@ -96,7 +95,10 @@
                bool current_frame_had_raf,
                bool next_frame_has_pending_raf,
                bool has_custom_property_animations);
-  void DidSubmitCompositorFrame(uint32_t frame_token);
+  void DidSubmitCompositorFrame(
+      uint32_t frame_token,
+      const viz::BeginFrameId& current_frame_id,
+      const viz::BeginFrameId& last_activated_frame_id);
   void DidReceiveCompositorFrameAck();
   void DidPresentCompositorFrame(uint32_t frame_token,
                                  const viz::FrameTimingDetails& details);
diff --git a/cc/metrics/compositor_timing_history_unittest.cc b/cc/metrics/compositor_timing_history_unittest.cc
index 695217c..7734463 100644
--- a/cc/metrics/compositor_timing_history_unittest.cc
+++ b/cc/metrics/compositor_timing_history_unittest.cc
@@ -59,7 +59,7 @@
                      int main_thread_animations_count,
                      bool current_frame_had_raf = false,
                      bool next_frame_has_pending_raf = false) {
-    timing_history_.WillBeginMainFrame(true, Now());
+    timing_history_.WillBeginMainFrame(getFakeBeginFrameArg());
     timing_history_.BeginMainFrameStarted(Now());
     timing_history_.WillCommit();
     timing_history_.DidCommit();
@@ -77,9 +77,10 @@
                      int composited_animations_count,
                      int main_thread_animations_count,
                      bool has_custom_property_animation) {
-    timing_history_.WillBeginMainFrame(true, Now());
+    viz::BeginFrameArgs args_ = getFakeBeginFrameArg();
+    timing_history_.WillBeginMainFrame(args_);
     timing_history_.BeginMainFrameStarted(Now());
-    timing_history_.BeginMainFrameAborted();
+    timing_history_.BeginMainFrameAborted(args_.frame_id);
     timing_history_.WillActivate();
     timing_history_.DidActivate();
     timing_history_.WillDraw();
@@ -94,6 +95,13 @@
   std::unique_ptr<CompositorFrameReportingController> reporting_controller_;
   TestCompositorTimingHistory timing_history_;
   base::TimeTicks now_;
+
+  viz::BeginFrameArgs getFakeBeginFrameArg(bool on_critical_path = true) {
+    viz::BeginFrameArgs args_ = viz::BeginFrameArgs();
+    args_.frame_time = Now();
+    args_.on_critical_path = on_critical_path;
+    return args_;
+  }
 };
 
 base::TimeTicks TestCompositorTimingHistory::Now() const {
@@ -118,7 +126,7 @@
   base::TimeDelta activate_duration = base::TimeDelta::FromMilliseconds(4);
   base::TimeDelta draw_duration = base::TimeDelta::FromMilliseconds(5);
 
-  timing_history_.WillBeginMainFrame(true, Now());
+  timing_history_.WillBeginMainFrame(getFakeBeginFrameArg());
   AdvanceNowBy(begin_main_frame_queue_duration);
   timing_history_.BeginMainFrameStarted(Now());
   AdvanceNowBy(begin_main_frame_start_to_ready_to_commit_duration);
@@ -172,12 +180,13 @@
   base::TimeDelta activate_duration = base::TimeDelta::FromMilliseconds(4);
   base::TimeDelta draw_duration = base::TimeDelta::FromMilliseconds(5);
 
-  timing_history_.WillBeginMainFrame(false, Now());
+  viz::BeginFrameArgs args_ = getFakeBeginFrameArg(false);
+  timing_history_.WillBeginMainFrame(args_);
   AdvanceNowBy(begin_main_frame_queue_duration);
   timing_history_.BeginMainFrameStarted(Now());
   AdvanceNowBy(begin_main_frame_start_to_ready_to_commit_duration);
   // BeginMainFrameAborted counts as a commit complete.
-  timing_history_.BeginMainFrameAborted();
+  timing_history_.BeginMainFrameAborted(args_.frame_id);
   timing_history_.WillPrepareTiles();
   AdvanceNowBy(prepare_tiles_duration);
   timing_history_.DidPrepareTiles();
@@ -213,17 +222,19 @@
   base::TimeDelta begin_main_frame_start_to_ready_to_commit_duration =
       base::TimeDelta::FromMilliseconds(1);
 
-  timing_history_.WillBeginMainFrame(true, Now());
+  viz::BeginFrameArgs args_ = getFakeBeginFrameArg();
+  timing_history_.WillBeginMainFrame(args_);
   AdvanceNowBy(begin_main_frame_queue_duration_critical);
   timing_history_.BeginMainFrameStarted(Now());
   AdvanceNowBy(begin_main_frame_start_to_ready_to_commit_duration);
-  timing_history_.BeginMainFrameAborted();
+  timing_history_.BeginMainFrameAborted(args_.frame_id);
 
-  timing_history_.WillBeginMainFrame(false, Now());
+  args_ = getFakeBeginFrameArg(false);
+  timing_history_.WillBeginMainFrame(args_);
   AdvanceNowBy(begin_main_frame_queue_duration_not_critical);
   timing_history_.BeginMainFrameStarted(Now());
   AdvanceNowBy(begin_main_frame_start_to_ready_to_commit_duration);
-  timing_history_.BeginMainFrameAborted();
+  timing_history_.BeginMainFrameAborted(args_.frame_id);
 
   // Since the critical BeginMainFrames are faster than non critical ones,
   // the expectations are straightforward.
@@ -245,21 +256,23 @@
       base::TimeDelta::FromMilliseconds(1);
 
   // A single critical frame that is slow.
-  timing_history_.WillBeginMainFrame(true, Now());
+  viz::BeginFrameArgs args_ = getFakeBeginFrameArg();
+  timing_history_.WillBeginMainFrame(args_);
   AdvanceNowBy(begin_main_frame_queue_duration_critical);
   timing_history_.BeginMainFrameStarted(Now());
   AdvanceNowBy(begin_main_frame_start_to_ready_to_commit_duration);
   // BeginMainFrameAborted counts as a commit complete.
-  timing_history_.BeginMainFrameAborted();
+  timing_history_.BeginMainFrameAborted(args_.frame_id);
 
   // A bunch of faster non critical frames that are newer.
   for (int i = 0; i < 100; i++) {
-    timing_history_.WillBeginMainFrame(false, Now());
+    args_ = getFakeBeginFrameArg(false);
+    timing_history_.WillBeginMainFrame(args_);
     AdvanceNowBy(begin_main_frame_queue_duration_not_critical);
     timing_history_.BeginMainFrameStarted(Now());
     AdvanceNowBy(begin_main_frame_start_to_ready_to_commit_duration);
     // BeginMainFrameAborted counts as a commit complete.
-    timing_history_.BeginMainFrameAborted();
+    timing_history_.BeginMainFrameAborted(args_.frame_id);
   }
 
   // Recent fast non critical BeginMainFrames should result in the
@@ -282,19 +295,21 @@
       base::TimeDelta::FromMilliseconds(1);
 
   // A single non critical frame that is fast.
-  timing_history_.WillBeginMainFrame(false, Now());
+  viz::BeginFrameArgs args_ = getFakeBeginFrameArg(false);
+  timing_history_.WillBeginMainFrame(args_);
   AdvanceNowBy(begin_main_frame_queue_duration_not_critical);
   timing_history_.BeginMainFrameStarted(Now());
   AdvanceNowBy(begin_main_frame_start_to_ready_to_commit_duration);
-  timing_history_.BeginMainFrameAborted();
+  timing_history_.BeginMainFrameAborted(args_.frame_id);
 
   // A bunch of slower critical frames that are newer.
   for (int i = 0; i < 100; i++) {
-    timing_history_.WillBeginMainFrame(true, Now());
+    args_ = getFakeBeginFrameArg();
+    timing_history_.WillBeginMainFrame(args_);
     AdvanceNowBy(begin_main_frame_queue_duration_critical);
     timing_history_.BeginMainFrameStarted(Now());
     AdvanceNowBy(begin_main_frame_start_to_ready_to_commit_duration);
-    timing_history_.BeginMainFrameAborted();
+    timing_history_.BeginMainFrameAborted(args_.frame_id);
   }
 
   // Recent slow critical BeginMainFrames should result in the
diff --git a/cc/mojom/BUILD.gn b/cc/mojom/BUILD.gn
index 7f648e69..03d1c93 100644
--- a/cc/mojom/BUILD.gn
+++ b/cc/mojom/BUILD.gn
@@ -6,11 +6,7 @@
 
 mojom("mojom") {
   generate_java = true
-  sources = [
-    "touch_action.mojom",
-  ]
+  sources = [ "touch_action.mojom" ]
 
-  public_deps = [
-    "//mojo/public/mojom/base",
-  ]
+  public_deps = [ "//mojo/public/mojom/base" ]
 }
diff --git a/cc/paint/BUILD.gn b/cc/paint/BUILD.gn
index a7536ba..7064a90 100644
--- a/cc/paint/BUILD.gn
+++ b/cc/paint/BUILD.gn
@@ -112,9 +112,7 @@
 }
 
 fuzzer_test("paint_op_buffer_fuzzer") {
-  sources = [
-    "paint_op_buffer_fuzzer.cc",
-  ]
+  sources = [ "paint_op_buffer_fuzzer.cc" ]
 
   libfuzzer_options = [ "max_len=4096" ]
 
@@ -128,9 +126,7 @@
 }
 
 fuzzer_test("transfer_cache_fuzzer") {
-  sources = [
-    "transfer_cache_fuzzer.cc",
-  ]
+  sources = [ "transfer_cache_fuzzer.cc" ]
 
   libfuzzer_options = [ "max_len=4096" ]
 
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 632c224..985890e 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -145,7 +145,9 @@
 }
 
 void Scheduler::DidSubmitCompositorFrame(uint32_t frame_token) {
-  compositor_timing_history_->DidSubmitCompositorFrame(frame_token);
+  compositor_timing_history_->DidSubmitCompositorFrame(
+      frame_token, begin_main_frame_args_.frame_id,
+      last_activate_origin_frame_args_.frame_id);
   state_machine_.DidSubmitCompositorFrame();
 
   // There is no need to call ProcessScheduledActions here because
@@ -186,7 +188,8 @@
 void Scheduler::BeginMainFrameAborted(CommitEarlyOutReason reason) {
   TRACE_EVENT1("cc", "Scheduler::BeginMainFrameAborted", "reason",
                CommitEarlyOutReasonToString(reason));
-  compositor_timing_history_->BeginMainFrameAborted();
+  compositor_timing_history_->BeginMainFrameAborted(
+      last_dispatched_begin_main_frame_args_.frame_id);
   state_machine_.BeginMainFrameAborted(reason);
   ProcessScheduledActions();
 }
@@ -564,8 +567,8 @@
   begin_main_frame_args_.on_critical_path = !ImplLatencyTakesPriority();
 
   BeginImplFrame(args, Now());
-  compositor_timing_history_->WillFinishImplFrame(
-      state_machine_.needs_redraw());
+  compositor_timing_history_->WillFinishImplFrame(state_machine_.needs_redraw(),
+                                                  args.frame_id);
   FinishImplFrame();
 }
 
@@ -720,7 +723,7 @@
   // * Creating a new OuputSurface will not occur during the deadline in
   //     order to allow the state machine to "settle" first.
   compositor_timing_history_->WillFinishImplFrame(
-      state_machine_.needs_redraw());
+      state_machine_.needs_redraw(), begin_main_frame_args_.frame_id);
   state_machine_.OnBeginImplFrameDeadline();
   ProcessScheduledActions();
   FinishImplFrame();
@@ -801,9 +804,7 @@
       case SchedulerStateMachine::Action::NONE:
         break;
       case SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME:
-        compositor_timing_history_->WillBeginMainFrame(
-            begin_main_frame_args_.on_critical_path,
-            begin_main_frame_args_.frame_time);
+        compositor_timing_history_->WillBeginMainFrame(begin_main_frame_args_);
         state_machine_.WillSendBeginMainFrame();
         client_->ScheduledActionSendBeginMainFrame(begin_main_frame_args_);
         last_dispatched_begin_main_frame_args_ = begin_main_frame_args_;
diff --git a/cc/test/fake_compositor_frame_reporting_controller.cc b/cc/test/fake_compositor_frame_reporting_controller.cc
index 1b8daa2..04e285f 100644
--- a/cc/test/fake_compositor_frame_reporting_controller.cc
+++ b/cc/test/fake_compositor_frame_reporting_controller.cc
@@ -10,21 +10,23 @@
     bool is_single_threaded)
     : CompositorFrameReportingController(is_single_threaded) {}
 
-void FakeCompositorFrameReportingController::WillBeginMainFrame() {
+void FakeCompositorFrameReportingController::WillBeginMainFrame(
+    const viz::BeginFrameId& id) {
   if (!reporters_[PipelineStage::kBeginImplFrame])
-    CompositorFrameReportingController::WillBeginImplFrame();
-  CompositorFrameReportingController::WillBeginMainFrame();
+    CompositorFrameReportingController::WillBeginImplFrame(id);
+  CompositorFrameReportingController::WillBeginMainFrame(id);
 }
 
-void FakeCompositorFrameReportingController::BeginMainFrameAborted() {
+void FakeCompositorFrameReportingController::BeginMainFrameAborted(
+    const viz::BeginFrameId& id) {
   if (!reporters_[PipelineStage::kBeginMainFrame])
-    WillBeginMainFrame();
-  CompositorFrameReportingController::BeginMainFrameAborted();
+    WillBeginMainFrame(id);
+  CompositorFrameReportingController::BeginMainFrameAborted(id);
 }
 
 void FakeCompositorFrameReportingController::WillCommit() {
   if (!reporters_[PipelineStage::kBeginMainFrame])
-    WillBeginMainFrame();
+    WillBeginMainFrame(viz::BeginFrameId());
   CompositorFrameReportingController::WillCommit();
 }
 
@@ -47,8 +49,11 @@
 }
 
 void FakeCompositorFrameReportingController::DidSubmitCompositorFrame(
-    uint32_t frame_token) {
-  CompositorFrameReportingController::DidSubmitCompositorFrame(frame_token);
+    uint32_t frame_token,
+    const viz::BeginFrameId& current_frame_id,
+    const viz::BeginFrameId& last_activated_frame_id) {
+  CompositorFrameReportingController::DidSubmitCompositorFrame(
+      frame_token, current_frame_id, last_activated_frame_id);
 
   viz::FrameTimingDetails details;
   details.presentation_feedback.timestamp = base::TimeTicks::Now();
diff --git a/cc/test/fake_compositor_frame_reporting_controller.h b/cc/test/fake_compositor_frame_reporting_controller.h
index 1a28bbb..0536f550f77 100644
--- a/cc/test/fake_compositor_frame_reporting_controller.h
+++ b/cc/test/fake_compositor_frame_reporting_controller.h
@@ -27,13 +27,16 @@
   FakeCompositorFrameReportingController& operator=(
       const FakeCompositorFrameReportingController& controller) = delete;
 
-  void WillBeginMainFrame() override;
-  void BeginMainFrameAborted() override;
+  void WillBeginMainFrame(const viz::BeginFrameId& id) override;
+  void BeginMainFrameAborted(const viz::BeginFrameId& id) override;
   void WillCommit() override;
   void DidCommit() override;
   void WillActivate() override;
   void DidActivate() override;
-  void DidSubmitCompositorFrame(uint32_t frame_token) override;
+  void DidSubmitCompositorFrame(
+      uint32_t frame_token,
+      const viz::BeginFrameId& current_frame_id,
+      const viz::BeginFrameId& last_activated_frame_id) override;
   void DidPresentCompositorFrame(
       uint32_t frame_token,
       const viz::FrameTimingDetails& details) override;
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 8c0a18c..1cd333e 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1711,6 +1711,7 @@
   "java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarAnimationCoordinator.java",
   "java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java",
   "java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarNewTabButton.java",
+  "java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarVariationManager.java",
   "java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarCoordinator.java",
   "java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarLinearLayout.java",
   "java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarMediator.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index edbac41..43ebe700 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -18,10 +18,8 @@
     "//third_party/android_deps:android_support_v7_appcompat_java",
   ]
 
-  sources = [
-    "java/src/org/chromium/chrome/browser/" +
-        "autofill_assistant/header/AnimatedPoodle.java",
-  ]
+  sources = [ "java/src/org/chromium/chrome/browser/" +
+              "autofill_assistant/header/AnimatedPoodle.java" ]
 }
 
 android_resources("animated_poodle_resources") {
@@ -200,9 +198,7 @@
 
 generate_jni("test_support_jni_headers") {
   testonly = true
-  sources = [
-    "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTestService.java",
-  ]
+  sources = [ "javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantTestService.java" ]
 }
 
 android_library("autofill_assistant_java_test_support") {
@@ -280,9 +276,7 @@
     "//ui/android:ui_full_java",
   ]
 
-  data = [
-    "//components/test/data/autofill_assistant/",
-  ]
+  data = [ "//components/test/data/autofill_assistant/" ]
 }
 
 android_resources("java_resources") {
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 338dc34..ffb33708 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
@@ -9,6 +9,7 @@
 import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.action.ViewActions.scrollTo;
 import static android.support.test.espresso.action.ViewActions.typeText;
+import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
 import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
@@ -20,6 +21,7 @@
 
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.getAbsoluteBoundingRect;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.startAutofillAssistant;
+import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewAssertionTrue;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition;
 import static org.chromium.chrome.browser.autofill_assistant.proto.ConfigureBottomSheetProto.PeekMode.HANDLE;
 import static org.chromium.chrome.browser.autofill_assistant.proto.ConfigureBottomSheetProto.PeekMode.HANDLE_HEADER;
@@ -47,8 +49,10 @@
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
+import org.chromium.chrome.browser.autofill_assistant.proto.ChipIcon;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipType;
+import org.chromium.chrome.browser.autofill_assistant.proto.ClientSettingsProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.CollectUserDataProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ConfigureBottomSheetProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ConfigureBottomSheetProto.PeekMode;
@@ -312,6 +316,71 @@
         onView(withText("Title 0")).perform(scrollTo()).check(matches(isDisplayed()));
     }
 
+    @Test
+    @MediumTest
+    public void testCancelSnackbarUndo() {
+        ArrayList<ActionProto> list = new ArrayList<>();
+        list.add((ActionProto) 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) 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));
+        startAutofillAssistant(mTestRule.getActivity(), testService);
+        waitUntilViewMatchesCondition(withText("Cancel"), isCompletelyDisplayed());
+
+        onView(withText("Cancel")).perform(click());
+        waitUntilViewMatchesCondition(withText(R.string.undo), isCompletelyDisplayed());
+        onView(withText("Cancel")).check(doesNotExist());
+        onView(withText(R.string.undo)).perform(click());
+        waitUntilViewMatchesCondition(withText("Cancel"), isDisplayed());
+    }
+
+    @Test
+    @MediumTest
+    public void testCancelSnackbarTimeout() {
+        ClientSettingsProto clientSettings = (ClientSettingsProto) ClientSettingsProto.newBuilder()
+                                                     .setCancelDelayMs(2000)
+                                                     .build();
+        ArrayList<ActionProto> list = new ArrayList<>();
+        list.add((ActionProto) 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) 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), clientSettings);
+        startAutofillAssistant(mTestRule.getActivity(), testService);
+        waitUntilViewMatchesCondition(withText("Cancel"), isCompletelyDisplayed());
+
+        onView(withText("Cancel")).perform(click());
+        waitUntilViewMatchesCondition(withText(R.string.undo), isCompletelyDisplayed());
+        onView(withText("Cancel")).check(doesNotExist());
+        waitUntilViewAssertionTrue(withText(R.string.undo), doesNotExist(), 3000L);
+        onView(withId(R.id.autofill_assistant)).check(doesNotExist());
+    }
+
     private ViewAction swipeDownToMinimize() {
         return actionWithAssertions(
                 new GeneralSwipeAction(Swipe.FAST, GeneralLocation.CENTER, view -> {
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
index 06321c8..0cbc39b 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiTestUtil.java
@@ -9,6 +9,9 @@
 
 import static org.hamcrest.MatcherAssert.assertThat;
 
+import static org.chromium.content_public.browser.test.util.CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL;
+import static org.chromium.content_public.browser.test.util.CriteriaHelper.DEFAULT_POLLING_INTERVAL;
+
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
@@ -19,6 +22,7 @@
 import android.support.test.espresso.NoMatchingViewException;
 import android.support.test.espresso.UiController;
 import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.ViewAssertion;
 import android.support.test.espresso.core.deps.guava.base.Preconditions;
 import android.support.test.espresso.matcher.BoundedMatcher;
 import android.text.SpannableString;
@@ -271,6 +275,12 @@
      */
     public static void waitUntilViewMatchesCondition(
             Matcher<View> matcher, Matcher<View> condition) {
+        waitUntilViewMatchesCondition(matcher, condition, DEFAULT_MAX_TIME_TO_POLL);
+    }
+
+    /** @see {@link #waitUntilViewMatchesCondition(Matcher, Matcher)} */
+    public static void waitUntilViewMatchesCondition(
+            Matcher<View> matcher, Matcher<View> condition, long maxTimeoutMs) {
         CriteriaHelper.pollInstrumentationThread(
                 new Criteria("Timeout while waiting for " + matcher + " to satisfy " + condition) {
                     @Override
@@ -284,7 +294,32 @@
                             return false;
                         }
                     }
-                });
+                },
+                maxTimeoutMs, DEFAULT_POLLING_INTERVAL);
+    }
+
+    /**
+     * Same as {@link #waitUntilViewMatchesCondition(Matcher, Matcher, long)}, but waits for a view
+     * assertion instead.
+     */
+    public static void waitUntilViewAssertionTrue(
+            Matcher<View> matcher, ViewAssertion viewAssertion, long maxTimeoutMs) {
+        CriteriaHelper.pollInstrumentationThread(
+                new Criteria(
+                        "Timeout while waiting for " + matcher + " to satisfy " + viewAssertion) {
+                    @Override
+                    public boolean isSatisfied() {
+                        try {
+                            onView(matcher).check(viewAssertion);
+                            return true;
+                        } catch (NoMatchingViewException | AssertionError e) {
+                            // Note: all other exceptions are let through, in particular
+                            // AmbiguousViewMatcherException.
+                            return false;
+                        }
+                    }
+                },
+                maxTimeoutMs, DEFAULT_POLLING_INTERVAL);
     }
 
     /**
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiTest.java
index ea959c51..5013974 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupPopupUiTest.java
@@ -48,6 +48,8 @@
 import org.chromium.chrome.browser.flags.FeatureUtilities;
 import org.chromium.chrome.browser.fullscreen.FullscreenManagerTestUtils;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager;
+import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager.Variations;
 import org.chromium.chrome.features.start_surface.StartSurfaceLayout;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -80,18 +82,12 @@
         FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true);
         FeatureUtilities.setIsBottomToolbarEnabledForTesting(true);
         FeatureUtilities.setDuetTabStripIntegrationAndroidEnabledForTesting(true);
-        mActivityTestRule.startMainActivityFromLauncher();
-        Layout layout = mActivityTestRule.getActivity().getLayoutManager().getOverviewLayout();
-        assertTrue(layout instanceof StartSurfaceLayout);
-        CriteriaHelper.pollUiThread(mActivityTestRule.getActivity()
-                                            .getTabModelSelector()
-                                            .getTabModelFilterProvider()
-                                            .getCurrentTabModelFilter()::isTabModelRestored);
     }
 
     @Test
     @MediumTest
-    public void testOnAnchorViewChanged() throws InterruptedException {
+    public void testOnAnchorViewChanged_HOME_SEARCH_TAB_SWITCHER() throws InterruptedException {
+        launchActivity(Variations.HOME_SEARCH_TAB_SWITCHER);
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
         // Tab strip should show automatically when entering tab group.
         createTabGroupAndEnterTabPage(cta, 2, null);
@@ -111,7 +107,50 @@
 
     @Test
     @MediumTest
+    public void testOnAnchorViewChanged_HOME_SEARCH_SHARE() throws InterruptedException {
+        launchActivity(Variations.HOME_SEARCH_SHARE);
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        // Tab strip should show automatically when entering tab group.
+        createTabGroupAndEnterTabPage(cta, 2, null);
+        CriteriaHelper.pollInstrumentationThread(() -> isAnchoredOnTopToolbar(cta));
+        verifyShowingTabStrip(cta, 2);
+
+        // In portrait mode, tab strip should anchor on bottom toolbar; in landscape mode, bottom
+        // toolbar hides and tab strip should anchor on top toolbar.
+        rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
+        CriteriaHelper.pollInstrumentationThread(() -> isAnchoredOnTopToolbar(cta));
+        verifyShowingTabStrip(cta, 2);
+
+        rotateDeviceToOrientation(cta, Configuration.ORIENTATION_PORTRAIT);
+        CriteriaHelper.pollInstrumentationThread(() -> isAnchoredOnTopToolbar(cta));
+        verifyShowingTabStrip(cta, 2);
+    }
+
+    @Test
+    @MediumTest
+    public void testOnAnchorViewChanged_NEW_TAB_SEARCH_SHARE() throws InterruptedException {
+        launchActivity(Variations.NEW_TAB_SEARCH_SHARE);
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        // Tab strip should show automatically when entering tab group.
+        createTabGroupAndEnterTabPage(cta, 2, null);
+        CriteriaHelper.pollInstrumentationThread(() -> isAnchoredOnTopToolbar(cta));
+        verifyShowingTabStrip(cta, 2);
+
+        // In portrait mode, tab strip should anchor on bottom toolbar; in landscape mode, bottom
+        // toolbar hides and tab strip should anchor on top toolbar.
+        rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
+        CriteriaHelper.pollInstrumentationThread(() -> isAnchoredOnTopToolbar(cta));
+        verifyShowingTabStrip(cta, 2);
+
+        rotateDeviceToOrientation(cta, Configuration.ORIENTATION_PORTRAIT);
+        CriteriaHelper.pollInstrumentationThread(() -> isAnchoredOnTopToolbar(cta));
+        verifyShowingTabStrip(cta, 2);
+    }
+
+    @Test
+    @MediumTest
     public void testTabStripShowHide() throws InterruptedException {
+        launchActivity();
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
         // Try to trigger tab strip in a single tab page.
         triggerTabStripAndVerify(cta, 0);
@@ -144,6 +183,7 @@
     @Test
     @MediumTest
     public void testTabStripUpdate() throws InterruptedException {
+        launchActivity();
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
 
         // Tab strip should show automatically when entering tab group.
@@ -180,6 +220,7 @@
     @MediumTest
     @CommandLineFlags.Add({ChromeSwitches.DISABLE_MINIMUM_SHOW_DURATION})
     public void testTabStripChangeWithScrolling() throws InterruptedException {
+        launchActivity();
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
         FullscreenManagerTestUtils.disableBrowserOverrides();
 
@@ -287,4 +328,19 @@
                                      .getRelatedTabList(currentTab.getId());
         return tabGroup.indexOf(currentTab);
     }
+
+    private void launchActivity() {
+        launchActivity(Variations.HOME_SEARCH_TAB_SWITCHER);
+    }
+
+    private void launchActivity(@Variations String variation) {
+        BottomToolbarVariationManager.setVariation(variation);
+        mActivityTestRule.startMainActivityFromLauncher();
+        Layout layout = mActivityTestRule.getActivity().getLayoutManager().getOverviewLayout();
+        assertTrue(layout instanceof StartSurfaceLayout);
+        CriteriaHelper.pollUiThread(mActivityTestRule.getActivity()
+                                            .getTabModelSelector()
+                                            .getTabModelFilterProvider()
+                                            .getCurrentTabModelFilter()::isTabModelRestored);
+    }
 }
diff --git a/chrome/android/java/res/layout/bottom_toolbar_browsing.xml b/chrome/android/java/res/layout/bottom_toolbar_browsing.xml
index 046cf2e0..e218e1d 100644
--- a/chrome/android/java/res/layout/bottom_toolbar_browsing.xml
+++ b/chrome/android/java/res/layout/bottom_toolbar_browsing.xml
@@ -16,23 +16,25 @@
     android:paddingStart="@dimen/bottom_toolbar_padding"
     android:paddingEnd="@dimen/bottom_toolbar_padding" >
 
+    <include layout="@layout/toolbar_space" />
+
     <org.chromium.chrome.browser.toolbar.HomeButton
-        android:id="@+id/home_button"
+        android:id="@+id/bottom_home_button"
         app:tint="@color/standard_mode_tint"
         android:background="?attr/selectableItemBackgroundBorderless"
         android:contentDescription="@string/accessibility_toolbar_btn_home"
+        android:visibility="gone"
+        style="@style/SplitToolbarButton" />
+
+    <org.chromium.chrome.browser.toolbar.bottom.BottomToolbarNewTabButton
+        android:id="@+id/bottom_new_tab_button"
+        android:contentDescription="@string/accessibility_toolbar_btn_new_tab"
+        app:tint="@color/standard_mode_tint"
+        app:srcCompat="@drawable/new_tab_icon"
+        android:visibility="gone"
         style="@style/SplitToolbarButton" />
 
     <include layout="@layout/toolbar_space" />
-
-    <org.chromium.chrome.browser.toolbar.bottom.ShareButton
-        android:id="@+id/share_button"
-        android:src="@drawable/ic_share_white_24dp"
-        app:tint="@color/standard_mode_tint"
-        android:contentDescription="@string/share"
-        android:background="?attr/selectableItemBackgroundBorderless"
-        style="@style/SplitToolbarButton" />
-
     <include layout="@layout/toolbar_space" />
 
     <org.chromium.chrome.browser.toolbar.bottom.SearchAccelerator
@@ -48,19 +50,26 @@
         android:src="@drawable/ic_search"/>
 
     <include layout="@layout/toolbar_space" />
+    <include layout="@layout/toolbar_space" />
 
     <org.chromium.chrome.browser.toolbar.TabSwitcherButtonView
-        android:id="@+id/tab_switcher_button"
+        android:id="@+id/bottom_tab_switcher_button"
         style="@style/SplitToolbarButton"
         app:menuMaxWidth="@dimen/tab_switcher_menu_width"
+        android:visibility="gone"
         android:background="?attr/selectableItemBackgroundBorderless"
         android:contentDescription="@string/accessibility_toolbar_btn_tabswitcher_toggle_default"
         app:menuVerticalOverlapAnchor="false" />
 
-    <include layout="@layout/toolbar_space" />
+    <org.chromium.chrome.browser.toolbar.bottom.ShareButton
+        android:id="@+id/bottom_share_button"
+        android:src="@drawable/ic_share_white_24dp"
+        app:tint="@color/standard_mode_tint"
+        android:visibility="gone"
+        android:background="?attr/selectableItemBackgroundBorderless"
+        android:contentDescription="@string/share"
+        style="@style/SplitToolbarButton" />
 
-    <include
-        style="@style/SplitToolbarButton"
-        layout="@layout/bottom_toolbar_menu_button" />
+    <include layout="@layout/toolbar_space" />
 
 </org.chromium.chrome.browser.toolbar.bottom.BrowsingModeBottomToolbarLinearLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 9e09129..71def33 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1288,7 +1288,7 @@
     public SnackbarManager getSnackbarManager() {
         if (mRootUiCoordinator != null && getBottomSheetController() != null
                 && getBottomSheetController().isSheetOpen()
-                && getBottomSheetController().isSheetHiding()) {
+                && !getBottomSheetController().isSheetHiding()) {
             return mRootUiCoordinator.getBottomSheetSnackbarManager();
         }
         return mSnackbarManager;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateImpl.java
index 1f65fe6..79faee2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateImpl.java
@@ -206,9 +206,9 @@
                     || mDecorView.getWidth()
                             < DeviceFormFactor.getNonMultiDisplayMinimumTabletWidthPx(mContext);
 
-            final boolean bottomToolbarVisible =
-                    mToolbarManager != null && mToolbarManager.isBottomToolbarVisible();
-            shouldShowIconRow &= !bottomToolbarVisible;
+            final boolean isMenuButtonOnTop =
+                    mToolbarManager != null && !mToolbarManager.isMenuFromBottom();
+            shouldShowIconRow &= isMenuButtonOnTop;
 
             // Update the icon row items (shown in narrow form factors).
             menu.findItem(R.id.icon_row_menu_id).setVisible(shouldShowIconRow);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java
index 76500b7..320617b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.CloseButtonVisibilityManager;
@@ -38,7 +39,9 @@
     private final CloseButtonVisibilityManager mCloseButtonVisibilityManager;
 
     private boolean mInTwaMode;
-    private boolean mHideBrowserControlsInTwaMode;
+    private boolean mShowBrowserControlsInTwaMode;
+    private boolean mShowBrowserControlsForChildTab;
+
     private @BrowserControlsState int mBrowserControlsState = DEFAULT_BROWSER_CONTROLS_STATE;
 
     private final TabObserver mTabObserver = new EmptyTabObserver() {
@@ -70,9 +73,9 @@
         mCloseButtonVisibilityManager = closeButtonVisibilityManager;
 
         WebappExtras webappExtras = intentDataProvider.getWebappExtras();
-        mHideBrowserControlsInTwaMode =
-                (webappExtras == null || webappExtras.displayMode == WebDisplayMode.FULLSCREEN
-                        || webappExtras.displayMode == WebDisplayMode.STANDALONE);
+        mShowBrowserControlsForChildTab = (webappExtras != null);
+        mShowBrowserControlsInTwaMode =
+                (webappExtras != null && webappExtras.displayMode == WebDisplayMode.MINIMAL_UI);
     }
 
     /**
@@ -114,12 +117,17 @@
         // Show close button if toolbar is not visible, so that during the in and off-scope
         // transitions we avoid button flickering when toolbar is appearing/disappearing.
         boolean closeButtonVisibility =
-                !mInTwaMode || (mBrowserControlsState == BrowserControlsState.HIDDEN);
+                shouldShowBrowserControlsAndCloseButton(mTabProvider.getTab())
+                || (mBrowserControlsState == BrowserControlsState.HIDDEN);
 
         mCloseButtonVisibilityManager.setVisibility(closeButtonVisibility);
     }
 
-    private @BrowserControlsState int computeBrowserControlsState(Tab tab) {
+    private boolean shouldShowBrowserControlsAndCloseButton(@Nullable Tab tab) {
+        return !mInTwaMode || (isChildTab(tab) && mShowBrowserControlsForChildTab);
+    }
+
+    private @BrowserControlsState int computeBrowserControlsState(@Nullable Tab tab) {
         // Force browser controls to show when the security level is dangerous for consistency with
         // TabStateBrowserControlsVisibilityDelegate.
         if (tab != null
@@ -127,7 +135,15 @@
             return BrowserControlsState.SHOWN;
         }
 
-        return mInTwaMode && mHideBrowserControlsInTwaMode ? BrowserControlsState.HIDDEN
-                                                           : BrowserControlsState.BOTH;
+        if (mInTwaMode && mShowBrowserControlsInTwaMode) {
+            return BrowserControlsState.BOTH;
+        }
+
+        return shouldShowBrowserControlsAndCloseButton(tab) ? BrowserControlsState.BOTH
+                                                            : BrowserControlsState.HIDDEN;
+    }
+
+    private boolean isChildTab(@Nullable Tab tab) {
+        return tab != null && tab.getParentId() != Tab.INVALID_TAB_ID;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigator.java
index da28402..66cf9b8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigator.java
@@ -6,7 +6,9 @@
 
 import androidx.annotation.Nullable;
 
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.browserservices.BrowserServicesActivityTabController;
+import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
 import org.chromium.chrome.browser.tab.Tab;
@@ -17,12 +19,18 @@
 import javax.inject.Inject;
 
 /**
- * Allows navigation to the most recent page that matches a criteria when the Custom Tabs close
- * button is pressed. We call this page the landing page.
+ * Closes the tab or navigates back when the Custom Tabs close button is pressed. The algorithm
+ * depends on whether the tab is a child tab - {@link Tab#getParentId()} != Tab.INVALID_TAB_ID.
  *
- * For example, in Trusted Web Activities we only show the close button when the user has left the
- * verified origin. If the user then pressed the close button, we want to navigate back to the
- * verified origin instead of closing the Activity.
+ * If the tab is not a child tab:
+ * Navigates to the most recent page which matches a criteria. We call this page the landing page.
+ * For instance, Trusted Web Activities show the close button when the user has left the verified
+ * origin. If the user then presses the close button, we want to navigate back to the verified
+ * origin instead of closing the Activity.
+ *
+ * If the tab is a child tab:
+ * Webapps: Closes the current tab
+ * Other: Same algorithm as non-child tabs.
  *
  * Thread safety: Should only be called on UI thread.
  * Native: Requires native.
@@ -32,12 +40,15 @@
     @Nullable private PageCriteria mLandingPageCriteria;
     private final BrowserServicesActivityTabController mTabController;
     private final CustomTabActivityTabProvider mTabProvider;
+    private final boolean mButtonClosesChildTab;
 
     @Inject
     public CloseButtonNavigator(BrowserServicesActivityTabController tabController,
-            CustomTabActivityTabProvider tabProvider) {
+            CustomTabActivityTabProvider tabProvider,
+            BrowserServicesIntentDataProvider intentDataProvider) {
         mTabController = tabController;
         mTabProvider = tabProvider;
+        mButtonClosesChildTab = (intentDataProvider.getWebappExtras() != null);
     }
 
     // TODO(peconn): Replace with Predicate<T> when we can use Java 8 libraries.
@@ -59,27 +70,43 @@
     }
 
     /**
-     * Handles navigation and Tab closures that should occur when the close button is pressed. It
-     * searches for a landing page in the history of the current Tab and then closes it if none are
-     * found. This continues until a landing page is found or all Tabs are closed.
+     * Handles navigation and Tab closures that should occur when the close button is pressed.
      */
     public void navigateOnClose() {
+        // If the tab is a child tab and |mButtonClosesChildTab| == true, close the child tab.
+        Tab currentTab = mTabProvider.getTab();
+        boolean isFromChildTab =
+                (currentTab != null && currentTab.getParentId() != Tab.INVALID_TAB_ID);
+        if (isFromChildTab && mButtonClosesChildTab) {
+            mTabController.closeTab();
+            return;
+        }
+
+        // Search for a landing page in the history of the current Tab and then close if if none
+        // found. Continue until a landing page is found or all Tabs are closed.
+        int numTabsClosed = 0;
         while (mTabProvider.getTab() != null) {
             // See if there's a close button navigation in our current Tab.
             NavigationController navigationController = getNavigationController();
             if (navigationController != null && navigateSingleTab(getNavigationController())) {
+                if (isFromChildTab) {
+                    recordChildTabScopeAlgorithmClosesOneTab(false);
+                }
                 return;
             }
 
             mTabController.closeTab();
+            ++numTabsClosed;
 
             // Check whether the close button navigation would have stopped on the newly revealed
             // Tab. We don't check this at the start of the loop (or make navigateSingleTab
             // consider the current Tab) because in that case if the user started on a landing page,
-            // we would not navigate at all. (Admittedly though this case would never happen at the
-            // time of writing since landing pages don't show the close button).
+            // we would not navigate at all.
             Tab nextTab = mTabProvider.getTab();
-            if (nextTab != null && isLandingPage(mTabProvider.getTab().getUrl())) {
+            if (nextTab != null && isLandingPage(nextTab.getUrl())) {
+                if (isFromChildTab) {
+                    recordChildTabScopeAlgorithmClosesOneTab(numTabsClosed == 1);
+                }
                 return;
             }
         }
@@ -104,6 +131,16 @@
         return false;
     }
 
+    /**
+     * Records how often the "navigate to landing page" algorithm for child tabs for Custom Tabs and
+     * Trusted Web Activities produces the same behaviour as the webapp "close current tab"
+     * algorithm.
+     */
+    private void recordChildTabScopeAlgorithmClosesOneTab(boolean closesOneTab) {
+        RecordHistogram.recordBooleanHistogram(
+                "CustomTabs.CloseButton.ChildTab.ScopeAlgorithm.ClosesOneTab", closesOneTab);
+    }
+
     @Nullable
     private NavigationController getNavigationController() {
         Tab tab = mTabProvider.getTab();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/flags/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/flags/FeatureUtilities.java
index cd63daa..73e4ef4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/flags/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/flags/FeatureUtilities.java
@@ -28,6 +28,7 @@
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider;
+import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager;
 import org.chromium.ui.base.DeviceFormFactor;
 
 import java.util.HashMap;
@@ -219,6 +220,16 @@
     public static void cacheBottomToolbarEnabled() {
         cacheFlag(ChromePreferenceKeys.FLAGS_CACHED_BOTTOM_TOOLBAR_ENABLED,
                 ChromeFeatureList.CHROME_DUET);
+        cacheBottomToolbarVariation();
+    }
+
+    /**
+     * Cache the enabled bottom toolbar variation.
+     */
+    public static void cacheBottomToolbarVariation() {
+        cacheVariation(ChromePreferenceKeys.VARIATION_CACHED_BOTTOM_TOOLBAR,
+                ChromeFeatureList.CHROME_DUET,
+                BottomToolbarVariationManager.getVariationParamName());
     }
 
     /**
@@ -265,6 +276,15 @@
     }
 
     /**
+     * @return The currently enabled bottom toolbar variation.
+     */
+    public static String getBottomToolbarVariation() {
+        return SharedPreferencesManager.getInstance().readString(
+                ChromePreferenceKeys.VARIATION_CACHED_BOTTOM_TOOLBAR,
+                BottomToolbarVariationManager.Variations.NONE);
+    }
+
+    /**
      * Set whether the bottom toolbar is enabled for tests. Reset to null at the end of tests.
      */
     @VisibleForTesting
@@ -731,6 +751,12 @@
                 preferenceName, ChromeFeatureList.isEnabled(featureName));
     }
 
+    private static void cacheVariation(
+            String preferenceName, String featureName, String variationName) {
+        SharedPreferencesManager.getInstance().writeString(preferenceName,
+                ChromeFeatureList.getFieldTrialParamByFeature(featureName, variationName));
+    }
+
     private static boolean isFlagEnabled(String preferenceName, boolean defaultValue) {
         Boolean flag = sFlags.get(preferenceName);
         if (flag == null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
index cbdf8c6..6561531 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/WebApkUma.java
@@ -354,9 +354,13 @@
 
     /**
      * Records whether a WebAPK navigation is within the WebAPK's scope.
+     * @param isChildTab Whether {@link Tab#getParentId()} is non-empty.
+     * @param isNavigationInScope
      */
-    public static void recordNavigation(boolean isNavigationInScope) {
-        RecordHistogram.recordBooleanHistogram("WebApk.Navigation.InScope", isNavigationInScope);
+    public static void recordNavigation(boolean isChildTab, boolean isNavigationInScope) {
+        RecordHistogram.recordBooleanHistogram(
+                isChildTab ? "WebApk.Navigation.ChildTab.InScope" : "WebApk.Navigation.InScope",
+                isNavigationInScope);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceMetrics.java
index 23e47f2..1d4d05a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceMetrics.java
@@ -7,8 +7,9 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.components.search_engines.TemplateUrl;
 import org.chromium.components.search_engines.TemplateUrlService;
 
@@ -17,10 +18,6 @@
 
 /** Hosts common code for search engine choice metrics reporting. */
 public class SearchEngineChoiceMetrics {
-    /** Key used to store the default Search Engine Type before choice is presented. */
-    @VisibleForTesting
-    public static final String PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE =
-            "search_engine_choice_default_type_before";
 
     /**
      * AndroidSearchEngineChoiceEvents defined in tools/metrics/histograms/enums.xml. These values
@@ -112,25 +109,23 @@
 
     /** @return True if the current search engine is possibly different from the previous one. */
     static boolean isSearchEnginePossiblyDifferent() {
-        return ContextUtils.getAppSharedPreferences().contains(
-                PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE);
+        return SharedPreferencesManager.getInstance().contains(
+                ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE);
     }
 
     /** Remove the stored choice from prefs. */
     @VisibleForTesting
     static void removePreviousSearchEngineType() {
-        ContextUtils.getAppSharedPreferences()
-                .edit()
-                .remove(PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE)
-                .apply();
+        SharedPreferencesManager.getInstance().removeKey(
+                ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE);
     }
 
     /** Retrieves the previously set search engine from Android prefs. */
     @VisibleForTesting
     @SearchEngineType
     static int getPreviousSearchEngineType() {
-        return ContextUtils.getAppSharedPreferences().getInt(
-                PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE,
+        return SharedPreferencesManager.getInstance().readInt(
+                ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE,
                 SearchEngineType.SEARCH_ENGINE_UNKNOWN);
     }
 
@@ -139,10 +134,8 @@
      */
     @VisibleForTesting
     static void setPreviousSearchEngineType(@SearchEngineType int engine) {
-        ContextUtils.getAppSharedPreferences()
-                .edit()
-                .putInt(PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE, engine)
-                .apply();
+        SharedPreferencesManager.getInstance().writeInt(
+                ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE, engine);
     }
 
     /** Translates from the default search engine url to the {@link SearchEngineType} int. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
index 86226346..ffe14b9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
@@ -8,11 +8,12 @@
 
 import androidx.annotation.Nullable;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.omaha.VersionNumber;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.settings.SettingsLauncher;
 import org.chromium.chrome.browser.settings.search_engine.SearchEngineSettings;
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
@@ -23,16 +24,9 @@
 
 /**
  * Class that prompts the user to change their search engine at the browser startup.
- * User is only meant to be propmpted once, hence the fact of prompting is saved to preferences.
+ * User is only meant to be prompted once, hence the fact of prompting is saved to preferences.
  */
 public final class SearchEngineChoiceNotification {
-    /** Key used to store the date of when search engine choice was requested. */
-    static final String PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP =
-            "search_engine_choice_requested_timestamp";
-
-    /** Key used to store the version of Chrome in which the choice was presented. */
-    static final String PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION =
-            "search_engine_choice_presented_version";
 
     /** Variations parameter name for notification snackbar duration (in seconds). */
     private static final String PARAM_NOTIFICATION_SNACKBAR_DURATION_SECONDS =
@@ -117,23 +111,19 @@
 
     private static void updateSearchEngineChoiceRequested() {
         long now = System.currentTimeMillis();
-        ContextUtils.getAppSharedPreferences()
-                .edit()
-                .putLong(PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP, now)
-                .apply();
+        SharedPreferencesManager.getInstance().writeLong(
+                ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP, now);
     }
 
     private static boolean wasSearchEngineChoiceRequested() {
-        return ContextUtils.getAppSharedPreferences().contains(
-                PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP);
+        return SharedPreferencesManager.getInstance().contains(
+                ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP);
     }
 
     private static void updateSearchEngineChoicePresented() {
         String productVersion = ChromeVersionInfo.getProductVersion();
-        ContextUtils.getAppSharedPreferences()
-                .edit()
-                .putString(PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION, productVersion)
-                .apply();
+        SharedPreferencesManager.getInstance().writeString(
+                ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_PRESENTED_VERSION, productVersion);
     }
 
     private static boolean wasSearchEngineChoicePresented() {
@@ -148,8 +138,8 @@
 
     @Nullable
     private static VersionNumber getLastPresentedVersionNumber() {
-        return VersionNumber.fromString(ContextUtils.getAppSharedPreferences().getString(
-                PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION, null));
+        return VersionNumber.fromString(SharedPreferencesManager.getInstance().readString(
+                ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_PRESENTED_VERSION, null));
     }
 
     @Nullable
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/sync/ManageSyncPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/sync/ManageSyncPreferences.java
index 4ac8dd4..f52e34e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/sync/ManageSyncPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/sync/ManageSyncPreferences.java
@@ -32,12 +32,14 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.settings.ChromeSwitchPreference;
 import org.chromium.chrome.browser.settings.SettingsUtils;
+import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.sync.TrustedVaultClient;
 import org.chromium.chrome.browser.sync.ui.PassphraseCreationDialogFragment;
 import org.chromium.chrome.browser.sync.ui.PassphraseDialogFragment;
 import org.chromium.chrome.browser.sync.ui.PassphraseTypeDialogFragment;
 import org.chromium.components.signin.ChromeSigninController;
+import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.sync.ModelType;
 import org.chromium.components.sync.PassphraseType;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
@@ -214,6 +216,8 @@
      * from this state.
      */
     private void updateSyncPreferences() {
+        // TODO(crbug.com/1041815): Migrate away from ChromeSigninController and use IdentityManager
+        // instead.
         String signedInAccountName = ChromeSigninController.get().getSignedInAccountName();
         if (signedInAccountName == null) {
             // May happen if account is removed from the device while this screen is shown.
@@ -403,7 +407,12 @@
         if (mProfileSyncService.isPassphraseRequiredForPreferredDataTypes()) {
             displayPassphraseDialog();
         } else if (mProfileSyncService.isTrustedVaultKeyRequiredForPreferredDataTypes()) {
-            TrustedVaultClient.get().displayKeyRetrievalDialog(getContext());
+            CoreAccountInfo primaryAccountInfo =
+                    IdentityServicesProvider.get().getIdentityManager().getPrimaryAccountInfo();
+            if (primaryAccountInfo != null) {
+                TrustedVaultClient.get().displayKeyRetrievalDialog(
+                        getActivity(), primaryAccountInfo);
+            }
         } else {
             displayPassphraseTypeDialog();
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/sync/SyncAndServicesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/sync/SyncAndServicesPreferences.java
index 286a864..078369f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/sync/SyncAndServicesPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/sync/SyncAndServicesPreferences.java
@@ -65,6 +65,7 @@
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.ChromeSigninController;
+import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.metrics.SigninAccessPoint;
 import org.chromium.components.signin.metrics.SignoutReason;
 import org.chromium.components.sync.AndroidSyncSettings;
@@ -334,6 +335,8 @@
         mProfileSyncService.addSyncStateChangedListener(this);
         mSigninPreference.registerForUpdates();
 
+        // TODO(crbug.com/1041815): Migrate away from ChromeSigninController and use IdentityManager
+        // instead.
         if (!mIsFromSigninScreen || ChromeSigninController.get().isSignedIn()) {
             return;
         }
@@ -570,6 +573,8 @@
         }
 
         if (mCurrentSyncError == SyncError.AUTH_ERROR) {
+            // TODO(crbug.com/1041815): Migrate away from ChromeSigninController and use
+            // IdentityManager instead.
             AccountManagerFacade.get().updateCredentials(
                     ChromeSigninController.get().getSignedInUser(), getActivity(), null);
             return;
@@ -585,6 +590,8 @@
         }
 
         if (mCurrentSyncError == SyncError.OTHER_ERRORS) {
+            // TODO(crbug.com/1041815): Migrate away from ChromeSigninController and use
+            // IdentityManager instead.
             final Account account = ChromeSigninController.get().getSignedInUser();
             // TODO(https://crbug.com/873116): Pass the correct reason for the signout.
             IdentityServicesProvider.get().getSigninManager().signOut(
@@ -603,7 +610,12 @@
 
         if (mCurrentSyncError == SyncError.TRUSTED_VAULT_KEY_REQUIRED_FOR_EVERYTHING
                 || mCurrentSyncError == SyncError.TRUSTED_VAULT_KEY_REQUIRED_FOR_PASSWORDS) {
-            TrustedVaultClient.get().displayKeyRetrievalDialog(getContext());
+            CoreAccountInfo primaryAccountInfo =
+                    IdentityServicesProvider.get().getIdentityManager().getPrimaryAccountInfo();
+            if (primaryAccountInfo != null) {
+                TrustedVaultClient.get().displayKeyRetrievalDialog(
+                        getActivity(), primaryAccountInfo);
+            }
             return;
         }
     }
@@ -645,6 +657,8 @@
             closeDialogIfOpen(FRAGMENT_ENTER_PASSPHRASE);
         }
 
+        // TODO(crbug.com/1041815): Migrate away from ChromeSigninController and use IdentityManager
+        // instead.
         if (!ChromeSigninController.get().isSignedIn()) {
             getPreferenceScreen().removePreference(mManageYourGoogleAccount);
             getPreferenceScreen().removePreference(mSyncCategory);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
index 5671ac7..33e001e8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncNotificationController.java
@@ -24,8 +24,10 @@
 import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
 import org.chromium.chrome.browser.settings.SettingsLauncher;
 import org.chromium.chrome.browser.settings.sync.SyncAndServicesPreferences;
+import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.chrome.browser.sync.GoogleServiceAuthError.State;
 import org.chromium.chrome.browser.sync.ui.PassphraseActivity;
+import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.sync.AndroidSyncSettings;
 import org.chromium.components.sync.PassphraseType;
 
@@ -84,12 +86,17 @@
             }
         } else if (mProfileSyncService.isEngineInitialized()
                 && mProfileSyncService.isTrustedVaultKeyRequiredForPreferredDataTypes()) {
-            Intent intent = TrustedVaultClient.get().createKeyRetrievalIntent();
-            if (intent != null) {
-                showSyncNotification(mProfileSyncService.isEncryptEverythingEnabled()
-                                ? R.string.sync_error_card_title
-                                : R.string.sync_passwords_error_card_title,
-                        intent);
+            CoreAccountInfo primaryAccountInfo =
+                    IdentityServicesProvider.get().getIdentityManager().getPrimaryAccountInfo();
+            if (primaryAccountInfo != null) {
+                Intent intent =
+                        TrustedVaultClient.get().createKeyRetrievalIntent(primaryAccountInfo);
+                if (intent != null) {
+                    showSyncNotification(mProfileSyncService.isEncryptEverythingEnabled()
+                                    ? R.string.sync_error_card_title
+                                    : R.string.sync_passwords_error_card_title,
+                            intent);
+                }
             }
         } else {
             mNotificationManager.cancel(NotificationConstants.NOTIFICATION_ID_SYNC);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/TrustedVaultClient.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/TrustedVaultClient.java
index a56990a..8fee1d4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/TrustedVaultClient.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/TrustedVaultClient.java
@@ -15,6 +15,7 @@
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.util.IntentUtils;
+import org.chromium.components.signin.base.CoreAccountInfo;
 
 import java.util.Collections;
 import java.util.List;
@@ -32,29 +33,30 @@
         /**
          * Reads and returns available encryption keys without involving any user action.
          *
-         * @param gaiaId String representation of the Gaia ID.
+         * @param accountInfo Account representing the user.
          * @return a promise with known keys, if any, where the last one is the most recent.
          */
-        Promise<List<byte[]>> fetchKeys(String gaiaId);
+        Promise<List<byte[]>> fetchKeys(CoreAccountInfo accountInfo);
 
         /**
          * Gets an Intent that can be used to display a UI that allows the user to reauthenticate
          * and retrieve the sync encryption keys.
          *
+         * @param accountInfo Account representing the user.
          * @return the Intent object or null is something went wrong.
          */
         @Nullable
-        Intent createKeyRetrievalIntent();
+        Intent createKeyRetrievalIntent(CoreAccountInfo accountInfo);
 
         /**
          * Invoked when the result of fetchKeys() represents keys that cannot decrypt Nigori, which
          * should only be possible if the provided keys are not up-to-date.
          *
-         * @param gaiaId String representation of the Gaia ID.
+         * @param accountInfo Account representing the user.
          * @return a promise which indicates completion and also represents whether the operation
          * took any effect (false positives acceptable).
          */
-        Promise<Boolean> markKeysAsStale(String gaiaId);
+        Promise<Boolean> markKeysAsStale(CoreAccountInfo accountInfo);
     }
 
     /**
@@ -62,17 +64,17 @@
      */
     public static class EmptyBackend implements Backend {
         @Override
-        public Promise<List<byte[]>> fetchKeys(String gaiaId) {
+        public Promise<List<byte[]>> fetchKeys(CoreAccountInfo accountInfo) {
             return Promise.fulfilled(Collections.emptyList());
         }
 
         @Override
-        public Intent createKeyRetrievalIntent() {
+        public Intent createKeyRetrievalIntent(CoreAccountInfo accountInfo) {
             return null;
         }
 
         @Override
-        public Promise<Boolean> markKeysAsStale(String gaiaId) {
+        public Promise<Boolean> markKeysAsStale(CoreAccountInfo accountInfo) {
             return Promise.fulfilled(false);
         }
     };
@@ -103,9 +105,12 @@
 
     /**
      * Displays a UI that allows the user to reauthenticate and retrieve the sync encryption keys.
+     *
+     * @param context Context to use when starting the dialog activity.
+     * @param accountInfo Account representing the user.
      */
-    public void displayKeyRetrievalDialog(Context context) {
-        Intent intent = createKeyRetrievalIntent();
+    public void displayKeyRetrievalDialog(Context context, CoreAccountInfo accountInfo) {
+        Intent intent = createKeyRetrievalIntent(accountInfo);
         if (intent == null) return;
 
         IntentUtils.safeStartActivity(context, intent);
@@ -117,12 +122,13 @@
     /**
      * Creates an intent that launches an activity that triggers the key retrieval UI.
      *
+     * @param accountInfo Account representing the user.
      * @return the intent for opening the key retrieval activity or null if none is actually
      * required
      */
     @Nullable
-    public Intent createKeyRetrievalIntent() {
-        return mBackend.createKeyRetrievalIntent();
+    public Intent createKeyRetrievalIntent(CoreAccountInfo accountInfo) {
+        return mBackend.createKeyRetrievalIntent(accountInfo);
     }
 
     /**
@@ -165,23 +171,27 @@
      * fetchKeysCompleted().
      */
     @CalledByNative
-    private static void fetchKeys(long nativeTrustedVaultClientAndroid, String gaiaId) {
+    private static void fetchKeys(
+            long nativeTrustedVaultClientAndroid, CoreAccountInfo accountInfo) {
         assert isNativeRegistered(nativeTrustedVaultClientAndroid);
-        get().mBackend.fetchKeys(gaiaId).then(
-                (keys)
-                        -> {
-                    if (isNativeRegistered(nativeTrustedVaultClientAndroid)) {
-                        TrustedVaultClientJni.get().fetchKeysCompleted(
-                                nativeTrustedVaultClientAndroid, gaiaId,
-                                keys.toArray(new byte[0][]));
-                    }
-                },
-                (exception) -> {
-                    if (isNativeRegistered(nativeTrustedVaultClientAndroid)) {
-                        TrustedVaultClientJni.get().fetchKeysCompleted(
-                                nativeTrustedVaultClientAndroid, gaiaId, new byte[0][]);
-                    }
-                });
+
+        get().mBackend.fetchKeys(accountInfo)
+                .then(
+                        (keys)
+                                -> {
+                            if (isNativeRegistered(nativeTrustedVaultClientAndroid)) {
+                                TrustedVaultClientJni.get().fetchKeysCompleted(
+                                        nativeTrustedVaultClientAndroid, accountInfo.getGaiaId(),
+                                        keys.toArray(new byte[0][]));
+                            }
+                        },
+                        (exception) -> {
+                            if (isNativeRegistered(nativeTrustedVaultClientAndroid)) {
+                                TrustedVaultClientJni.get().fetchKeysCompleted(
+                                        nativeTrustedVaultClientAndroid, accountInfo.getGaiaId(),
+                                        new byte[0][]);
+                            }
+                        });
     }
 
     /**
@@ -189,25 +199,28 @@
      * markKeysAsStaleCompleted().
      */
     @CalledByNative
-    private static void markKeysAsStale(long nativeTrustedVaultClientAndroid, String gaiaId) {
+    private static void markKeysAsStale(
+            long nativeTrustedVaultClientAndroid, CoreAccountInfo accountInfo) {
         assert isNativeRegistered(nativeTrustedVaultClientAndroid);
-        get().mBackend.markKeysAsStale(gaiaId).then(
-                (result)
-                        -> {
-                    if (isNativeRegistered(nativeTrustedVaultClientAndroid)) {
-                        TrustedVaultClientJni.get().markKeysAsStaleCompleted(
-                                nativeTrustedVaultClientAndroid, result);
-                    }
-                },
-                (exception) -> {
-                    if (isNativeRegistered(nativeTrustedVaultClientAndroid)) {
-                        // There's no certainty about whether the operation made any difference so
-                        // let's return true indicating that it might have, since false positives
-                        // are allowed.
-                        TrustedVaultClientJni.get().markKeysAsStaleCompleted(
-                                nativeTrustedVaultClientAndroid, true);
-                    }
-                });
+
+        get().mBackend.markKeysAsStale(accountInfo)
+                .then(
+                        (result)
+                                -> {
+                            if (isNativeRegistered(nativeTrustedVaultClientAndroid)) {
+                                TrustedVaultClientJni.get().markKeysAsStaleCompleted(
+                                        nativeTrustedVaultClientAndroid, result);
+                            }
+                        },
+                        (exception) -> {
+                            if (isNativeRegistered(nativeTrustedVaultClientAndroid)) {
+                                // There's no certainty about whether the operation made any
+                                // difference so let's return true indicating that it might have,
+                                // since false positives are allowed.
+                                TrustedVaultClientJni.get().markKeysAsStaleCompleted(
+                                        nativeTrustedVaultClientAndroid, true);
+                            }
+                        });
     }
 
     @NativeMethods
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
index 30d32d3..e197619 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
@@ -40,7 +40,7 @@
     }
 
     private boolean isMenuButtonInBottomToolbar() {
-        return mToolbarManager != null && mToolbarManager.isBottomToolbarVisible();
+        return mToolbarManager != null && mToolbarManager.isMenuFromBottom();
     }
 
     private boolean shouldShowDataSaverMenuItem() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/HomeButton.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/HomeButton.java
index 589acf5..e66e813 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/HomeButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/HomeButton.java
@@ -151,7 +151,7 @@
      * @param tab The notifying {@link Tab} that might be selected soon, this is a hint that a tab
      *         change is likely.
      */
-    private void updateButtonEnabledState(Tab tab) {
+    public void updateButtonEnabledState(Tab tab) {
         // New tab page button takes precedence over homepage.
         final boolean isHomepageEnabled = HomepageManager.isHomepageEnabled();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonCoordinator.java
index 3cd3480..8878ce0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonCoordinator.java
@@ -6,9 +6,7 @@
 
 import android.content.res.ColorStateList;
 import android.view.View.OnClickListener;
-import android.view.ViewGroup;
 
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ThemeColorProvider;
 import org.chromium.chrome.browser.ThemeColorProvider.TintObserver;
 import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
@@ -55,10 +53,9 @@
 
     /**
      * Build the controller that manages the tab switcher button.
-     * @param root The root {@link ViewGroup} for locating the view to inflate.
+     * @param view The {@link TabSwitcherButtonView} the controller manages.
      */
-    public TabSwitcherButtonCoordinator(ViewGroup root) {
-        final TabSwitcherButtonView view = root.findViewById(R.id.tab_switcher_button);
+    public TabSwitcherButtonCoordinator(TabSwitcherButtonView view) {
         PropertyModelChangeProcessor.create(
                 mTabSwitcherButtonModel, view, new TabSwitcherButtonViewBinder());
         mOverviewModeObserver = new EmptyOverviewModeObserver() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 0b50fe7..5aa6097 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -95,6 +95,7 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider;
 import org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator;
 import org.chromium.chrome.browser.toolbar.bottom.BottomTabSwitcherActionMenuCoordinator;
+import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager;
 import org.chromium.chrome.browser.toolbar.top.ActionModeController;
 import org.chromium.chrome.browser.toolbar.top.ActionModeController.ActionBarDelegate;
 import org.chromium.chrome.browser.toolbar.top.TabSwitcherActionMenuCoordinator;
@@ -718,6 +719,17 @@
             public void onOverviewModeStartedShowing(boolean showToolbar) {
                 mToolbar.setTabSwitcherMode(true, showToolbar, false);
                 updateButtonStatus();
+                if (FeatureUtilities.isBottomToolbarEnabled()
+                        && !BottomToolbarVariationManager
+                                    .shouldBottomToolbarBeVisibleInOverviewMode()) {
+                    // TODO(crbug.com/1036474): don't tell mToolbar the visibility of bottom toolbar
+                    // has been changed when entering overview, so it won't draw extra animations
+                    // or buttons during the transition. Before, bottom toolbar was always visible
+                    // in portrait mode, so the visibility was equivalent to the orientation change.
+                    // We may have to tell mToolbar extra information, like orientation, in future.
+                    // mToolbar.onBottomToolbarVisibilityChanged(false);
+                    mBottomControlsCoordinator.setBottomControlsVisible(false);
+                }
             }
 
             @Override
@@ -730,6 +742,16 @@
             public void onOverviewModeStartedHiding(boolean showToolbar, boolean delayAnimation) {
                 mToolbar.setTabSwitcherMode(false, showToolbar, delayAnimation);
                 updateButtonStatus();
+                if (FeatureUtilities.isBottomToolbarEnabled()
+                        && !BottomToolbarVariationManager
+                                    .shouldBottomToolbarBeVisibleInOverviewMode()) {
+                    // User may enter overview mode in landscape mode but exit in portrait mode.
+                    mIsBottomToolbarVisible = !FeatureUtilities.isAdaptiveToolbarEnabled()
+                            || mActivity.getResources().getConfiguration().orientation
+                                    != Configuration.ORIENTATION_LANDSCAPE;
+                    mToolbar.onBottomToolbarVisibilityChanged(mIsBottomToolbarVisible);
+                    mBottomControlsCoordinator.setBottomControlsVisible(mIsBottomToolbarVisible);
+                }
             }
 
             @Override
@@ -858,8 +880,11 @@
     // TODO(crbug.com/1026020): Move this logic to BottomToolbar class.
     private void onShareDelegateAvailable(ShareDelegate shareDelegate) {
         final OnClickListener shareButtonListener = v -> {
-            recordBottomToolbarUseForIPH();
-            RecordUserAction.record("MobileBottomToolbarShareButton");
+            if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+                recordBottomToolbarUseForIPH();
+                RecordUserAction.record("MobileBottomToolbarShareButton");
+            }
+
             Tab tab = null;
             Activity activity = null;
             boolean isIncognito = false;
@@ -1041,7 +1066,8 @@
         });
 
         if (mTabGroupPopupUi != null) {
-            mTabGroupPopUiParentSupplier.set(mIsBottomToolbarVisible
+            mTabGroupPopUiParentSupplier.set(
+                    mIsBottomToolbarVisible && BottomToolbarVariationManager.isTabSwitcherOnBottom()
                             ? mActivity.findViewById(R.id.bottom_controls)
                             : mActivity.findViewById(R.id.toolbar));
             mTabGroupPopupUi.initializeWithNative(mActivity);
@@ -1120,9 +1146,6 @@
      */
     public void showAppMenuUpdateBadge() {
         mToolbar.showAppMenuUpdateBadge();
-        if (mBottomControlsCoordinator != null) {
-            mBottomControlsCoordinator.showAppMenuUpdateBadge();
-        }
     }
 
     /**
@@ -1131,9 +1154,6 @@
      */
     public void removeAppMenuUpdateBadge(boolean animate) {
         mToolbar.removeAppMenuUpdateBadge(animate);
-        if (mBottomControlsCoordinator != null) {
-            mBottomControlsCoordinator.removeAppMenuUpdateBadge();
-        }
     }
 
     /**
@@ -1141,10 +1161,6 @@
      * TODO(amaralp): Only the top or bottom menu should be visible.
      */
     public boolean isShowingAppMenuUpdateBadge() {
-        if (mBottomControlsCoordinator != null
-                && mBottomControlsCoordinator.isShowingAppMenuUpdateBadge()) {
-            return true;
-        }
         return mToolbar.isShowingAppMenuUpdateBadge();
     }
 
@@ -1221,15 +1237,12 @@
 
     @Override
     public @Nullable View getMenuButtonView() {
-        if (mBottomControlsCoordinator != null && isBottomToolbarVisible()) {
-            return mBottomControlsCoordinator.getMenuButtonWrapper().getImageButton();
-        }
         return mToolbar.getMenuButton();
     }
 
     @Override
     public boolean isMenuFromBottom() {
-        return isBottomToolbarVisible();
+        return mIsBottomToolbarVisible && BottomToolbarVariationManager.isMenuButtonOnBottom();
     }
 
     /**
@@ -1356,15 +1369,20 @@
         if (mBottomControlsCoordinator != null && FeatureUtilities.isBottomToolbarEnabled()
                 && FeatureUtilities.isAdaptiveToolbarEnabled()) {
             mIsBottomToolbarVisible = newOrientation != Configuration.ORIENTATION_LANDSCAPE;
+            if (!BottomToolbarVariationManager.shouldBottomToolbarBeVisibleInOverviewMode()
+                    && mIsBottomToolbarVisible) {
+                mIsBottomToolbarVisible = !mActivity.isInOverviewMode();
+            }
             mToolbar.onBottomToolbarVisibilityChanged(mIsBottomToolbarVisible);
             mBottomControlsCoordinator.setBottomControlsVisible(mIsBottomToolbarVisible);
             if (mAppMenuButtonHelper != null) {
-                mAppMenuButtonHelper.setMenuShowsFromBottom(mIsBottomToolbarVisible);
+                mAppMenuButtonHelper.setMenuShowsFromBottom(isMenuFromBottom());
             }
             mIdentityDiscController.updateButtonState();
 
             if (mTabGroupPopupUi != null) {
                 mTabGroupPopUiParentSupplier.set(mIsBottomToolbarVisible
+                                        && BottomToolbarVariationManager.isTabSwitcherOnBottom()
                                 ? mActivity.findViewById(R.id.bottom_controls)
                                 : mActivity.findViewById(R.id.toolbar));
             }
@@ -1502,10 +1520,10 @@
             }
         });
         mAppMenuButtonHelper = mAppMenuHandler.createAppMenuButtonHelper();
-        mAppMenuButtonHelper.setMenuShowsFromBottom(isBottomToolbarVisible());
+        mAppMenuButtonHelper.setMenuShowsFromBottom(isMenuFromBottom());
         mAppMenuButtonHelper.setOnAppMenuShownListener(() -> {
             RecordUserAction.record("MobileToolbarShowMenu");
-            if (isBottomToolbarVisible()) {
+            if (isMenuFromBottom()) {
                 RecordUserAction.record("MobileBottomToolbarShowMenu");
             } else {
                 RecordUserAction.record("MobileTopToolbarShowMenu");
@@ -1524,10 +1542,6 @@
 
     @Nullable
     private MenuButton getMenuButtonWrapper() {
-        if (mBottomControlsCoordinator != null) {
-            return mBottomControlsCoordinator.getMenuButtonWrapper();
-        }
-
         return mToolbar.getMenuButtonWrapper();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
index f9e9a9d..10e9d49 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsCoordinator.java
@@ -25,7 +25,6 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabGroupUi;
 import org.chromium.chrome.browser.tasks.tab_management.TabManagementModuleProvider;
 import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
-import org.chromium.chrome.browser.toolbar.MenuButton;
 import org.chromium.chrome.browser.toolbar.TabCountProvider;
 import org.chromium.chrome.browser.toolbar.bottom.BottomControlsViewBinder.ViewHolder;
 import org.chromium.chrome.browser.ui.ImmersiveModeManager;
@@ -177,44 +176,6 @@
     }
 
     /**
-     * Show the update badge over the bottom toolbar's app menu.
-     */
-    public void showAppMenuUpdateBadge() {
-        if (mBottomToolbarCoordinator != null) {
-            mBottomToolbarCoordinator.showAppMenuUpdateBadge();
-        }
-    }
-
-    /**
-     * Remove the update badge.
-     */
-    public void removeAppMenuUpdateBadge() {
-        if (mBottomToolbarCoordinator != null) {
-            mBottomToolbarCoordinator.removeAppMenuUpdateBadge();
-        }
-    }
-
-    /**
-     * @return Whether the update badge is showing.
-     */
-    public boolean isShowingAppMenuUpdateBadge() {
-        if (mBottomToolbarCoordinator != null) {
-            return mBottomToolbarCoordinator.isShowingAppMenuUpdateBadge();
-        }
-        return false;
-    }
-
-    /**
-     * @return The wrapper for the browsing mode toolbar's app menu button.
-     */
-    public MenuButton getMenuButtonWrapper() {
-        if (mBottomToolbarCoordinator != null) {
-            return mBottomToolbarCoordinator.getMenuButtonWrapper();
-        }
-        return null;
-    }
-
-    /**
      * Handles system back press action if needed.
      * @return Whether or not the back press event is consumed here.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java
index eb16977..19475da 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java
@@ -14,11 +14,11 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.ThemeColorProvider;
+import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
 import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
 import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
-import org.chromium.chrome.browser.toolbar.MenuButton;
 import org.chromium.chrome.browser.toolbar.TabCountProvider;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
 
@@ -43,6 +43,9 @@
     private OverviewModeBehavior mOverviewModeBehavior;
     private OverviewModeObserver mOverviewModeObserver;
 
+    /** The activity tab provider. */
+    private ActivityTabProvider mTabProvider;
+
     /**
      * Build the coordinator that manages the bottom toolbar.
      * @param stub The bottom toolbar {@link ViewStub} to inflate.
@@ -66,6 +69,7 @@
         mTabSwitcherModeStub = root.findViewById(R.id.bottom_toolbar_tab_switcher_mode_stub);
 
         mThemeColorProvider = themeColorProvider;
+        mTabProvider = tabProvider;
     }
 
     /**
@@ -90,18 +94,44 @@
             AppMenuButtonHelper menuButtonHelper, OverviewModeBehavior overviewModeBehavior,
             TabCountProvider tabCountProvider, IncognitoStateProvider incognitoStateProvider,
             ViewGroup topToolbarRoot) {
-        mBrowsingModeCoordinator.initializeWithNative(tabSwitcherListener, menuButtonHelper,
-                tabCountProvider, mThemeColorProvider, incognitoStateProvider,
+        mBrowsingModeCoordinator.initializeWithNative(newTabClickListener, tabSwitcherListener,
+                menuButtonHelper, tabCountProvider, mThemeColorProvider, incognitoStateProvider,
                 overviewModeBehavior);
         mTabSwitcherModeCoordinator = new TabSwitcherBottomToolbarCoordinator(mTabSwitcherModeStub,
                 topToolbarRoot, incognitoStateProvider, mThemeColorProvider, newTabClickListener,
                 closeTabsClickListener, menuButtonHelper, tabCountProvider);
+
         // Do not change bottom bar if StartSurface Single Pane is enabled and HomePage is not
         // customized.
-        if (!ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePage()) {
+        if (!ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePage()
+                && BottomToolbarVariationManager.shouldBottomToolbarBeVisibleInOverviewMode()) {
             mOverviewModeBehavior = overviewModeBehavior;
-            mOverviewModeObserver = new BottomToolbarAnimationCoordinator(
-                    mBrowsingModeCoordinator, mTabSwitcherModeCoordinator);
+            mOverviewModeObserver = new EmptyOverviewModeObserver() {
+                @Override
+                public void onOverviewModeStartedShowing(boolean showToolbar) {
+                    mBrowsingModeCoordinator.getSearchAccelerator().setEnabled(false);
+                    if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+                        mBrowsingModeCoordinator.getShareButton().setEnabled(false);
+                    }
+                    if (BottomToolbarVariationManager.isHomeButtonOnBottom()) {
+                        mBrowsingModeCoordinator.getHomeButton().setEnabled(false);
+                    }
+                }
+
+                @Override
+                public void onOverviewModeStartedHiding(
+                        boolean showToolbar, boolean delayAnimation) {
+                    mBrowsingModeCoordinator.getSearchAccelerator().setEnabled(true);
+                    if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+                        mBrowsingModeCoordinator.getShareButton().updateButtonEnabledState(
+                                mTabProvider.get());
+                    }
+                    if (BottomToolbarVariationManager.isHomeButtonOnBottom()) {
+                        mBrowsingModeCoordinator.getHomeButton().updateButtonEnabledState(
+                                mTabProvider.get());
+                    }
+                }
+            };
             if (mOverviewModeBehavior != null) {
                 mOverviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver);
             }
@@ -119,34 +149,6 @@
     }
 
     /**
-     * Show the update badge over the bottom toolbar's app menu.
-     */
-    void showAppMenuUpdateBadge() {
-        mBrowsingModeCoordinator.showAppMenuUpdateBadge();
-    }
-
-    /**
-     * Remove the update badge.
-     */
-    void removeAppMenuUpdateBadge() {
-        mBrowsingModeCoordinator.removeAppMenuUpdateBadge();
-    }
-
-    /**
-     * @return Whether the update badge is showing.
-     */
-    boolean isShowingAppMenuUpdateBadge() {
-        return mBrowsingModeCoordinator.isShowingAppMenuUpdateBadge();
-    }
-
-    /**
-     * @return The wrapper for the browsing mode toolbar's app menu button.
-     */
-    MenuButton getMenuButtonWrapper() {
-        return mBrowsingModeCoordinator.getMenuButton();
-    }
-
-    /**
      * Clean up any state when the bottom toolbar is destroyed.
      */
     void destroy() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarNewTabButton.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarNewTabButton.java
index be823cc..a501280 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarNewTabButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarNewTabButton.java
@@ -9,7 +9,6 @@
 import android.content.res.Resources;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
-import android.support.graphics.drawable.VectorDrawableCompat;
 import android.util.AttributeSet;
 
 import androidx.annotation.StringRes;
@@ -30,7 +29,7 @@
 class BottomToolbarNewTabButton extends ChromeImageButton
         implements IncognitoStateObserver, ThemeColorObserver, TintObserver {
     /** The gray pill background behind the plus icon. */
-    private final Drawable mBackground;
+    private Drawable mBackground;
 
     /** The {@link Resources} used to compute the background color. */
     private final Resources mResources;
@@ -45,13 +44,12 @@
         super(context, attrs);
 
         mResources = context.getResources();
+    }
 
-        setImageDrawable(VectorDrawableCompat.create(
-                getContext().getResources(), R.drawable.new_tab_icon, getContext().getTheme()));
-
-        mBackground = ApiCompatibilityUtils.getDrawable(mResources, R.drawable.ntp_search_box);
-        mBackground.mutate();
-        setBackground(mBackground);
+    @Override
+    public void setBackground(Drawable background) {
+        super.setBackground(background);
+        mBackground = background;
     }
 
     /**
@@ -101,8 +99,9 @@
     }
 
     private void updateBackground() {
-        if (mThemeColorProvider == null || mIncognitoStateProvider == null) return;
-
+        if (mThemeColorProvider == null || mIncognitoStateProvider == null || mBackground == null) {
+            return;
+        }
         mBackground.setColorFilter(
                 ToolbarColors.getTextBoxColorForToolbarBackgroundInNonNativePage(mResources,
                         mThemeColorProvider.getThemeColor(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarVariationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarVariationManager.java
new file mode 100644
index 0000000..5aca8d3
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarVariationManager.java
@@ -0,0 +1,119 @@
+// 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.
+
+package org.chromium.chrome.browser.toolbar.bottom;
+
+import androidx.annotation.StringDef;
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.chrome.browser.flags.FeatureUtilities;
+import org.chromium.chrome.browser.incognito.IncognitoUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The variation manager helps figure out the current variation and the visibility of buttons on
+ * bottom toolbar. Every operation related to the variation, e.g. getting variation value, should be
+ * through {@link BottomToolbarVariationManager} rather than calling {@link FeatureUtilities}.
+ */
+public class BottomToolbarVariationManager {
+    @StringDef({Variations.NONE, Variations.HOME_SEARCH_TAB_SWITCHER, Variations.HOME_SEARCH_SHARE,
+            Variations.NEW_TAB_SEARCH_SHARE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Variations {
+        String NONE = "";
+        String HOME_SEARCH_TAB_SWITCHER = "HomeSearchTabSwitcher";
+        String HOME_SEARCH_SHARE = "HomeSearchShare";
+        String NEW_TAB_SEARCH_SHARE = "NewTabSearchShare";
+    }
+
+    private static String sVariation;
+
+    /**
+     * @return The currently enabled bottom toolbar variation.
+     *         Should be called after FeatureUtilities.isBottomToolbarEnabled().
+     */
+    private static @Variations String getVariation() {
+        if (sVariation != null) return sVariation;
+        if (!FeatureUtilities.isBottomToolbarEnabled()) {
+            return Variations.HOME_SEARCH_TAB_SWITCHER;
+        }
+        sVariation = FeatureUtilities.getBottomToolbarVariation();
+        if (sVariation.equals(Variations.NONE)) {
+            return Variations.HOME_SEARCH_TAB_SWITCHER;
+        }
+        return sVariation;
+    }
+
+    /**
+     * @return Whether or not share button should be visible on the top toolbar in portrait mode
+     *         in the current variation.
+     */
+    public static boolean isShareButtonOnBottom() {
+        return FeatureUtilities.isBottomToolbarEnabled()
+                && !getVariation().equals(Variations.HOME_SEARCH_TAB_SWITCHER);
+    }
+
+    /**
+     * @return Whether or not new tab button should be visible on the bottom toolbar
+     *         in portrait mode in the current variation.
+     */
+    public static boolean isNewTabButtonOnBottom() {
+        return FeatureUtilities.isBottomToolbarEnabled()
+                && getVariation().equals(Variations.NEW_TAB_SEARCH_SHARE);
+    }
+
+    /**
+     * @return Whether or not menu button should be visible on the top toolbar
+     *         in portrait mode in the current variation.
+     */
+    public static boolean isMenuButtonOnBottom() {
+        // If we don't have variations that put menu on bottom in the future,
+        // then this method can be removed.
+        return false;
+    }
+
+    /**
+     * @return Whether or not bottom toolbar should be visible in overview mode of portrait mode
+     *         in the current variation.
+     */
+    public static boolean shouldBottomToolbarBeVisibleInOverviewMode() {
+        return (getVariation().equals(Variations.NEW_TAB_SEARCH_SHARE)
+                       && !FeatureUtilities.isStartSurfaceEnabled())
+                || ((!FeatureUtilities.isGridTabSwitcherEnabled()
+                            || !IncognitoUtils.isIncognitoModeEnabled())
+                        && getVariation().equals(Variations.HOME_SEARCH_TAB_SWITCHER));
+    }
+
+    /**
+     * @return Whether or not home button should be visible in top toolbar of portrait mode
+     *         in current variation.
+     */
+    public static boolean isHomeButtonOnBottom() {
+        return FeatureUtilities.isBottomToolbarEnabled()
+                && !getVariation().equals(Variations.NEW_TAB_SEARCH_SHARE);
+    }
+
+    /**
+     * @return Whether or not tab switcher button should be visible in bottom toolbar
+     *         of portrait mode in current variation.
+     */
+    public static boolean isTabSwitcherOnBottom() {
+        return FeatureUtilities.isBottomToolbarEnabled()
+                && getVariation().equals(Variations.HOME_SEARCH_TAB_SWITCHER);
+    }
+
+    /**
+     * @return Name of the variation parameter of bottom toolbar.
+     */
+    public static String getVariationParamName() {
+        return "chrome_duet_variation";
+    }
+
+    @VisibleForTesting
+    public static void setVariation(String variation) {
+        sVariation = variation;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarCoordinator.java
index 73acce327..c770288 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarCoordinator.java
@@ -21,7 +21,6 @@
 import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil;
 import org.chromium.chrome.browser.toolbar.HomeButton;
 import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
-import org.chromium.chrome.browser.toolbar.MenuButton;
 import org.chromium.chrome.browser.toolbar.TabCountProvider;
 import org.chromium.chrome.browser.toolbar.TabSwitcherButtonCoordinator;
 import org.chromium.chrome.browser.toolbar.TabSwitcherButtonView;
@@ -45,6 +44,9 @@
     /** The share button that lives in the bottom toolbar. */
     private final ShareButton mShareButton;
 
+    /** The new tab button that lives in the bottom toolbar. */
+    private final BottomToolbarNewTabButton mNewTabButton;
+
     /** The search accelerator that lives in the bottom toolbar. */
     private final SearchAccelerator mSearchAccelerator;
 
@@ -54,9 +56,6 @@
     /** The tab switcher button view that lives in the bottom toolbar. */
     private final TabSwitcherButtonView mTabSwitcherButtonView;
 
-    /** The menu button that lives in the browsing mode bottom toolbar. */
-    private final MenuButton mMenuButton;
-
     /** The view group that includes all views shown on browsing mode */
     private final BrowsingModeBottomToolbarLinearLayout mToolbarRoot;
 
@@ -64,10 +63,10 @@
     private final BrowsingModeBottomToolbarModel mModel;
 
     /** The callback to be exectured when the share button on click listener is available. */
-    private final Callback<OnClickListener> mShareButtonListenerSupplierCallback;
+    private Callback<OnClickListener> mShareButtonListenerSupplierCallback;
 
     /** The supplier for the share button on click listener. */
-    private final ObservableSupplier<OnClickListener> mShareButtonListenerSupplier;
+    private ObservableSupplier<OnClickListener> mShareButtonListenerSupplier;
 
     /** The activity tab provider that used for making the IPH. */
     private final ActivityTabProvider mTabProvider;
@@ -83,7 +82,7 @@
     BrowsingModeBottomToolbarCoordinator(View root, ActivityTabProvider tabProvider,
             OnClickListener homeButtonListener, OnClickListener searchAcceleratorListener,
             ObservableSupplier<OnClickListener> shareButtonListenerSupplier,
-            OnLongClickListener tabSwitcherLongClickListner) {
+            OnLongClickListener tabSwitcherLongClickListener) {
         mModel = new BrowsingModeBottomToolbarModel();
         mToolbarRoot = root.findViewById(R.id.bottom_toolbar_browsing);
         mTabProvider = tabProvider;
@@ -93,30 +92,44 @@
 
         mMediator = new BrowsingModeBottomToolbarMediator(mModel);
 
-        mHomeButton = mToolbarRoot.findViewById(R.id.home_button);
+        mHomeButton = mToolbarRoot.findViewById(R.id.bottom_home_button);
         mHomeButton.setOnClickListener(homeButtonListener);
         mHomeButton.setActivityTabProvider(mTabProvider);
         setupIPH(FeatureConstants.CHROME_DUET_HOME_BUTTON_FEATURE, mHomeButton, homeButtonListener);
 
-        mShareButton = mToolbarRoot.findViewById(R.id.share_button);
-        mShareButtonListenerSupplierCallback = shareButtonListener -> {
-            mShareButton.setOnClickListener(shareButtonListener);
-        };
-        mShareButtonListenerSupplier = shareButtonListenerSupplier;
-        mShareButtonListenerSupplier.addObserver(mShareButtonListenerSupplierCallback);
-        mShareButton.setActivityTabProvider(mTabProvider);
+        mNewTabButton = mToolbarRoot.findViewById(R.id.bottom_new_tab_button);
+
+        mShareButton = mToolbarRoot.findViewById(R.id.bottom_share_button);
 
         mSearchAccelerator = mToolbarRoot.findViewById(R.id.search_accelerator);
         mSearchAccelerator.setOnClickListener(searchAcceleratorListener);
         setupIPH(FeatureConstants.CHROME_DUET_SEARCH_FEATURE, mSearchAccelerator,
                 searchAcceleratorListener);
 
-        mTabSwitcherButtonCoordinator = new TabSwitcherButtonCoordinator(mToolbarRoot);
         // TODO(amaralp): Make this adhere to MVC framework.
-        mTabSwitcherButtonView = mToolbarRoot.findViewById(R.id.tab_switcher_button);
+        mTabSwitcherButtonView = mToolbarRoot.findViewById(R.id.bottom_tab_switcher_button);
+        mTabSwitcherButtonCoordinator = new TabSwitcherButtonCoordinator(mTabSwitcherButtonView);
 
-        mTabSwitcherButtonView.setOnLongClickListener(tabSwitcherLongClickListner);
-        mMenuButton = mToolbarRoot.findViewById(R.id.menu_button_wrapper);
+        mTabSwitcherButtonView.setOnLongClickListener(tabSwitcherLongClickListener);
+        if (BottomToolbarVariationManager.isNewTabButtonOnBottom()) {
+            mNewTabButton.setVisibility(View.VISIBLE);
+        }
+        if (BottomToolbarVariationManager.isHomeButtonOnBottom()) {
+            mHomeButton.setVisibility(View.VISIBLE);
+        }
+
+        if (BottomToolbarVariationManager.isTabSwitcherOnBottom()) {
+            mTabSwitcherButtonView.setVisibility(View.VISIBLE);
+        }
+        if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+            mShareButton.setVisibility(View.VISIBLE);
+            mShareButtonListenerSupplierCallback = shareButtonListener -> {
+                mShareButton.setOnClickListener(shareButtonListener);
+            };
+            mShareButtonListenerSupplier = shareButtonListenerSupplier;
+            mShareButton.setActivityTabProvider(mTabProvider);
+            mShareButtonListenerSupplier.addObserver(mShareButtonListenerSupplierCallback);
+        }
     }
 
     /**
@@ -166,6 +179,8 @@
      * Calling this must occur after the native library have completely loaded.
      * @param tabSwitcherListener An {@link OnClickListener} that is triggered when the
      *                            tab switcher button is clicked.
+     * @param tabSwitcherListener An {@link OnClickListener} that is triggered when the
+     *                            tab switcher button is clicked.
      * @param menuButtonHelper An {@link AppMenuButtonHelper} that is triggered when the
      *                         menu button is clicked.
      * @param tabCountProvider Updates the tab count number in the tab switcher button.
@@ -173,32 +188,41 @@
      * @param incognitoStateProvider Notifies components when incognito state changes.
      * @param overviewModeBehavior Notifies components when overview mode changes.
      */
-    void initializeWithNative(OnClickListener tabSwitcherListener,
+    void initializeWithNative(OnClickListener newTabListener, OnClickListener tabSwitcherListener,
             AppMenuButtonHelper menuButtonHelper, TabCountProvider tabCountProvider,
             ThemeColorProvider themeColorProvider, IncognitoStateProvider incognitoStateProvider,
             OverviewModeBehavior overviewModeBehavior) {
         mMediator.setThemeColorProvider(themeColorProvider);
+        if (BottomToolbarVariationManager.isNewTabButtonOnBottom()) {
+            mNewTabButton.setOnClickListener(newTabListener);
+            mNewTabButton.setThemeColorProvider(themeColorProvider);
+            mNewTabButton.setIncognitoStateProvider(incognitoStateProvider);
+        }
+        if (BottomToolbarVariationManager.isHomeButtonOnBottom()) {
+            mHomeButton.setThemeColorProvider(themeColorProvider);
+        }
 
-        mHomeButton.setThemeColorProvider(themeColorProvider);
-        mShareButton.setThemeColorProvider(themeColorProvider);
+        if (BottomToolbarVariationManager.isShareButtonOnBottom()) {
+            mShareButton.setThemeColorProvider(themeColorProvider);
+        }
+
         mSearchAccelerator.setThemeColorProvider(themeColorProvider);
         mSearchAccelerator.setIncognitoStateProvider(incognitoStateProvider);
 
-        mTabSwitcherButtonCoordinator.setTabSwitcherListener(tabSwitcherListener);
-        mTabSwitcherButtonCoordinator.setThemeColorProvider(themeColorProvider);
-        mTabSwitcherButtonCoordinator.setTabCountProvider(tabCountProvider);
-        // Send null to IPH here to avoid tabSwitcherListener to be called twince, since
-        // mTabSwitcherButtonView has it own OnClickListener, but other buttons set OnClickListener
-        // to their wrappers.
-        setupIPH(FeatureConstants.CHROME_DUET_TAB_SWITCHER_FEATURE, mTabSwitcherButtonView, null);
-
-        assert menuButtonHelper != null;
-        mMenuButton.setAppMenuButtonHelper(menuButtonHelper);
-        mMenuButton.setThemeColorProvider(themeColorProvider);
+        if (BottomToolbarVariationManager.isTabSwitcherOnBottom()) {
+            mTabSwitcherButtonCoordinator.setTabSwitcherListener(tabSwitcherListener);
+            mTabSwitcherButtonCoordinator.setThemeColorProvider(themeColorProvider);
+            mTabSwitcherButtonCoordinator.setTabCountProvider(tabCountProvider);
+            // Send null to IPH here to avoid tabSwitcherListener to be called twince, since
+            // mTabSwitcherButtonView has it own OnClickListener, but other buttons set
+            // OnClickListener to their wrappers.
+            setupIPH(FeatureConstants.CHROME_DUET_TAB_SWITCHER_FEATURE, mTabSwitcherButtonView,
+                    null);
+        }
 
         // If StartSurface is HomePage, BrowsingModeBottomToolbar is shown in browsing mode and in
         // overview mode. We need to pass the OverviewModeBehavior to the buttons so they are
-        // disabled based on the moverview state.
+        // disabled based on the overview state.
         if (ReturnToChromeExperimentsUtil.shouldShowStartSurfaceAsTheHomePage()) {
             mShareButton.setOverviewModeBehavior(overviewModeBehavior);
             mTabSwitcherButtonCoordinator.setOverviewModeBehavior(overviewModeBehavior);
@@ -207,27 +231,6 @@
     }
 
     /**
-     * Show the update badge over the bottom toolbar's app menu.
-     */
-    void showAppMenuUpdateBadge() {
-        mMenuButton.showAppMenuUpdateBadgeIfAvailable(true);
-    }
-
-    /**
-     * Remove the update badge.
-     */
-    void removeAppMenuUpdateBadge() {
-        mMenuButton.removeAppMenuUpdateBadge(true);
-    }
-
-    /**
-     * @return Whether the update badge is showing.
-     */
-    boolean isShowingAppMenuUpdateBadge() {
-        return mMenuButton.isShowingAppMenuUpdateBadge();
-    }
-
-    /**
      * @param enabled Whether to disable click events on the bottom toolbar. Setting true can also
      *                prevent from all click events on toolbar and all children views on toolbar.
      */
@@ -243,13 +246,6 @@
     }
 
     /**
-     * @return The browsing mode bottom toolbar's menu button.
-     */
-    MenuButton getMenuButton() {
-        return mMenuButton;
-    }
-
-    /**
      * @return The browsing mode bottom toolbar's share button.
      */
     ShareButton getShareButton() {
@@ -281,12 +277,13 @@
      * Clean up any state when the browsing mode bottom toolbar is destroyed.
      */
     public void destroy() {
-        mShareButtonListenerSupplier.removeObserver(mShareButtonListenerSupplierCallback);
+        if (mShareButtonListenerSupplier != null) {
+            mShareButtonListenerSupplier.removeObserver(mShareButtonListenerSupplierCallback);
+        }
         mMediator.destroy();
         mHomeButton.destroy();
         mShareButton.destroy();
         mSearchAccelerator.destroy();
         mTabSwitcherButtonCoordinator.destroy();
-        mMenuButton.destroy();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/SearchAccelerator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/SearchAccelerator.java
index 73b0ff9..e4bacfa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/SearchAccelerator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/SearchAccelerator.java
@@ -10,7 +10,6 @@
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.view.View;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
@@ -39,9 +38,6 @@
     /** A provider that notifies when incognito mode is entered or exited. */
     private IncognitoStateProvider mIncognitoStateProvider;
 
-    /** The wrapper View that contains the search accelerator and the label. */
-    private View mWrapper;
-
     public SearchAccelerator(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -52,15 +48,6 @@
         setBackground(mBackground);
     }
 
-    @Override
-    public void setOnClickListener(OnClickListener listener) {
-        if (mWrapper != null) {
-            mWrapper.setOnClickListener(listener);
-        } else {
-            super.setOnClickListener(listener);
-        }
-    }
-
     void setThemeColorProvider(ThemeColorProvider themeColorProvider) {
         mThemeColorProvider = themeColorProvider;
         mThemeColorProvider.addThemeColorObserver(this);
@@ -93,6 +80,7 @@
     @Override
     public void onTintChanged(ColorStateList tint, boolean useLight) {
         ApiCompatibilityUtils.setImageTintList(this, tint);
+        updateBackground();
     }
 
     @Override
@@ -105,7 +93,8 @@
 
         mBackground.setColorFilter(ToolbarColors.getTextBoxColorForToolbarBackgroundInNonNativePage(
                                            mResources, mThemeColorProvider.getThemeColor(),
-                                           mIncognitoStateProvider.isIncognitoSelected()),
+                                           mIncognitoStateProvider.isIncognitoSelected()
+                                                   && mThemeColorProvider.useLight()),
                 PorterDuff.Mode.SRC_IN);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ShareButton.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ShareButton.java
index 0d9bd287..c08514c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ShareButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/ShareButton.java
@@ -90,7 +90,11 @@
         }
     }
 
-    private void updateButtonEnabledState(Tab tab) {
+    public void updateButtonEnabledState(Tab tab) {
+        if (tab == null) {
+            setEnabled(false);
+            return;
+        }
         final String url = tab.getUrl();
         final boolean isChromeScheme = url.startsWith(UrlConstants.CHROME_URL_PREFIX)
                 || url.startsWith(UrlConstants.CHROME_NATIVE_URL_PREFIX);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/TabSwitcherBottomToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/TabSwitcherBottomToolbarCoordinator.java
index 27881e593..0d83499 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/TabSwitcherBottomToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/TabSwitcherBottomToolbarCoordinator.java
@@ -4,11 +4,13 @@
 
 package org.chromium.chrome.browser.toolbar.bottom;
 
+import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.ViewStub;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ThemeColorProvider;
 import org.chromium.chrome.browser.flags.FeatureUtilities;
@@ -21,6 +23,8 @@
 /**
  * The coordinator for the tab switcher mode bottom toolbar. This class handles all interactions
  * that the tab switcher bottom toolbar has with the outside world.
+ * TODO(crbug.com/1036474): This coordinator is not used currently and can be removed if the final
+ *                          duet design doesn't need a stand-alone toolbar in tab switcher mode.
  */
 public class TabSwitcherBottomToolbarCoordinator {
     /** The mediator that handles events from outside the tab switcher bottom toolbar. */
@@ -82,6 +86,10 @@
         mCloseAllTabsButton.setVisibility(View.INVISIBLE);
 
         mNewTabButton = root.findViewById(R.id.tab_switcher_new_tab_button);
+        Drawable background =
+                ApiCompatibilityUtils.getDrawable(root.getResources(), R.drawable.ntp_search_box);
+        background.mutate();
+        mNewTabButton.setBackground(background);
         mNewTabButton.setOnClickListener(newTabClickListener);
         mNewTabButton.setIncognitoStateProvider(incognitoStateProvider);
         mNewTabButton.setThemeColorProvider(themeColorProvider);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
index f3c79db..2282856 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
@@ -21,7 +21,6 @@
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeState;
-import org.chromium.chrome.browser.flags.FeatureUtilities;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabModel;
@@ -46,7 +45,7 @@
 
     StartSurfaceToolbarMediator(PropertyModel model) {
         mPropertyModel = model;
-        mPropertyModel.set(MENU_IS_VISIBLE, !FeatureUtilities.isBottomToolbarEnabled());
+        mPropertyModel.set(MENU_IS_VISIBLE, true);
         mOverviewModeState = OverviewModeState.NOT_SHOWN;
     }
 
@@ -118,9 +117,7 @@
         mPropertyModel.set(ACCESSIBILITY_ENABLED, enabled);
     }
 
-    void onBottomToolbarVisibilityChanged(boolean isVisible) {
-        mPropertyModel.set(MENU_IS_VISIBLE, !isVisible);
-    }
+    void onBottomToolbarVisibilityChanged(boolean isVisible) {}
 
     void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior) {
         assert mOverviewModeBehavior == null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTPhone.java
index 4593e37..903ebbb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTPhone.java
@@ -31,12 +31,12 @@
 import org.chromium.chrome.browser.toolbar.NewTabButton;
 import org.chromium.chrome.browser.toolbar.TabCountProvider;
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
+import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.animation.CancelAwareAnimatorListener;
 import org.chromium.components.browser_ui.widget.animation.Interpolators;
-import org.chromium.ui.UiUtils;
 import org.chromium.ui.widget.OptimizedFrameLayout;
 
 /** The tab switcher mode top toolbar shown on phones. */
@@ -64,7 +64,7 @@
     private ColorStateList mDarkIconTint;
 
     private boolean mIsIncognito;
-    private boolean mShouldShowButtons;
+    private boolean mShouldShowNewTabButton;
     private boolean mShouldShowNewTabVariation;
 
     private ObjectAnimator mVisiblityAnimator;
@@ -82,38 +82,15 @@
         mMenuButton = findViewById(R.id.menu_button_wrapper);
         mToggleTabStackButton = findViewById(R.id.tab_switcher_mode_tab_switcher_button);
 
-        boolean isBottomToolbarEnabled = FeatureUtilities.isBottomToolbarEnabled();
-        boolean isGridTabSwitcherEnabled = FeatureUtilities.isGridTabSwitcherEnabled();
+        // TODO(twellington): Try to make NewTabButton responsible for handling its own clicks.
+        //                    TabSwitcherBottomToolbarCoordinator also uses NewTabButton and
+        //                    sets an onClickListener directly on NewTabButton rather than
+        //                    acting as the click listener itself so the behavior between this
+        //                    class and the bottom toolbar will need to be unified.
+        mNewTabImageButton.setOnClickListener(this);
+        mNewTabViewButton.setOnClickListener(this);
 
-        if (isBottomToolbarEnabled && !isGridTabSwitcherEnabled) {
-            UiUtils.removeViewFromParent(mNewTabImageButton);
-            mNewTabImageButton.destroy();
-            mNewTabImageButton = null;
-
-            UiUtils.removeViewFromParent(mMenuButton);
-            mMenuButton.destroy();
-            mMenuButton = null;
-
-            UiUtils.removeViewFromParent(mToggleTabStackButton);
-            mToggleTabStackButton.destroy();
-            mToggleTabStackButton = null;
-
-            UiUtils.removeViewFromParent(mNewTabViewButton);
-            mNewTabViewButton = null;
-        } else {
-            // TODO(twellington): Try to make NewTabButton responsible for handling its own clicks.
-            //                    TabSwitcherBottomToolbarCoordinator also uses NewTabButton and
-            //                    sets an onClickListener directly on NewTabButton rather than
-            //                    acting as the click listener itself so the behavior between this
-            //                    class and the bottom toolbar will need to be unified.
-            mNewTabImageButton.setOnClickListener(this);
-            mNewTabViewButton.setOnClickListener(this);
-        }
-
-        if ((usingHorizontalTabSwitcher() || FeatureUtilities.isGridTabSwitcherEnabled())
-                && IncognitoUtils.isIncognitoModeEnabled()) {
-            updateTabSwitchingElements(true);
-        }
+        updateTabSwitchingElements(shouldShowIncognitoToggle());
     }
 
     @Override
@@ -295,11 +272,14 @@
      * @param isVisible Whether the bottom toolbar is visible.
      */
     void onBottomToolbarVisibilityChanged(boolean isVisible) {
-        // When bottom toolbar is showing, hide buttons in top toolbar that have overlapping
-        // functionality; otherwise show buttons in top toolbar.
-        mShouldShowButtons = !isVisible;
-        setNewTabButtonVisibility(mShouldShowButtons);
-        setMenuButtonVisibility(mShouldShowButtons);
+        mShouldShowNewTabButton = !isVisible
+                || (FeatureUtilities.isBottomToolbarEnabled()
+                        && !BottomToolbarVariationManager.isNewTabButtonOnBottom());
+        setNewTabButtonVisibility(mShouldShowNewTabButton);
+        // show tab switcher button on the top in landscape mode.
+        if (BottomToolbarVariationManager.isTabSwitcherOnBottom() && !shouldShowIncognitoToggle()) {
+            mToggleTabStackButton.setVisibility(isVisible ? GONE : VISIBLE);
+        }
     }
 
     private void setNewTabButtonVisibility(boolean isButtonVisible) {
@@ -414,6 +394,15 @@
         setToggleTabStackButtonVisibility(!showIncognitoToggle);
     }
 
+    /**
+     * @return Whether or not incognito toggle should be visible based on the enabled features
+     *         and incognito status.
+     */
+    private boolean shouldShowIncognitoToggle() {
+        return (usingHorizontalTabSwitcher() || FeatureUtilities.isGridTabSwitcherEnabled())
+                && IncognitoUtils.isIncognitoModeEnabled();
+    }
+
     private void updateIncognitoToggleTabsVisibility() {
         // TODO(yuezhanggg): Add a regression test for this "New Tab" variation. (crbug: 977546)
         if (!FeatureUtilities.isGridTabSwitcherEnabled() || !ChromeFeatureList.isInitialized()
@@ -430,7 +419,7 @@
         // Show new tab variation when there are no incognito tabs.
         mShouldShowNewTabVariation = !hasIncognitoTabs();
         mIncognitoToggleTabLayout.setVisibility(mShouldShowNewTabVariation ? GONE : VISIBLE);
-        setNewTabButtonVisibility(mShouldShowButtons);
+        setNewTabButtonVisibility(mShouldShowNewTabButton);
     }
 
     private boolean hasIncognitoTabs() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
index 5efae4f1..f1c571c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -73,6 +73,7 @@
 import org.chromium.chrome.browser.toolbar.TabSwitcherDrawable;
 import org.chromium.chrome.browser.toolbar.ToolbarColors;
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
+import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager;
 import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator.UrlExpansionObserver;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.ViewUtils;
@@ -376,7 +377,7 @@
 
             setLayoutTransition(null);
 
-            if (getMenuButtonWrapper() != null && !mIsBottomToolbarVisible) {
+            if (getMenuButtonWrapper() != null) {
                 getMenuButtonWrapper().setVisibility(View.VISIBLE);
             }
 
@@ -945,7 +946,7 @@
 
         int toolbarButtonVisibility = getToolbarButtonVisibility();
         mToolbarButtonsContainer.setVisibility(toolbarButtonVisibility);
-        if (!mIsBottomToolbarVisible && !getToolbarDataProvider().isInOverviewAndShowingOmnibox()) {
+        if (!getToolbarDataProvider().isInOverviewAndShowingOmnibox()) {
             if (mHomeButton != null && mHomeButton.getVisibility() != GONE) {
                 mHomeButton.setVisibility(toolbarButtonVisibility);
             }
@@ -1286,9 +1287,9 @@
             canvas.restore();
         }
 
-        // Draw the tab stack button and associated text.
+        // Draw the tab stack button and associated text if necessary.
         if (mTabSwitcherAnimationTabStackDrawable != null && mToggleTabStackButton != null
-                && !mIsBottomToolbarVisible && mUrlExpansionPercent != 1f) {
+                && mUrlExpansionPercent != 1f && !isTabSwitcherOnBottom()) {
             // Draw the tab stack button image.
             canvas.save();
             translateCanvasToView(mToolbarButtonsContainer, mToggleTabStackButton, canvas);
@@ -1316,7 +1317,7 @@
 
         // Draw the menu button if necessary.
         final ImageButton menuButton = getMenuButton();
-        if (menuButton != null && !mIsBottomToolbarVisible && !isShowingAppMenuUpdateBadge()
+        if (menuButton != null && !isShowingAppMenuUpdateBadge()
                 && mTabSwitcherAnimationMenuDrawable != null && mUrlExpansionPercent != 1f) {
             mTabSwitcherAnimationMenuDrawable.setBounds(menuButton.getPaddingLeft(),
                     menuButton.getPaddingTop(),
@@ -1334,8 +1335,8 @@
                                             : mTabSwitcherAnimationMenuBadgeDarkDrawable;
 
         final View menuBadge = getMenuBadge();
-        if (menuBadge != null && !mIsBottomToolbarVisible && isShowingAppMenuUpdateBadge()
-                && badgeDrawable != null && mUrlExpansionPercent != 1f) {
+        if (menuBadge != null && isShowingAppMenuUpdateBadge() && badgeDrawable != null
+                && mUrlExpansionPercent != 1f) {
             badgeDrawable.setBounds(menuBadge.getPaddingLeft(), menuBadge.getPaddingTop(),
                     menuBadge.getWidth() - menuBadge.getPaddingRight(),
                     menuBadge.getHeight() - menuBadge.getPaddingBottom());
@@ -1656,7 +1657,8 @@
     public void updateButtonVisibility() {
         if (mHomeButton == null) return;
 
-        boolean hideHomeButton = !mIsHomeButtonEnabled || mIsBottomToolbarVisible
+        boolean hideHomeButton = !mIsHomeButtonEnabled
+                || (mIsBottomToolbarVisible && BottomToolbarVariationManager.isHomeButtonOnBottom())
                 || (FeatureUtilities.isStartSurfaceEnabled()
                         && !FeatureUtilities.isStartSurfaceSinglePaneEnabled());
         if (hideHomeButton) {
@@ -1906,8 +1908,8 @@
         mIsHomeButtonEnabled = !inTabSwitcherMode;
 
         if (mToggleTabStackButton != null) {
-            mToggleTabStackButton.setVisibility(
-                    inTabSwitcherMode || mIsBottomToolbarVisible ? GONE : VISIBLE);
+            boolean isGone = inTabSwitcherMode || isTabSwitcherOnBottom();
+            mToggleTabStackButton.setVisibility(isGone ? GONE : VISIBLE);
         }
 
         if (getMenuButton() != null) {
@@ -2025,7 +2027,7 @@
                 MathUtils.flipSignIf(URL_FOCUS_TOOLBAR_BUTTONS_TRANSLATION_X_DP, isRtl) * density;
 
         final View menuButtonWrapper = getMenuButtonWrapper();
-        if (menuButtonWrapper != null && !mIsBottomToolbarVisible) {
+        if (menuButtonWrapper != null) {
             animator = ObjectAnimator.ofFloat(
                     menuButtonWrapper, TRANSLATION_X, toolbarButtonTranslationX);
             animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
@@ -2038,7 +2040,7 @@
             animators.add(animator);
         }
 
-        if (mToggleTabStackButton != null && !mIsBottomToolbarVisible) {
+        if (mToggleTabStackButton != null && !isTabSwitcherOnBottom()) {
             animator = ObjectAnimator.ofFloat(
                     mToggleTabStackButton, TRANSLATION_X, toolbarButtonTranslationX);
             animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
@@ -2077,7 +2079,7 @@
         animators.add(animator);
 
         final View menuButtonWrapper = getMenuButtonWrapper();
-        if (menuButtonWrapper != null && !mIsBottomToolbarVisible) {
+        if (menuButtonWrapper != null) {
             animator = ObjectAnimator.ofFloat(menuButtonWrapper, TRANSLATION_X, 0);
             animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
             animator.setStartDelay(URL_CLEAR_FOCUS_MENU_DELAY_MS);
@@ -2091,7 +2093,7 @@
             animators.add(animator);
         }
 
-        if (mToggleTabStackButton != null && !mIsBottomToolbarVisible) {
+        if (mToggleTabStackButton != null && !isTabSwitcherOnBottom()) {
             animator = ObjectAnimator.ofFloat(mToggleTabStackButton, TRANSLATION_X, 0);
             animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
             animator.setStartDelay(URL_CLEAR_FOCUS_TABSTACK_DELAY_MS);
@@ -2432,6 +2434,14 @@
         return getToolbarDataProvider().getPrimaryColor();
     }
 
+    /**
+     * @return Whether tab switcher is shown on the bottom toolbar.
+     *         Return false when bottom toolbar is not visible.
+     */
+    private boolean isTabSwitcherOnBottom() {
+        return mIsBottomToolbarVisible && BottomToolbarVariationManager.isTabSwitcherOnBottom();
+    }
+
     private void updateVisualsForLocationBarState() {
         // These are used to skip setting state unnecessarily while in the tab switcher.
         boolean inOrEnteringStaticTab =
@@ -2828,9 +2838,7 @@
     public void onBottomToolbarVisibilityChanged(boolean isVisible) {
         mIsBottomToolbarVisible = isVisible;
 
-        final int visibility = isVisible ? GONE : VISIBLE;
-        mToggleTabStackButton.setVisibility(visibility);
-        getMenuButtonWrapper().setVisibility(visibility);
+        mToggleTabStackButton.setVisibility(isTabSwitcherOnBottom() ? GONE : VISIBLE);
         updateButtonVisibility();
         mToolbarButtonsContainer.requestLayout();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index b215e4f..4511acd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -272,7 +272,7 @@
                 tab.reloadIgnoringCache();
             }
         }
-        tab.addObserver(createTabObserver());
+        mTabObserverRegistrar.registerActivityTabObserver(createTabObserver());
     }
 
     @Override
@@ -532,7 +532,8 @@
                         mToolbarCoordinator.showToolbarTemporarily();
                     }
                     if (mWebappInfo.isForWebApk()) {
-                        WebApkUma.recordNavigation(isNavigationInScope);
+                        boolean isChildTab = (tab.getParentId() != Tab.INVALID_TAB_ID);
+                        WebApkUma.recordNavigation(isChildTab, isNavigationInScope);
                     }
                 }
             }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarTest.java
index c25d54c..cdf951d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarTest.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.flags.FeatureUtilities;
+import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager.Variations;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.OverviewModeBehaviorWatcher;
@@ -43,7 +44,6 @@
     @Before
     public void setUp() throws InterruptedException {
         FeatureUtilities.setIsBottomToolbarEnabledForTesting(true);
-        mActivityTestRule.startMainActivityOnBlankPage();
     }
 
     @After
@@ -54,6 +54,7 @@
     @Test
     @MediumTest
     public void testBottomToolbarVisibility() {
+        mActivityTestRule.startMainActivityOnBlankPage();
         Assert.assertNotNull("BottomToolbarCoordinator should be constructed.",
                 mActivityTestRule.getActivity().getToolbarManager().getBottomToolbarCoordinator());
 
@@ -64,12 +65,15 @@
 
     @Test
     @MediumTest
-    public void testBottomToolbarTabSwitcherButton() throws ExecutionException {
+    public void testBottomToolbarTabSwitcherButton_Home_Search_Tab_Switcher()
+            throws ExecutionException {
+        BottomToolbarVariationManager.setVariation(Variations.HOME_SEARCH_TAB_SWITCHER);
+        mActivityTestRule.startMainActivityOnBlankPage();
         Assert.assertFalse("Tab switcher should not be visible.",
                 mActivityTestRule.getActivity().getOverviewModeBehavior().overviewVisible());
 
         ViewGroup bottomToolbar = mActivityTestRule.getActivity().findViewById(R.id.bottom_toolbar);
-        View tabSwitcherButton = bottomToolbar.findViewById(R.id.tab_switcher_button);
+        View tabSwitcherButton = bottomToolbar.findViewById(R.id.bottom_tab_switcher_button);
 
         OverviewModeBehaviorWatcher overviewModeWatcher = new OverviewModeBehaviorWatcher(
                 mActivityTestRule.getActivity().getOverviewModeBehavior(), true, false);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/AdaptiveToolbarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/AdaptiveToolbarTest.java
index 49f18ca..3cef483 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/AdaptiveToolbarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/top/AdaptiveToolbarTest.java
@@ -37,6 +37,8 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.flags.FeatureUtilities;
+import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager;
+import org.chromium.chrome.browser.toolbar.bottom.BottomToolbarVariationManager.Variations;
 import org.chromium.chrome.features.start_surface.StartSurfaceLayout;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -89,8 +91,9 @@
     // clang-format off
     @CommandLineFlags.Add({"enable-features=" + ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID +
             "<Study", "force-fieldtrials=Study/Group", NO_NEW_TAB_VARIATION_PARAMS})
-    public void testTopToolbar_WithGTS_WithBottomToolbar() throws InterruptedException {
+    public void testTopToolbar_WithGTS_WithBottomToolbar_Home_Search_Tab_Switcher() {
         // clang-format on
+        BottomToolbarVariationManager.setVariation(Variations.HOME_SEARCH_TAB_SWITCHER);
         setupFlagsAndLaunchActivity(true, true);
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
         Layout layout = cta.getLayoutManager().getOverviewLayout();
@@ -98,11 +101,66 @@
         enterTabSwitcher(cta);
         verifyTabSwitcherCardCount(cta, 1);
 
+        // Both menu and new tab button should be visible in top tab switcher toolbar.
         checkTopToolbarButtonsExistence(true);
-        checkTopToolbarButtonsVisibility(false);
+        checkTopToolbarButtonsVisibility(true);
 
         rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
 
+        // Both menu and new tab button should be visible in top tab switcher toolbar.
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(true);
+    }
+
+    @Test
+    @MediumTest
+    // clang-format off
+    @CommandLineFlags.Add({"enable-features=" + ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID +
+            "<Study", "force-fieldtrials=Study/Group", NO_NEW_TAB_VARIATION_PARAMS})
+    public void testTopToolbar_WithGTS_WithBottomToolbar_Home_Search_Share() {
+        // clang-format on
+        BottomToolbarVariationManager.setVariation(Variations.HOME_SEARCH_SHARE);
+        setupFlagsAndLaunchActivity(true, true);
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        Layout layout = cta.getLayoutManager().getOverviewLayout();
+        assertTrue(layout instanceof StartSurfaceLayout);
+        enterTabSwitcher(cta);
+        verifyTabSwitcherCardCount(cta, 1);
+
+        // Both menu and new tab button should be visible in top tab switcher toolbar.
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(true);
+
+        rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
+
+        // Both menu and new tab button should be visible in top tab switcher toolbar.
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(true);
+    }
+
+    @Test
+    @MediumTest
+    // clang-format off
+    @CommandLineFlags.Add({"enable-features=" + ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID +
+            "<Study", "force-fieldtrials=Study/Group", NO_NEW_TAB_VARIATION_PARAMS})
+    public void testTopToolbar_WithGTS_WithBottomToolbar_New_Tab_Search_Share() {
+        // clang-format on
+        BottomToolbarVariationManager.setVariation(Variations.NEW_TAB_SEARCH_SHARE);
+        setupFlagsAndLaunchActivity(true, true);
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        Layout layout = cta.getLayoutManager().getOverviewLayout();
+        assertTrue(layout instanceof StartSurfaceLayout);
+        enterTabSwitcher(cta);
+        verifyTabSwitcherCardCount(cta, 1);
+
+        // Menu button should be visible and new tab button should be invisible
+        // in top tab switcher toolbar.
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(false, true);
+
+        rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
+
+        // Both menu and new tab button should be visible in top tab switcher toolbar.
         checkTopToolbarButtonsExistence(true);
         checkTopToolbarButtonsVisibility(true);
     }
@@ -132,18 +190,59 @@
 
     @Test
     @MediumTest
-    public void testTopToolbar_WithoutGTS_WithBottomToolbar() throws InterruptedException {
+    public void testTopToolbar_WithoutGTS_WithBottomToolbar_Home_Search_Tab_Switcher() {
+        BottomToolbarVariationManager.setVariation(Variations.HOME_SEARCH_TAB_SWITCHER);
         setupFlagsAndLaunchActivity(true, false);
         final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
         Layout layout = cta.getLayoutManager().getOverviewLayout();
         assertFalse(layout instanceof StartSurfaceLayout);
         enterTabSwitcher(cta);
 
-        checkTopToolbarButtonsExistence(false);
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(true);
 
         rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
 
-        checkTopToolbarButtonsExistence(false);
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(true);
+    }
+
+    @Test
+    @MediumTest
+    public void testTopToolbar_WithoutGTS_WithBottomToolbar_Home_Search_Share() {
+        BottomToolbarVariationManager.setVariation(Variations.HOME_SEARCH_SHARE);
+        setupFlagsAndLaunchActivity(true, false);
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        Layout layout = cta.getLayoutManager().getOverviewLayout();
+        assertFalse(layout instanceof StartSurfaceLayout);
+        enterTabSwitcher(cta);
+
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(true);
+
+        rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
+
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(true);
+    }
+
+    @Test
+    @MediumTest
+    public void testTopToolbar_WithoutGTS_WithBottomToolbar_New_Tab_Search_Share() {
+        BottomToolbarVariationManager.setVariation(Variations.NEW_TAB_SEARCH_SHARE);
+        setupFlagsAndLaunchActivity(true, false);
+        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
+        Layout layout = cta.getLayoutManager().getOverviewLayout();
+        assertFalse(layout instanceof StartSurfaceLayout);
+        enterTabSwitcher(cta);
+
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(false, true);
+
+        rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
+
+        checkTopToolbarButtonsExistence(true);
+        checkTopToolbarButtonsVisibility(true);
     }
 
     private void checkTopToolbarButtonsExistence(boolean isNotNull) {
@@ -161,12 +260,16 @@
     }
 
     private void checkTopToolbarButtonsVisibility(boolean isVisible) {
-        int visibility = isVisible ? View.VISIBLE : View.GONE;
+        checkTopToolbarButtonsVisibility(isVisible, isVisible);
+    }
+
+    private void checkTopToolbarButtonsVisibility(
+            boolean isNewTabButtonVisible, boolean isMenuButtonVisible) {
         onView(withId(R.id.tab_switcher_toolbar)).check((v, noMatchingViewException) -> {
             View newTabButton = v.findViewById(R.id.new_tab_button);
             View menuButton = v.findViewById(R.id.menu_button_wrapper);
-            assertEquals(visibility, newTabButton.getVisibility());
-            assertEquals(visibility, menuButton.getVisibility());
+            assertEquals(isNewTabButtonVisible, newTabButton.getVisibility() == View.VISIBLE);
+            assertEquals(isMenuButtonVisible, menuButton.getVisibility() == View.VISIBLE);
         });
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManagerTest.java
index b2e1231..f38de87 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManagerTest.java
@@ -26,6 +26,7 @@
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
 import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarCoordinator;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.webapps.WebDisplayMode;
 import org.chromium.chrome.test.util.browser.webapps.WebApkInfoBuilder;
@@ -55,6 +56,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mTabProvider.getTab()).thenReturn(mTab);
+        when(mTab.getParentId()).thenReturn(Tab.INVALID_TAB_ID);
         setTabSecurityLevel(ConnectionSecurityLevel.NONE);
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java
index c37585a..93f3728 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CloseButtonNavigatorTest.java
@@ -10,38 +10,63 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.BlockJUnit4ClassRunner;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.ParameterizedRobolectricTestRunner;
+import org.robolectric.ParameterizedRobolectricTestRunner.Parameter;
+import org.robolectric.ParameterizedRobolectricTestRunner.Parameters;
+import org.robolectric.annotation.Config;
 
+import org.chromium.base.metrics.test.DisableHistogramsRule;
+import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabController;
 import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.webapps.WebappExtras;
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.NavigationEntry;
 import org.chromium.content_public.browser.NavigationHistory;
 import org.chromium.content_public.browser.WebContents;
 
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Stack;
 
 /**
  * Tests for {@link CloseButtonNavigator}.
  */
-@RunWith(BlockJUnit4ClassRunner.class)
+@RunWith(ParameterizedRobolectricTestRunner.class)
+@Config(sdk = 21, manifest = Config.NONE)
 public class CloseButtonNavigatorTest {
+    @Rule
+    public DisableHistogramsRule mDisableHistogramsRule = new DisableHistogramsRule();
+
+    @Parameters
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {{true}, {false}});
+    }
+
+    @Parameter(0)
+    public boolean mIsWebapp;
+
     @Mock public CustomTabActivityTabController mTabController;
     @Mock public CustomTabActivityTabProvider mTabProvider;
+    @Mock
+    public WebappExtras mWebappExtras;
+    @Mock
+    public BrowserServicesIntentDataProvider mIntentDataProvider;
 
-    // private final List<Tab> mTabs = new ArrayList<>();
     private final Stack<Tab> mTabs = new Stack<>();
     private CloseButtonNavigator mCloseButtonNavigator;
 
@@ -49,7 +74,13 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mCloseButtonNavigator = new CloseButtonNavigator(mTabController, mTabProvider);
+        if (!mIsWebapp) {
+            mWebappExtras = null;
+        }
+        doReturn(mWebappExtras).when(mIntentDataProvider).getWebappExtras();
+
+        mCloseButtonNavigator =
+                new CloseButtonNavigator(mTabController, mTabProvider, mIntentDataProvider);
 
         // Set up our mTabs to act as the mock tab model:
         // - mTabController.closeTab removes the top tab.
@@ -83,10 +114,15 @@
         when(tab.getWebContents()).thenReturn(webContents);
         when(webContents.getNavigationController()).thenReturn(navigationController);
         when(navigationController.getNavigationHistory()).thenReturn(history);
+        setParentTabId(tab, Tab.INVALID_TAB_ID);
 
         return tab;
     }
 
+    private void setParentTabId(Tab childTab, int parentTabId) {
+        when(childTab.getParentId()).thenReturn(parentTabId);
+    }
+
     private NavigationController currentTabsNavigationController() {
         // The navigation controller will be a mock object created in the above method.
         return mTabs.peek().getWebContents().getNavigationController();
@@ -113,10 +149,16 @@
     public void noCriteria_multipleTabs() {
         mTabs.push(createTabWithNavigationHistory( "www.blue.com/page1"));
         mTabs.push(createTabWithNavigationHistory( "www.blue.com/page2"));
+        setParentTabId(mTabs.get(1), mTabs.get(0).getId());
 
         mCloseButtonNavigator.navigateOnClose();
 
-        assertTrue(mTabs.empty());
+        if (mIsWebapp) {
+            assertEquals(1, mTabs.size());
+            verify(currentTabsNavigationController(), never()).goToNavigationIndex(anyInt());
+        } else {
+            assertTrue(mTabs.empty());
+        }
     }
 
     @Test
@@ -137,10 +179,16 @@
         mCloseButtonNavigator.setLandingPageCriteria(CloseButtonNavigatorTest::isRed);
         mTabs.push(createTabWithNavigationHistory( "www.blue.com/page1"));
         mTabs.push(createTabWithNavigationHistory( "www.blue.com/page2"));
+        setParentTabId(mTabs.get(1), mTabs.get(0).getId());
 
         mCloseButtonNavigator.navigateOnClose();
 
-        assertTrue(mTabs.empty());
+        if (mIsWebapp) {
+            assertEquals(1, mTabs.size());
+            verify(currentTabsNavigationController(), never()).goToNavigationIndex(anyInt());
+        } else {
+            assertTrue(mTabs.empty());
+        }
     }
 
     @Test
@@ -172,6 +220,7 @@
                 "www.blue.com/page1",
                 "www.blue.com/page2"
         ));
+        setParentTabId(mTabs.get(1), mTabs.get(0).getId());
 
         mCloseButtonNavigator.navigateOnClose();
 
@@ -190,12 +239,17 @@
                 "www.blue.com/page2",
                 "www.blue.com/page3"
         ));
+        setParentTabId(mTabs.get(1), mTabs.get(0).getId());
 
         mCloseButtonNavigator.navigateOnClose();
 
         assertEquals(1, mTabs.size());
-        verify(currentTabsNavigationController()).goToNavigationIndex(eq(0));
-        verify(currentTabsNavigationController()).goToNavigationIndex(anyInt());
+        if (mIsWebapp) {
+            verify(currentTabsNavigationController(), never()).goToNavigationIndex(anyInt());
+        } else {
+            verify(currentTabsNavigationController()).goToNavigationIndex(eq(0));
+            verify(currentTabsNavigationController()).goToNavigationIndex(anyInt());
+        }
     }
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
index e11cb726..234c61d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
@@ -35,6 +35,8 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.components.search_engines.TemplateUrl;
@@ -92,17 +94,16 @@
     @Test
     @SmallTest
     public void receiveSearchEngineChoiceRequest() {
-        assertFalse(ContextUtils.getAppSharedPreferences().contains(
-                SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP));
+        SharedPreferencesManager prefs = SharedPreferencesManager.getInstance();
+        assertFalse(prefs.contains(ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP));
         SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest();
-        assertTrue(ContextUtils.getAppSharedPreferences().contains(
-                SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP));
+        assertTrue(prefs.contains(ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP));
 
-        long firstTimestamp = ContextUtils.getAppSharedPreferences().getLong(
-                SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP, 0);
+        long firstTimestamp =
+                prefs.readLong(ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP);
         SearchEngineChoiceNotification.receiveSearchEngineChoiceRequest();
-        long secondTimestamp = ContextUtils.getAppSharedPreferences().getLong(
-                SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP, 0);
+        long secondTimestamp =
+                prefs.readLong(ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP);
 
         assertEquals(firstTimestamp, secondTimestamp);
     }
@@ -110,15 +111,13 @@
     @Test
     @SmallTest
     public void handleSearchEngineChoice_ignoredWhenNotRequested() {
-        assertFalse(ContextUtils.getAppSharedPreferences().contains(
-                SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION));
+        SharedPreferencesManager prefs = SharedPreferencesManager.getInstance();
+        assertFalse(prefs.contains(ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_PRESENTED_VERSION));
 
         SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, null);
 
         assertFalse("When not requested, the call should have been ignored.",
-                ContextUtils.getAppSharedPreferences().contains(
-                        SearchEngineChoiceNotification
-                                .PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION));
+                prefs.contains(ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_PRESENTED_VERSION));
 
         assertEquals(0,
                 ShadowRecordHistogram.getHistogramValueCountForTesting(
@@ -140,16 +139,14 @@
                         "Android.SearchEngineChoice.Events",
                         SearchEngineChoiceMetrics.Events.SNACKBAR_SHOWN));
 
+        SharedPreferencesManager prefs = SharedPreferencesManager.getInstance();
         assertTrue("Version of the app should be persisted upon prompting.",
-                ContextUtils.getAppSharedPreferences().contains(
-                        SearchEngineChoiceNotification
-                                .PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION));
+                prefs.contains(ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_PRESENTED_VERSION));
 
         assertEquals("Presented version should be set to the current product version.",
                 ChromeVersionInfo.getProductVersion(),
-                ContextUtils.getAppSharedPreferences().getString(
-                        SearchEngineChoiceNotification.PREF_SEARCH_ENGINE_CHOICE_PRESENTED_VERSION,
-                        null));
+                prefs.readString(
+                        ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_PRESENTED_VERSION, null));
     }
 
     @Test
@@ -161,8 +158,8 @@
 
         SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager);
         assertFalse("Second call removes the preference for search engine choice before.",
-                ContextUtils.getAppSharedPreferences().contains(
-                        SearchEngineChoiceMetrics.PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE));
+                SharedPreferencesManager.getInstance().contains(
+                        ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE));
 
         SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager);
 
@@ -202,8 +199,8 @@
 
         assertFalse(
                 "First handleSearchEngineChoice call after prompt removes SE choice before pref.",
-                ContextUtils.getAppSharedPreferences().contains(
-                        SearchEngineChoiceMetrics.PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE));
+                SharedPreferencesManager.getInstance().contains(
+                        ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE));
 
         assertEquals(0,
                 ShadowRecordHistogram.getHistogramValueCountForTesting(
@@ -227,8 +224,8 @@
         SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager);
         assertFalse(
                 "First handleSearchEngineChoice call after prompt removes SE choice before pref.",
-                ContextUtils.getAppSharedPreferences().contains(
-                        SearchEngineChoiceMetrics.PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE));
+                SharedPreferencesManager.getInstance().contains(
+                        ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE));
 
         doReturn(mAlternativeSearchEngine)
                 .when(mTemplateUrlService)
@@ -270,8 +267,8 @@
 
         assertFalse(
                 "First handleSearchEngineChoice call after prompt removes SE choice before pref.",
-                ContextUtils.getAppSharedPreferences().contains(
-                        SearchEngineChoiceMetrics.PREF_SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE));
+                SharedPreferencesManager.getInstance().contains(
+                        ChromePreferenceKeys.SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE));
 
         SearchEngineChoiceNotification.handleSearchEngineChoice(mContext, mSnackbarManager);
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index cbe0a11..6991e7c 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -10486,6 +10486,35 @@
       The limit on "<ph name="APP_NAME">$1<ex>Google Photos</ex></ph>" that your parent set ran out. You can use it for <ph name="TIME_LIMIT">$2<ex>2 hours and 30 minutes</ex></ph> tomorrow.
     </message>
 
+    <!-- Extension request -->
+    <if expr="not is_android">
+      <message name="IDS_ENTERPRISE_EXTENSION_REQUEST_APPROVED_TITLE" desc="The notification title when there are some extension requests approved.">
+        {NUM_EXTENSIONS, plural,
+          =1 {An extension has been approved}
+          other {# extensions have been approved}}
+      </message>
+      <message name="IDS_ENTERPRISE_EXTENSION_REQUEST_REJECTED_TITLE" desc="The notification title when there are some extension requests rejected.">
+        {NUM_EXTENSIONS, plural,
+          =1 {An extension has been rejected}
+          other {# extensions have been rejected}}
+      </message>
+      <message name="IDS_ENTERPRISE_EXTENSION_REQUEST_FORCE_INSTALLED_TITLE" desc="The notification title when there are some extension requests force installed.">
+        {NUM_EXTENSIONS, plural,
+          =1 {An extension has been installed by your administrator}
+          other {# extensions have been installed by your administrator}}
+      </message>
+
+      <message name="IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_INSTALL" desc="The notification message that tell user how to install the approved extension.">
+        {NUM_EXTENSIONS, plural,
+          =1 {Click to install the extension}
+          other {Click to install these extensions}}
+      </message>
+      <message name="IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_VIEW" desc="The notification message that show user the reviewed installed extension requests.">
+        {NUM_EXTENSIONS, plural,
+          =1 {Click to view the extension}
+          other {Click to view these extensions}}
+      </message>
+    </if>
   </messages>
 </release>
 </grit>
diff --git a/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_APPROVED_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_APPROVED_TITLE.png.sha1
new file mode 100644
index 0000000..24482fe
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_APPROVED_TITLE.png.sha1
@@ -0,0 +1 @@
+56753fdeb3266b58301fb3c9aed33fff5a53e503
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_INSTALL.png.sha1 b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_INSTALL.png.sha1
new file mode 100644
index 0000000..24482fe
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_INSTALL.png.sha1
@@ -0,0 +1 @@
+56753fdeb3266b58301fb3c9aed33fff5a53e503
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_VIEW.png.sha1 b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_VIEW.png.sha1
new file mode 100644
index 0000000..cc5b760
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_VIEW.png.sha1
@@ -0,0 +1 @@
+11d8350374f809e9fdcd389bd6d93b565b83ef98
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_FORCE_INSTALLED_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_FORCE_INSTALLED_TITLE.png.sha1
new file mode 100644
index 0000000..5e589d0f
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_FORCE_INSTALLED_TITLE.png.sha1
@@ -0,0 +1 @@
+5f7ecf4d397c645aac55c4bd2acf0583943aef26
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_REJECTED_TITLE.png.sha1 b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_REJECTED_TITLE.png.sha1
new file mode 100644
index 0000000..cc5b760
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_ENTERPRISE_EXTENSION_REQUEST_REJECTED_TITLE.png.sha1
@@ -0,0 +1 @@
+11d8350374f809e9fdcd389bd6d93b565b83ef98
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 553c2b2..9df82e6 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -72,9 +72,7 @@
 
 # This proto library is used for non-android NTPs below.
 proto_library("ntp_background_proto") {
-  sources = [
-    "search/background/ntp_background.proto",
-  ]
+  sources = [ "search/background/ntp_background.proto" ]
   generate_python = false
 }
 
@@ -3075,6 +3073,8 @@
       "chrome_browser_field_trials_desktop.h",
       "chrome_process_singleton.cc",
       "chrome_process_singleton.h",
+      "component_updater/intervention_policy_database_component_installer.cc",
+      "component_updater/intervention_policy_database_component_installer.h",
       "component_updater/tls_deprecation_config_component_installer.cc",
       "component_updater/tls_deprecation_config_component_installer.h",
       "custom_handlers/register_protocol_handler_permission_request.cc",
@@ -3117,6 +3117,8 @@
       "enterprise_reporting/browser_report_generator.h",
       "enterprise_reporting/extension_info.cc",
       "enterprise_reporting/extension_info.h",
+      "enterprise_reporting/notification/extension_request_notification.cc",
+      "enterprise_reporting/notification/extension_request_notification.h",
       "enterprise_reporting/policy_info.cc",
       "enterprise_reporting/policy_info.h",
       "enterprise_reporting/prefs.cc",
@@ -3385,6 +3387,8 @@
       "resource_coordinator/decision_details.h",
       "resource_coordinator/discard_metrics_lifecycle_unit_observer.cc",
       "resource_coordinator/discard_metrics_lifecycle_unit_observer.h",
+      "resource_coordinator/intervention_policy_database.cc",
+      "resource_coordinator/intervention_policy_database.h",
       "resource_coordinator/leveldb_site_characteristics_database.cc",
       "resource_coordinator/leveldb_site_characteristics_database.h",
       "resource_coordinator/lifecycle_unit.cc",
@@ -3680,6 +3684,7 @@
       "//chrome/app/vector_icons",
       "//chrome/browser/policy:path_parser",
       "//chrome/browser/profile_resetter:profile_reset_report_proto",
+      "//chrome/browser/resource_coordinator:intervention_policy_database_proto",
       "//chrome/browser/resource_coordinator:tab_metrics_event_proto",
       "//chrome/browser/resource_coordinator/tab_ranker",
       "//chrome/browser/resources:component_extension_resources",
@@ -5329,27 +5334,19 @@
 
 if (is_android) {
   proto_library("client_discourse_context_proto") {
-    sources = [
-      "android/proto/client_discourse_context.proto",
-    ]
+    sources = [ "android/proto/client_discourse_context.proto" ]
   }
 
   proto_library("delta_file_proto") {
-    sources = [
-      "android/proto/delta_file.proto",
-    ]
+    sources = [ "android/proto/delta_file.proto" ]
   }
 
   proto_library("explore_sites_proto") {
-    sources = [
-      "android/explore_sites/catalog.proto",
-    ]
+    sources = [ "android/explore_sites/catalog.proto" ]
   }
 
   proto_library("usage_stats_proto") {
-    sources = [
-      "android/usage_stats/website_event.proto",
-    ]
+    sources = [ "android/usage_stats/website_event.proto" ]
   }
 }
 
@@ -5385,27 +5382,19 @@
 }
 
 source_set("theme_properties") {
-  sources = [
-    "themes/theme_properties.h",
-  ]
+  sources = [ "themes/theme_properties.h" ]
 }
 
 proto_library("availability_protos") {
-  sources = [
-    "availability/proto/availability_prober_cache_entry.proto",
-  ]
+  sources = [ "availability/proto/availability_prober_cache_entry.proto" ]
 }
 
 proto_library("resource_prefetch_predictor_proto") {
-  sources = [
-    "predictors/resource_prefetch_predictor.proto",
-  ]
+  sources = [ "predictors/resource_prefetch_predictor.proto" ]
 }
 
 proto_library("permissions_proto") {
-  sources = [
-    "permissions/crowd_deny.proto",
-  ]
+  sources = [ "permissions/crowd_deny.proto" ]
 }
 
 grit("resources") {
@@ -5450,24 +5439,16 @@
   if (enable_plugins) {
     # .json is not in the default sources_assignment_filter.
     if (is_chromeos) {
-      inputs = [
-        "resources/plugin_metadata/plugins_chromeos.json",
-      ]
+      inputs = [ "resources/plugin_metadata/plugins_chromeos.json" ]
     }
     if (is_linux && !is_chromeos) {
-      inputs = [
-        "resources/plugin_metadata/plugins_linux.json",
-      ]
+      inputs = [ "resources/plugin_metadata/plugins_linux.json" ]
     }
     if (is_mac) {
-      inputs = [
-        "resources/plugin_metadata/plugins_mac.json",
-      ]
+      inputs = [ "resources/plugin_metadata/plugins_mac.json" ]
     }
     if (is_win) {
-      inputs = [
-        "resources/plugin_metadata/plugins_win.json",
-      ]
+      inputs = [ "resources/plugin_metadata/plugins_win.json" ]
     }
   }
 
@@ -5523,12 +5504,8 @@
 if (is_chrome_branded) {
   action("chrome_internal_resources_gen") {
     script = "internal/transform_additional_modules_list.py"
-    sources = [
-      "internal/resources/additional_modules_list.input",
-    ]
-    outputs = [
-      additional_modules_list_file,
-    ]
+    sources = [ "internal/resources/additional_modules_list.input" ]
+    outputs = [ additional_modules_list_file ]
     args = rebase_path(sources, root_build_dir) +
            rebase_path(outputs, root_build_dir)
   }
@@ -5572,26 +5549,16 @@
 
 action("expired_flags_list_gen") {
   script = "//tools/flags/generate_expired_list.py"
-  sources = [
-    "flag-metadata.json",
-  ]
-  inputs = [
-    "//chrome/VERSION",
-  ]
-  outputs = [
-    "$root_gen_dir/chrome/browser/expired_flags_list.cc",
-  ]
+  sources = [ "flag-metadata.json" ]
+  inputs = [ "//chrome/VERSION" ]
+  outputs = [ "$root_gen_dir/chrome/browser/expired_flags_list.cc" ]
   args = rebase_path(sources, root_build_dir) +
          rebase_path(outputs, root_build_dir)
 }
 
 source_set("expired_flags_list") {
-  deps = [
-    ":expired_flags_list_gen",
-  ]
-  sources = [
-    "$root_gen_dir/chrome/browser/expired_flags_list.cc",
-  ]
+  deps = [ ":expired_flags_list_gen" ]
+  sources = [ "$root_gen_dir/chrome/browser/expired_flags_list.cc" ]
 }
 
 # Use a static library here because many test binaries depend on this but don't
@@ -5954,21 +5921,15 @@
       "//components/translate/content/common",
     ]
 
-    public_deps = [
-      "//net:test_support",
-    ]
+    public_deps = [ "//net:test_support" ]
   }
 }
 
 if (is_android) {
   java_cpp_enum("sharing_send_message_result_generated_enum") {
-    sources = [
-      "sharing/sharing_send_message_result.h",
-    ]
+    sources = [ "sharing/sharing_send_message_result.h" ]
   }
   java_cpp_enum("sharing_dialog_type_generated_enum") {
-    sources = [
-      "sharing/sharing_metrics.h",
-    ]
+    sources = [ "sharing/sharing_metrics.h" ]
   }
 }
diff --git a/chrome/browser/OWNERS b/chrome/browser/OWNERS
index 8eb63f5..365eb26 100644
--- a/chrome/browser/OWNERS
+++ b/chrome/browser/OWNERS
@@ -69,10 +69,10 @@
 per-file web_bluetooth*=file://content/browser/bluetooth/OWNERS
 
 # For security review.
-per-file chrome_browser_interface_binders.cc=set noparent
-per-file chrome_browser_interface_binders.cc=file://ipc/SECURITY_OWNERS
-per-file chrome_content_browser_client_receiver_bindings.cc=set noparent
-per-file chrome_content_browser_client_receiver_bindings.cc=file://ipc/SECURITY_OWNERS
+per-file chrome_browser_interface_binders.*=set noparent
+per-file chrome_browser_interface_binders.*=file://ipc/SECURITY_OWNERS
+per-file chrome_content_browser_client_receiver_bindings.*=set noparent
+per-file chrome_content_browser_client_receiver_bindings.*=file://ipc/SECURITY_OWNERS
 
 # BackForwardCache
 per-file chrome_back_forward_cache_browsertest.cc=arthursonzogni@chromium.org
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b9403ab..efa95d5 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1230,6 +1230,24 @@
 #endif  // OS_ANDROID
 
 #if defined(OS_ANDROID)
+const FeatureEntry::FeatureParam kChromeDuet_HomeSearchTabSwitcher[] = {
+    {"chrome_duet_variation", "HomeSearchTabSwitcher"}};
+
+const FeatureEntry::FeatureParam kChromeDuet_HomeSearchShare[] = {
+    {"chrome_duet_variation", "HomeSearchShare"}};
+
+const FeatureEntry::FeatureParam kChromeDuet_NewTabSearchShare[] = {
+    {"chrome_duet_variation", "NewTabSearchShare"}};
+
+const FeatureEntry::FeatureVariation kChromeDuetVariations[] = {
+    {"Home-Search-TabSwitcher Variation", kChromeDuet_HomeSearchTabSwitcher,
+     base::size(kChromeDuet_HomeSearchTabSwitcher), nullptr},
+    {"Home-Search-Share Variation", kChromeDuet_HomeSearchShare,
+     base::size(kChromeDuet_HomeSearchShare), nullptr},
+    {"NewTab-Search-Share Variation", kChromeDuet_NewTabSearchShare,
+     base::size(kChromeDuet_NewTabSearchShare), nullptr},
+};
+
 const FeatureEntry::FeatureParam kTabGridLayoutAndroid_NewTabVariation[] = {
     {"tab_grid_layout_android_new_tab", "NewTabVariation"}};
 
@@ -2064,7 +2082,9 @@
 #if defined(OS_ANDROID)
     {"enable-chrome-duet", flag_descriptions::kChromeDuetName,
      flag_descriptions::kChromeDuetDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kChromeDuetFeature)},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kChromeDuetFeature,
+                                    kChromeDuetVariations,
+                                    "ChromeDuet")},
     {"enable-chrome-duet-labels", flag_descriptions::kChromeDuetLabelsName,
      flag_descriptions::kChromeDuetLabelsDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kChromeDuetLabeled)},
diff --git a/chrome/browser/android/favicon_helper.cc b/chrome/browser/android/favicon_helper.cc
index 108e576..b9ea8a4 100644
--- a/chrome/browser/android/favicon_helper.cc
+++ b/chrome/browser/android/favicon_helper.cc
@@ -47,29 +47,6 @@
 
 namespace {
 
-void OnFaviconBitmapResultAvailable(
-    const JavaRef<jobject>& j_favicon_image_callback,
-    const favicon_base::FaviconRawBitmapResult& result) {
-  JNIEnv* env = AttachCurrentThread();
-
-  // Convert favicon_image_result to java objects.
-  ScopedJavaLocalRef<jstring> j_icon_url =
-      ConvertUTF8ToJavaString(env, result.icon_url.spec());
-  ScopedJavaLocalRef<jobject> j_favicon_bitmap;
-  if (result.is_valid()) {
-    SkBitmap favicon_bitmap;
-    gfx::PNGCodec::Decode(result.bitmap_data->front(),
-                          result.bitmap_data->size(),
-                          &favicon_bitmap);
-    if (!favicon_bitmap.isNull())
-      j_favicon_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap);
-  }
-
-  // Call java side OnFaviconBitmapResultAvailable method.
-  Java_FaviconImageCallback_onFaviconAvailable(env, j_favicon_image_callback,
-                                               j_favicon_bitmap, j_icon_url);
-}
-
 void OnEnsureIconIsAvailableFinished(
     const ScopedJavaGlobalRef<jobject>& j_availability_callback,
     bool newly_available) {
@@ -111,7 +88,8 @@
     return false;
 
   favicon_base::FaviconRawBitmapCallback callback_runner =
-      base::BindOnce(&OnFaviconBitmapResultAvailable,
+      base::BindOnce(&FaviconHelper::OnFaviconBitmapResultAvailable,
+                     weak_ptr_factory_.GetWeakPtr(),
                      ScopedJavaGlobalRef<jobject>(j_favicon_image_callback));
 
   // |j_page_url| is an origin, and it may not have had a favicon associated
@@ -157,13 +135,13 @@
     return false;
   history_ui_favicon_request_handler->GetRawFaviconForPageURL(
       page_url, static_cast<int>(j_desired_size_in_pixel),
-      base::BindOnce(&OnFaviconBitmapResultAvailable,
+      base::BindOnce(&FaviconHelper::OnFaviconBitmapResultAvailable,
+                     weak_ptr_factory_.GetWeakPtr(),
                      ScopedJavaGlobalRef<jobject>(j_favicon_image_callback)),
       favicon::FaviconRequestPlatform::kMobile,
       favicon::HistoryUiFaviconRequestOrigin::kRecentTabs,
       /*icon_url_for_uma=*/
-      open_tabs ? open_tabs->GetIconUrlForPageUrl(page_url) : GURL(),
-      cancelable_task_tracker_.get());
+      open_tabs ? open_tabs->GetIconUrlForPageUrl(page_url) : GURL());
   return true;
 }
 
@@ -238,6 +216,7 @@
   return ret;
 }
 
+// static
 void FaviconHelper::OnFaviconDownloaded(
     const ScopedJavaGlobalRef<jobject>& j_availability_callback,
     Profile* profile,
@@ -266,6 +245,7 @@
       base::Bind(&OnEnsureIconIsAvailableFinished, j_availability_callback));
 }
 
+// static
 void FaviconHelper::OnFaviconImageResultAvailable(
     const ScopedJavaGlobalRef<jobject>& j_availability_callback,
     Profile* profile,
@@ -289,3 +269,25 @@
       base::BindOnce(&FaviconHelper::OnFaviconDownloaded,
                      j_availability_callback, profile, page_url, icon_type));
 }
+
+void FaviconHelper::OnFaviconBitmapResultAvailable(
+    const JavaRef<jobject>& j_favicon_image_callback,
+    const favicon_base::FaviconRawBitmapResult& result) {
+  JNIEnv* env = AttachCurrentThread();
+
+  // Convert favicon_image_result to java objects.
+  ScopedJavaLocalRef<jstring> j_icon_url =
+      ConvertUTF8ToJavaString(env, result.icon_url.spec());
+  ScopedJavaLocalRef<jobject> j_favicon_bitmap;
+  if (result.is_valid()) {
+    SkBitmap favicon_bitmap;
+    gfx::PNGCodec::Decode(result.bitmap_data->front(),
+                          result.bitmap_data->size(), &favicon_bitmap);
+    if (!favicon_bitmap.isNull())
+      j_favicon_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap);
+  }
+
+  // Call java side OnFaviconBitmapResultAvailable method.
+  Java_FaviconImageCallback_onFaviconAvailable(env, j_favicon_image_callback,
+                                               j_favicon_bitmap, j_icon_url);
+}
diff --git a/chrome/browser/android/favicon_helper.h b/chrome/browser/android/favicon_helper.h
index 2b72f76..bb4bf4d 100644
--- a/chrome/browser/android/favicon_helper.h
+++ b/chrome/browser/android/favicon_helper.h
@@ -12,6 +12,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "components/favicon_base/favicon_types.h"
 #include "url/gurl.h"
@@ -55,6 +56,8 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(FaviconHelperTest, GetLargestSizeIndex);
 
+  virtual ~FaviconHelper();
+
   static void OnFaviconImageResultAvailable(
       const base::android::ScopedJavaGlobalRef<jobject>&
           j_availability_callback,
@@ -79,9 +82,16 @@
 
   static size_t GetLargestSizeIndex(const std::vector<gfx::Size>& sizes);
 
+  // This function is expected to be bound to a WeakPtr<FaviconHelper>, so that
+  // it won't be run if the FaviconHelper is deleted and
+  // |j_favicon_image_callback| isn't executed in that case.
+  void OnFaviconBitmapResultAvailable(
+      const base::android::JavaRef<jobject>& j_favicon_image_callback,
+      const favicon_base::FaviconRawBitmapResult& result);
+
   std::unique_ptr<base::CancelableTaskTracker> cancelable_task_tracker_;
 
-  virtual ~FaviconHelper();
+  base::WeakPtrFactory<FaviconHelper> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FaviconHelper);
 };
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index c176e05..38dd1b3 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -341,6 +341,7 @@
 #endif
 
 #if !defined(OS_ANDROID)
+#include "chrome/browser/component_updater/intervention_policy_database_component_installer.h"
 #include "chrome/browser/component_updater/tls_deprecation_config_component_installer.h"
 #include "chrome/browser/resource_coordinator/tab_manager.h"
 #endif
@@ -548,6 +549,8 @@
 #endif  // defined(OS_WIN)
 
 #if !defined(OS_ANDROID)
+  RegisterInterventionPolicyDatabaseComponent(
+      cus, g_browser_process->GetTabManager()->intervention_policy_database());
   RegisterTLSDeprecationConfigComponent(cus, path);
 #endif
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 46c5bc0..b471059 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -811,6 +811,8 @@
     "child_accounts/time_limit_override.h",
     "child_accounts/time_limits/app_activity_registry.cc",
     "child_accounts/time_limits/app_activity_registry.h",
+    "child_accounts/time_limits/app_activity_report_interface.cc",
+    "child_accounts/time_limits/app_activity_report_interface.h",
     "child_accounts/time_limits/app_service_wrapper.cc",
     "child_accounts/time_limits/app_service_wrapper.h",
     "child_accounts/time_limits/app_time_controller.cc",
@@ -2691,6 +2693,7 @@
     "child_accounts/time_limits/app_activity_registry_unittest.cc",
     "child_accounts/time_limits/app_service_wrapper_unittest.cc",
     "child_accounts/time_limits/app_time_controller_unittest.cc",
+    "child_accounts/time_limits/app_types_unittest.cc",
     "child_accounts/usage_time_limit_processor_unittest.cc",
     "child_accounts/usage_time_state_notifier_unittest.cc",
     "chrome_content_browser_client_chromeos_part_unittest.cc",
diff --git a/chrome/browser/chromeos/child_accounts/child_user_service.cc b/chrome/browser/chromeos/child_accounts/child_user_service.cc
index 1bf13cec..b199b12 100644
--- a/chrome/browser/chromeos/child_accounts/child_user_service.cc
+++ b/chrome/browser/chromeos/child_accounts/child_user_service.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/child_accounts/child_user_service.h"
 
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.h"
 #include "chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.h"
 #include "chrome/browser/chromeos/child_accounts/time_limits/web_time_limit_enforcer.h"
 #include "chrome/browser/profiles/profile.h"
@@ -60,6 +61,21 @@
   web_time_enforcer->OnWebTimeLimitEnded();
 }
 
+app_time::AppActivityReportInterface::ReportParams
+ChildUserService::GenerateAppActivityReport(
+    enterprise_management::ChildStatusReportRequest* report) const {
+  DCHECK(app_time_controller_);
+  return app_time_controller_->app_registry()->GenerateAppActivityReport(
+      report);
+}
+
+void ChildUserService::AppActivityReportSubmitted(
+    base::Time report_generation_timestamp) {
+  DCHECK(app_time_controller_);
+  app_time_controller_->app_registry()->CleanRegistry(
+      report_generation_timestamp);
+}
+
 bool ChildUserService::WebTimeLimitReached() const {
   if (!app_time_controller_)
     return false;
diff --git a/chrome/browser/chromeos/child_accounts/child_user_service.h b/chrome/browser/chromeos/child_accounts/child_user_service.h
index c72aa67..7a953d9 100644
--- a/chrome/browser/chromeos/child_accounts/child_user_service.h
+++ b/chrome/browser/chromeos/child_accounts/child_user_service.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.h"
 #include "chrome/browser/chromeos/child_accounts/time_limits/web_time_limit_interface.h"
 #include "components/keyed_service/core/keyed_service.h"
 
@@ -19,6 +20,10 @@
 class BrowserContext;
 }  // namespace content
 
+namespace enterprise_management {
+class ChildStatusReportRequest;
+}  // namespace enterprise_management
+
 class GURL;
 
 namespace chromeos {
@@ -31,7 +36,8 @@
 // TODO(crbug.com/1022231): Migrate ConsumerStatusReportingService,
 // EventBasedStatusReporting and ScreenTimeController to ChildUserService.
 class ChildUserService : public KeyedService,
-                         public app_time::WebTimeLimitInterface {
+                         public app_time::WebTimeLimitInterface,
+                         public app_time::AppActivityReportInterface {
  public:
   // Used for tests to get internal implementation details.
   class TestApi {
@@ -51,10 +57,16 @@
   ChildUserService& operator=(const ChildUserService&) = delete;
   ~ChildUserService() override;
 
-  // WebTimeLimitInterface:
+  // app_time::WebTimeLimitInterface:
   void PauseWebActivity(const std::string& app_id) override;
   void ResumeWebActivity(const std::string& app_id) override;
 
+  // app_time::AppActivityReportInterface:
+  app_time::AppActivityReportInterface::ReportParams GenerateAppActivityReport(
+      enterprise_management::ChildStatusReportRequest* report) const override;
+  void AppActivityReportSubmitted(
+      base::Time report_generation_timestamp) override;
+
   // Returns whether web time limit was reached for child user.
   // Always returns false if per-app times limits feature is disabled.
   bool WebTimeLimitReached() const;
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.cc b/chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.cc
index f22acb5..7d25ebd 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.cc
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.cc
@@ -5,10 +5,50 @@
 #include "chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.h"
 
 #include "base/stl_util.h"
+#include "components/policy/proto/device_management_backend.pb.h"
 
 namespace chromeos {
 namespace app_time {
 
+namespace {
+enterprise_management::App::AppType AppTypeForReporting(
+    apps::mojom::AppType type) {
+  switch (type) {
+    case apps::mojom::AppType::kArc:
+      return enterprise_management::App::ARC;
+    case apps::mojom::AppType::kBuiltIn:
+      return enterprise_management::App::BUILT_IN;
+    case apps::mojom::AppType::kCrostini:
+      return enterprise_management::App::CROSTINI;
+    case apps::mojom::AppType::kExtension:
+      return enterprise_management::App::EXTENSION;
+    case apps::mojom::AppType::kWeb:
+      return enterprise_management::App::WEB;
+    default:
+      return enterprise_management::App::UNKNOWN;
+  }
+}
+
+enterprise_management::AppActivity::AppState AppStateForReporting(
+    AppState state) {
+  switch (state) {
+    case AppState::kAvailable:
+      return enterprise_management::AppActivity::DEFAULT;
+    case AppState::kAlwaysAvailable:
+      return enterprise_management::AppActivity::ALWAYS_AVAILABLE;
+    case AppState::kBlocked:
+      return enterprise_management::AppActivity::BLOCKED;
+    case AppState::kLimitReached:
+      return enterprise_management::AppActivity::LIMIT_REACHED;
+    case AppState::kUninstalled:
+      return enterprise_management::AppActivity::UNINSTALLED;
+    default:
+      return enterprise_management::AppActivity::UNKNOWN;
+  }
+}
+
+}  // namespace
+
 AppActivityRegistry::AppDetails::AppDetails() = default;
 
 AppActivityRegistry::AppDetails::AppDetails(const AppActivity& activity)
@@ -130,6 +170,65 @@
   return activity_registry_.at(app_id).activity.RunningActiveTime();
 }
 
+AppActivityReportInterface::ReportParams
+AppActivityRegistry::GenerateAppActivityReport(
+    enterprise_management::ChildStatusReportRequest* report) const {
+  // TODO(agawronska): We should also report the ongoing activity if it started
+  // before the reporting, because it could have been going for a long time.
+  const base::Time timestamp = base::Time::Now();
+  bool anything_reported = false;
+
+  for (const auto& entry : activity_registry_) {
+    const AppId& app_id = entry.first;
+    const AppActivity& registered_activity = entry.second.activity;
+
+    // Do not report if there is no activity.
+    if (registered_activity.active_times().empty())
+      continue;
+
+    enterprise_management::AppActivity* app_activity =
+        report->add_app_activity();
+    enterprise_management::App* app_info = app_activity->mutable_app_info();
+    app_info->set_app_id(app_id.app_id());
+    app_info->set_app_type(AppTypeForReporting(app_id.app_type()));
+    // AppService is is only different for ARC++ apps.
+    if (app_id.app_type() == apps::mojom::AppType::kArc) {
+      app_info->add_additional_app_id(
+          app_service_wrapper_->GetAppServiceId(app_id));
+    }
+    app_activity->set_app_state(
+        AppStateForReporting(registered_activity.app_state()));
+    app_activity->set_populated_at(timestamp.ToJavaTime());
+
+    for (const auto& active_time : registered_activity.active_times()) {
+      enterprise_management::TimePeriod* time_period =
+          app_activity->add_active_time_periods();
+      time_period->set_start_timestamp(active_time.active_from().ToJavaTime());
+      time_period->set_end_timestamp(active_time.active_to().ToJavaTime());
+    }
+    anything_reported = true;
+  }
+
+  return AppActivityReportInterface::ReportParams{timestamp, anything_reported};
+}
+
+void AppActivityRegistry::CleanRegistry(base::Time timestamp) {
+  for (auto it = activity_registry_.begin(); it != activity_registry_.end();) {
+    const AppId& app_id = it->first;
+    AppActivity& registered_activity = it->second.activity;
+    // TODO(agawronska): Update data stored in user pref.
+    registered_activity.RemoveActiveTimeEarlierThan(timestamp);
+    // Remove app that was uninstalled and does not have any past activity
+    // stored.
+    if (GetAppState(app_id) == AppState::kUninstalled &&
+        registered_activity.active_times().empty()) {
+      it = activity_registry_.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+
 void AppActivityRegistry::Add(const AppId& app_id) {
   auto result = activity_registry_.emplace(
       app_id, AppDetails(AppActivity(AppState::kAvailable)));
@@ -158,16 +257,5 @@
   activity_registry_.at(app_id).activity.SetAppInactive(timestamp);
 }
 
-void AppActivityRegistry::CleanRegistry() {
-  for (auto it = activity_registry_.cbegin();
-       it != activity_registry_.cend();) {
-    if (GetAppState(it->first) == AppState::kUninstalled) {
-      it = activity_registry_.erase(it);
-    } else {
-      ++it;
-    }
-  }
-}
-
 }  // namespace app_time
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.h b/chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.h
index 29e05ff..9990d7b 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.h
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_activity_registry.h
@@ -9,6 +9,7 @@
 #include <set>
 
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.h"
 #include "chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.h"
 #include "chrome/browser/chromeos/child_accounts/time_limits/app_types.h"
 
@@ -16,6 +17,10 @@
 class Window;
 }  // namespace aura
 
+namespace enterprise_management {
+class ChildStatusReportRequest;
+}  // namespace enterprise_management
+
 namespace chromeos {
 namespace app_time {
 
@@ -52,6 +57,16 @@
   // reset.
   base::TimeDelta GetActiveTime(const AppId& app_id) const;
 
+  // Populates |report| with collected app activity. Returns whether any data
+  // were reported.
+  AppActivityReportInterface::ReportParams GenerateAppActivityReport(
+      enterprise_management::ChildStatusReportRequest* report) const;
+
+  // Removes data older than |timestamp| from the registry.
+  // Removes entries for uninstalled apps if there is no more relevant activity
+  // data left.
+  void CleanRegistry(base::Time timestamp);
+
  private:
   // Bundles detailed data stored for a specific app.
   struct AppDetails {
@@ -83,10 +98,6 @@
   void SetAppActive(const AppId& app_id, base::Time timestamp);
   void SetAppInactive(const AppId& app_id, base::Time timestamp);
 
-  // Removes uninstalled apps from the registry. Should be called after the
-  // recent data was successfully uploaded to server.
-  void CleanRegistry();
-
   // Owned by AppTimeController.
   AppServiceWrapper* const app_service_wrapper_;
 
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.cc b/chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.cc
new file mode 100644
index 0000000..27e1bce
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.cc
@@ -0,0 +1,30 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.h"
+
+#include "chrome/browser/chromeos/child_accounts/child_user_service.h"
+#include "chrome/browser/chromeos/child_accounts/child_user_service_factory.h"
+#include "chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace chromeos {
+namespace app_time {
+
+// static
+AppActivityReportInterface* AppActivityReportInterface::Get(Profile* profile) {
+  return static_cast<AppActivityReportInterface*>(
+      ChildUserServiceFactory::GetForBrowserContext(profile));
+}
+
+// static
+bool AppActivityReportInterface::ShouldReportAppActivity() {
+  return AppTimeController::ArePerAppTimeLimitsEnabled() &&
+         AppTimeController::IsAppActivityReportingEnabled();
+}
+
+AppActivityReportInterface::~AppActivityReportInterface() = default;
+
+}  // namespace app_time
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.h b/chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.h
new file mode 100644
index 0000000..920aa64
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_activity_report_interface.h
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMITS_APP_ACTIVITY_REPORT_INTERFACE_H_
+#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMITS_APP_ACTIVITY_REPORT_INTERFACE_H_
+
+#include "base/time/time.h"
+
+class Profile;
+
+namespace enterprise_management {
+class ChildStatusReportRequest;
+}  // namespace enterprise_management
+
+namespace chromeos {
+namespace app_time {
+
+// Interface of the object generating app activity for child user.
+class AppActivityReportInterface {
+ public:
+  // Parameters of the generated report.
+  struct ReportParams {
+    // Time the report was generated.
+    base::Time generation_time;
+
+    // Whether any data were added to the report.
+    bool anything_reported = false;
+  };
+
+  // Factory method that returns object generating app activity for child user.
+  // feature. Provided to reduce the dependencies between API consumer and child
+  // user related code. AppActivityReportInterface object has a lifetime of a
+  // KeyedService.
+  static AppActivityReportInterface* Get(Profile* profile);
+
+  static bool ShouldReportAppActivity();
+
+  virtual ~AppActivityReportInterface();
+
+  // Populates child status |report| with collected app activity.
+  // Returns whether any data were populated.
+  virtual ReportParams GenerateAppActivityReport(
+      enterprise_management::ChildStatusReportRequest* report) const = 0;
+
+  // Clears the stored app activity older than |report_generation_timestamp|.
+  // Should be called when child status report was successfully submitted.
+  virtual void AppActivityReportSubmitted(
+      base::Time report_generation_timestamp) = 0;
+};
+
+}  // namespace app_time
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMITS_APP_ACTIVITY_REPORT_INTERFACE_H_
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.cc b/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.cc
index 0ab6313..321226f 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.cc
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.cc
@@ -90,6 +90,10 @@
   return app_name;
 }
 
+std::string AppServiceWrapper::GetAppServiceId(const AppId& app_id) const {
+  return AppServiceIdFromAppId(app_id, profile_);
+}
+
 void AppServiceWrapper::AddObserver(EventListener* listener) {
   DCHECK(listener);
   listeners_.AddObserver(listener);
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.h b/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.h
index a204520..6e42148 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.h
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_service_wrapper.h
@@ -84,6 +84,11 @@
   // Might return empty string.
   std::string GetAppName(const AppId& app_id) const;
 
+  // Returns app service id for the app identified by |app_id|.
+  // App service id will be only different from app_id.app_id() for ARC++ apps.
+  // It does not make sense to call it for other apps.
+  std::string GetAppServiceId(const AppId& app_id) const;
+
   void AddObserver(EventListener* observer);
   void RemoveObserver(EventListener* observer);
 
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.cc b/chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.cc
index 20c98e9..69731b5 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.cc
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.cc
@@ -27,6 +27,10 @@
   return base::FeatureList::IsEnabled(features::kPerAppTimeLimits);
 }
 
+bool AppTimeController::IsAppActivityReportingEnabled() {
+  return base::FeatureList::IsEnabled(features::kAppActivityReporting);
+}
+
 // static
 void AppTimeController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterDictionaryPref(prefs::kPerAppTimeLimitsPolicy);
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.h b/chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.h
index a440c25..2090948 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.h
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_time_controller.h
@@ -24,6 +24,7 @@
 class AppTimeController {
  public:
   static bool ArePerAppTimeLimitsEnabled();
+  static bool IsAppActivityReportingEnabled();
 
   // Registers preferences
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
@@ -41,6 +42,12 @@
 
   WebTimeLimitEnforcer* web_time_enforcer() { return web_time_enforcer_.get(); }
 
+  const AppActivityRegistry* app_registry() const {
+    return app_registry_.get();
+  }
+
+  AppActivityRegistry* app_registry() { return app_registry_.get(); }
+
  private:
   void RegisterProfilePrefObservers(PrefService* pref_service);
   void TimeLimitsPolicyUpdated(const std::string& pref_name);
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_types.cc b/chrome/browser/chromeos/child_accounts/time_limits/app_types.cc
index 743e38a7..0b2fa45 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_types.cc
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_types.cc
@@ -92,7 +92,7 @@
 
 AppActivity::ActiveTime::ActiveTime(base::Time start, base::Time end)
     : active_from_(start), active_to_(end) {
-  DCHECK_GT(end, start);
+  DCHECK_GT(active_to_, active_from_);
 }
 
 AppActivity::ActiveTime::ActiveTime(const AppActivity::ActiveTime& rhs) =
@@ -101,6 +101,36 @@
 AppActivity::ActiveTime& AppActivity::ActiveTime::operator=(
     const AppActivity::ActiveTime& rhs) = default;
 
+bool AppActivity::ActiveTime::operator==(const ActiveTime& rhs) const {
+  return active_from_ == rhs.active_from() && active_to_ == rhs.active_to();
+}
+
+bool AppActivity::ActiveTime::operator!=(const ActiveTime& rhs) const {
+  return !(*this == rhs);
+}
+
+bool AppActivity::ActiveTime::Contains(base::Time timestamp) const {
+  return active_from_ < timestamp && active_to_ > timestamp;
+}
+
+bool AppActivity::ActiveTime::IsEarlierThan(base::Time timestamp) const {
+  return active_to_ <= timestamp;
+}
+
+bool AppActivity::ActiveTime::IsLaterThan(base::Time timestamp) const {
+  return active_from_ >= timestamp;
+}
+
+void AppActivity::ActiveTime::set_active_from(base::Time active_from) {
+  DCHECK_GT(active_to_, active_from);
+  active_from_ = active_from;
+}
+
+void AppActivity::ActiveTime::set_active_to(base::Time active_to) {
+  DCHECK_GT(active_to, active_from_);
+  active_to_ = active_to;
+}
+
 AppActivity::AppActivity(AppState app_state)
     : app_state_(app_state),
       running_active_time_(base::TimeDelta::FromSeconds(0)),
@@ -147,6 +177,23 @@
          (base::TimeTicks::Now() - last_updated_time_ticks_);
 }
 
+void AppActivity::RemoveActiveTimeEarlierThan(base::Time timestamp) {
+  for (auto active_time = active_times_.begin();
+       active_time != active_times_.end();) {
+    if (active_time->IsEarlierThan(timestamp)) {
+      active_time = active_times_.erase(active_time);
+      continue;
+    }
+    if (active_time->IsLaterThan(timestamp)) {
+      ++active_time;
+      continue;
+    }
+    DCHECK(active_time->Contains(timestamp));
+    active_time->set_active_from(timestamp);
+    ++active_time;
+  }
+}
+
 }  // namespace app_time
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_types.h b/chrome/browser/chromeos/child_accounts/time_limits/app_types.h
index 8998859..26e315f 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_types.h
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_types.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMITS_APP_TYPES_H_
 #define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_TIME_LIMITS_APP_TYPES_H_
 
-#include <optional>
+#include <list>
 #include <string>
-#include <vector>
 
+#include "base/optional.h"
 #include "base/time/time.h"
 #include "chrome/services/app_service/public/mojom/types.mojom.h"
 
@@ -110,8 +110,22 @@
     ActiveTime(const ActiveTime& rhs);
     ActiveTime& operator=(const ActiveTime& rhs);
 
+    bool operator==(const ActiveTime&) const;
+    bool operator!=(const ActiveTime&) const;
+
+    // Returns whether |timestamp| is included in this time period.
+    bool Contains(base::Time timestamp) const;
+
+    // Returns whether |timestamp| is earlier than this time period's start.
+    bool IsEarlierThan(base::Time timestamp) const;
+
+    // Returns whether |timestamp| is later than this time period's end.
+    bool IsLaterThan(base::Time timestamp) const;
+
     base::Time active_from() const { return active_from_; }
+    void set_active_from(base::Time active_from);
     base::Time active_to() const { return active_to_; }
+    void set_active_to(base::Time active_to);
 
    private:
     base::Time active_from_;
@@ -136,9 +150,12 @@
 
   base::TimeDelta RunningActiveTime() const;
 
+  // Removes active time data older than given |timestamp|.
+  void RemoveActiveTimeEarlierThan(base::Time timestamp);
+
   bool is_active() const { return is_active_; }
   AppState app_state() const { return app_state_; }
-  const std::vector<ActiveTime>& active_times() const { return active_times_; }
+  const std::list<ActiveTime>& active_times() const { return active_times_; }
 
  private:
   // boolean to specify if the application is active.
@@ -153,7 +170,7 @@
   base::TimeDelta running_active_time_;
 
   // The time app was active.
-  std::vector<ActiveTime> active_times_;
+  std::list<ActiveTime> active_times_;
 
   // Time tick for the last time the activity was updated.
   base::TimeTicks last_updated_time_ticks_;
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_types_unittest.cc b/chrome/browser/chromeos/child_accounts/time_limits/app_types_unittest.cc
new file mode 100644
index 0000000..8a06c9d
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_types_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/child_accounts/time_limits/app_types.h"
+
+#include <string>
+
+#include "base/stl_util.h"
+#include "base/test/gtest_util.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace app_time {
+
+namespace {
+base::Time TimeFromString(const std::string& str) {
+  base::Time timestamp;
+  EXPECT_TRUE(base::Time::FromString(str.c_str(), &timestamp));
+  return timestamp;
+}
+
+}  // namespace
+
+using ActiveTimeTest = testing::Test;
+using AppActivityTest = testing::Test;
+
+TEST_F(ActiveTimeTest, CreateActiveTime) {
+  const base::Time start = TimeFromString("11 Jan 2020 10:00:00 PST");
+  const base::Time end = TimeFromString("11 Jan 2020 10:10:00 PST");
+
+  // Create ActiveTime with the correct timestamps.
+  const AppActivity::ActiveTime active_time(start, end);
+  EXPECT_EQ(start, active_time.active_from());
+  EXPECT_EQ(end, active_time.active_to());
+
+  // Try to create ActiveTime with invalid ranges.
+  EXPECT_DCHECK_DEATH(AppActivity::ActiveTime(start, start));
+  EXPECT_DCHECK_DEATH(AppActivity::ActiveTime(end, start));
+}
+
+TEST_F(ActiveTimeTest, UpdateActiveTime) {
+  AppActivity::ActiveTime active_time(
+      TimeFromString("11 Jan 2020 10:00:00 PST"),
+      TimeFromString("11 Jan 2020 10:10:00 PST"));
+  const base::Time& start_equal_end = active_time.active_to();
+  EXPECT_DCHECK_DEATH(active_time.set_active_from(start_equal_end));
+
+  const base::Time start_after_end =
+      active_time.active_to() + base::TimeDelta::FromSeconds(1);
+  EXPECT_DCHECK_DEATH(active_time.set_active_from(start_after_end));
+
+  const base::Time& end_equal_start = active_time.active_from();
+  EXPECT_DCHECK_DEATH(active_time.set_active_to(end_equal_start));
+
+  const base::Time end_before_start =
+      active_time.active_from() - base::TimeDelta::FromSeconds(1);
+  EXPECT_DCHECK_DEATH(active_time.set_active_to(end_before_start));
+}
+
+TEST_F(ActiveTimeTest, ActiveTimeTimestampComparisions) {
+  const AppActivity::ActiveTime active_time(
+      TimeFromString("11 Jan 2020 10:00:00 PST"),
+      TimeFromString("11 Jan 2020 10:10:00 PST"));
+
+  const base::Time contained = TimeFromString("11 Jan 2020 10:05:00 PST");
+  EXPECT_TRUE(active_time.Contains(contained));
+  EXPECT_FALSE(active_time.IsEarlierThan(contained));
+  EXPECT_FALSE(active_time.IsLaterThan(contained));
+
+  const base::Time before = TimeFromString("11 Jan 2020 09:58:00 PST");
+  EXPECT_FALSE(active_time.Contains(before));
+  EXPECT_FALSE(active_time.IsEarlierThan(before));
+  EXPECT_TRUE(active_time.IsLaterThan(before));
+
+  const base::Time after = TimeFromString("11 Jan 2020 10:11:00 PST");
+  EXPECT_FALSE(active_time.Contains(after));
+  EXPECT_TRUE(active_time.IsEarlierThan(after));
+  EXPECT_FALSE(active_time.IsLaterThan(after));
+
+  const base::Time& equal_start = active_time.active_from();
+  EXPECT_FALSE(active_time.Contains(equal_start));
+  EXPECT_FALSE(active_time.IsEarlierThan(equal_start));
+  EXPECT_TRUE(active_time.IsLaterThan(equal_start));
+
+  const base::Time& equal_end = active_time.active_to();
+  EXPECT_FALSE(active_time.Contains(equal_end));
+  EXPECT_TRUE(active_time.IsEarlierThan(equal_end));
+  EXPECT_FALSE(active_time.IsLaterThan(equal_end));
+}
+
+TEST_F(AppActivityTest, RemoveActiveTimes) {
+  base::test::TaskEnvironment task_environment(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+  AppActivity activity(AppState::kAvailable);
+
+  // Time interval that will be removed.
+  base::Time start = base::Time::Now();
+  activity.SetAppActive(start);
+  task_environment.FastForwardBy(base::TimeDelta::FromMinutes(10));
+  base::Time end = base::Time::Now();
+  activity.SetAppInactive(end);
+  const AppActivity::ActiveTime to_remove(start, end);
+
+  // Time interval that will be trimmed.
+  start = base::Time::Now();
+  activity.SetAppActive(start);
+  task_environment.FastForwardBy(base::TimeDelta::FromMinutes(5));
+  const base::Time report_time = base::Time::Now();
+  task_environment.FastForwardBy(base::TimeDelta::FromMinutes(5));
+  end = base::Time::Now();
+  activity.SetAppInactive(end);
+  const AppActivity::ActiveTime to_trim(start, end);
+
+  // Time interval that will be kept.
+  start = base::Time::Now();
+  activity.SetAppActive(start);
+  task_environment.FastForwardBy(base::TimeDelta::FromMinutes(10));
+  end = base::Time::Now();
+  activity.SetAppInactive(end);
+  const AppActivity::ActiveTime to_keep(start, end);
+
+  EXPECT_EQ(3u, activity.active_times().size());
+  EXPECT_TRUE(base::Contains(activity.active_times(), to_remove));
+  EXPECT_TRUE(base::Contains(activity.active_times(), to_trim));
+  EXPECT_TRUE(base::Contains(activity.active_times(), to_keep));
+
+  activity.RemoveActiveTimeEarlierThan(report_time);
+
+  EXPECT_EQ(2u, activity.active_times().size());
+  EXPECT_FALSE(base::Contains(activity.active_times(), to_remove));
+  EXPECT_TRUE(base::Contains(activity.active_times(), to_keep));
+
+  const AppActivity::ActiveTime trimmed(report_time, to_trim.active_to());
+  EXPECT_TRUE(base::Contains(activity.active_times(), trimmed));
+}
+
+// TODO(agawronska) : Add more tests for app activity.
+
+}  // namespace app_time
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/eula_browsertest.cc b/chrome/browser/chromeos/login/eula_browsertest.cc
index c1027e7..a7c0fc38 100644
--- a/chrome/browser/chromeos/login/eula_browsertest.cc
+++ b/chrome/browser/chromeos/login/eula_browsertest.cc
@@ -272,8 +272,14 @@
                   .find(kOfflineEULAWarning) != std::string::npos);
 }
 
+#if defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER)
+// TODO(http://crbug.com/1041188): flaky on ChromeOS MSAN.
+#define MAYBE_LoadOnline DISABLED_LoadOnline
+#else
+#define MAYBE_LoadOnline LoadOnline
+#endif
 // Tests that online version is shown when it is accessible.
-IN_PROC_BROWSER_TEST_F(EulaTest, LoadOnline) {
+IN_PROC_BROWSER_TEST_F(EulaTest, MAYBE_LoadOnline) {
   ShowEulaScreen();
 
   // Wait until the webview has finished loading.
diff --git a/chrome/browser/component_updater/intervention_policy_database_component_installer.cc b/chrome/browser/component_updater/intervention_policy_database_component_installer.cc
new file mode 100644
index 0000000..1da07b9
--- /dev/null
+++ b/chrome/browser/component_updater/intervention_policy_database_component_installer.cc
@@ -0,0 +1,127 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/component_updater/intervention_policy_database_component_installer.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "chrome/browser/resource_coordinator/intervention_policy_database.h"
+#include "components/component_updater/component_updater_paths.h"
+#include "components/component_updater/component_updater_service.h"
+#include "components/crx_file/id_util.h"
+
+using component_updater::ComponentUpdateService;
+
+namespace {
+
+// The SHA256 of the SubjectPublicKeyInfo used to sign the component.
+// The component id is: copjbmjbojbakpaedmpkhmiplmmehfck
+const uint8_t kInterventionPolicyDatabasePublicKeySHA256[32] = {
+    0x2e, 0xf9, 0x1c, 0x91, 0xe9, 0x10, 0xaf, 0x04, 0x3c, 0xfa, 0x7c,
+    0x8f, 0xbc, 0xc4, 0x75, 0x2a, 0x48, 0x9a, 0x64, 0x74, 0xc6, 0xda,
+    0xb7, 0xb9, 0xdf, 0x5f, 0x51, 0x3e, 0x50, 0x39, 0x04, 0xab};
+
+// The name of the component, used in the chrome://components page.
+const char kInterventionPolicyDatabaseComponentName[] =
+    "Intervention Policy Database";
+
+// The name of the database file inside of an installation of this component.
+const base::FilePath::CharType kInterventionPolicyDatabaseBinaryPbFileName[] =
+    FILE_PATH_LITERAL("intervention_policy_database.pb");
+
+}  // namespace
+
+namespace component_updater {
+
+InterventionPolicyDatabaseComponentInstallerPolicy::
+    InterventionPolicyDatabaseComponentInstallerPolicy(
+        resource_coordinator::InterventionPolicyDatabase* database)
+    : database_(database) {
+  DCHECK(database_);
+}
+
+bool InterventionPolicyDatabaseComponentInstallerPolicy::
+    SupportsGroupPolicyEnabledComponentUpdates() const {
+  return false;
+}
+
+bool InterventionPolicyDatabaseComponentInstallerPolicy::
+    RequiresNetworkEncryption() const {
+  // Public data is delivered via this component, no need for encryption.
+  return false;
+}
+
+update_client::CrxInstaller::Result
+InterventionPolicyDatabaseComponentInstallerPolicy::OnCustomInstall(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) {
+  return update_client::CrxInstaller::Result(0);
+}
+
+void InterventionPolicyDatabaseComponentInstallerPolicy::OnCustomUninstall() {}
+
+// Called during startup and installation before ComponentReady().
+bool InterventionPolicyDatabaseComponentInstallerPolicy::VerifyInstallation(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) const {
+  return base::PathExists(
+      install_dir.Append(kInterventionPolicyDatabaseBinaryPbFileName));
+}
+
+// NOTE: This is always called on the main UI thread. It is called once every
+// startup to notify of an already installed component, and may be called
+// repeatedly after that every time a new component is ready.
+void InterventionPolicyDatabaseComponentInstallerPolicy::ComponentReady(
+    const base::Version& version,
+    const base::FilePath& install_dir,
+    std::unique_ptr<base::DictionaryValue> manifest) {
+  DCHECK(database_);
+  database_->InitializeDatabaseWithProtoFile(
+      install_dir.Append(kInterventionPolicyDatabaseBinaryPbFileName), version,
+      std::move(manifest));
+}
+
+base::FilePath
+InterventionPolicyDatabaseComponentInstallerPolicy::GetRelativeInstallDir()
+    const {
+  return base::FilePath(FILE_PATH_LITERAL("InterventionPolicyDatabase"));
+}
+
+void InterventionPolicyDatabaseComponentInstallerPolicy::GetHash(
+    std::vector<uint8_t>* hash) const {
+  hash->assign(kInterventionPolicyDatabasePublicKeySHA256,
+               kInterventionPolicyDatabasePublicKeySHA256 +
+                   base::size(kInterventionPolicyDatabasePublicKeySHA256));
+}
+
+std::string InterventionPolicyDatabaseComponentInstallerPolicy::GetName()
+    const {
+  return kInterventionPolicyDatabaseComponentName;
+}
+
+update_client::InstallerAttributes
+InterventionPolicyDatabaseComponentInstallerPolicy::GetInstallerAttributes()
+    const {
+  return update_client::InstallerAttributes();
+}
+
+std::vector<std::string>
+InterventionPolicyDatabaseComponentInstallerPolicy::GetMimeTypes() const {
+  return std::vector<std::string>();
+}
+
+void RegisterInterventionPolicyDatabaseComponent(
+    ComponentUpdateService* cus,
+    resource_coordinator::InterventionPolicyDatabase* database) {
+  std::unique_ptr<ComponentInstallerPolicy> policy(
+      new InterventionPolicyDatabaseComponentInstallerPolicy(database));
+  auto installer = base::MakeRefCounted<ComponentInstaller>(std::move(policy));
+  installer->Register(cus, base::OnceClosure());
+}
+
+}  // namespace component_updater
diff --git a/chrome/browser/component_updater/intervention_policy_database_component_installer.h b/chrome/browser/component_updater/intervention_policy_database_component_installer.h
new file mode 100644
index 0000000..1abe36d
--- /dev/null
+++ b/chrome/browser/component_updater/intervention_policy_database_component_installer.h
@@ -0,0 +1,60 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_COMPONENT_UPDATER_INTERVENTION_POLICY_DATABASE_COMPONENT_INSTALLER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_INTERVENTION_POLICY_DATABASE_COMPONENT_INSTALLER_H_
+
+#include "components/component_updater/component_installer.h"
+
+namespace resource_coordinator {
+class InterventionPolicyDatabase;
+}
+
+namespace component_updater {
+
+class ComponentUpdateService;
+
+// Component for receiving the intervention policy database. The database
+// consists in a proto, defined in
+// chrome/browser/resource_coordinator/intervention_policy_database.proto.
+class InterventionPolicyDatabaseComponentInstallerPolicy
+    : public ComponentInstallerPolicy {
+ public:
+  InterventionPolicyDatabaseComponentInstallerPolicy(
+      resource_coordinator::InterventionPolicyDatabase* database);
+  ~InterventionPolicyDatabaseComponentInstallerPolicy() override = default;
+
+ private:
+  // ComponentInstallerPolicy:
+  bool SupportsGroupPolicyEnabledComponentUpdates() const override;
+  bool RequiresNetworkEncryption() const override;
+  update_client::CrxInstaller::Result OnCustomInstall(
+      const base::DictionaryValue& manifest,
+      const base::FilePath& install_dir) override;
+  void OnCustomUninstall() override;
+  bool VerifyInstallation(const base::DictionaryValue& manifest,
+                          const base::FilePath& install_dir) const override;
+  void ComponentReady(const base::Version& version,
+                      const base::FilePath& install_dir,
+                      std::unique_ptr<base::DictionaryValue> manifest) override;
+  base::FilePath GetRelativeInstallDir() const override;
+  void GetHash(std::vector<uint8_t>* hash) const override;
+  std::string GetName() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
+  std::vector<std::string> GetMimeTypes() const override;
+
+  resource_coordinator::InterventionPolicyDatabase* database_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterventionPolicyDatabaseComponentInstallerPolicy);
+};
+
+// Call once to make the component update service aware of the Intervention
+// Policy Database component.
+void RegisterInterventionPolicyDatabaseComponent(
+    ComponentUpdateService* cus,
+    resource_coordinator::InterventionPolicyDatabase* database);
+
+}  // namespace component_updater
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_INTERVENTION_POLICY_DATABASE_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/enterprise_reporting/notification/extension_request_notification.cc b/chrome/browser/enterprise_reporting/notification/extension_request_notification.cc
new file mode 100644
index 0000000..659efac
--- /dev/null
+++ b/chrome/browser/enterprise_reporting/notification/extension_request_notification.cc
@@ -0,0 +1,109 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/enterprise_reporting/notification/extension_request_notification.h"
+
+#include <memory>
+
+#include "chrome/browser/notifications/notification_display_service.h"
+#include "chrome/browser/notifications/notification_display_service_factory.h"
+#include "chrome/browser/notifications/notification_handler.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/message_center/public/cpp/message_center_constants.h"
+#include "ui/message_center/public/cpp/notification.h"
+#include "ui/message_center/public/cpp/notification_delegate.h"
+#include "ui/native_theme/native_theme.h"
+
+namespace enterprise_reporting {
+namespace {
+
+constexpr char kApprovedNotificationId[] = "extension_approved_notificaiton";
+constexpr char kRejectedNotificationId[] = "extension_rejected_notificaiton";
+constexpr char kInstalledNotificationId[] = "extension_installed_notificaiton";
+constexpr char kExtensionRequestNotifierId[] =
+    "chrome_browser_cloud_management_extension_request";
+constexpr char kChromeWebstoreUrl[] =
+    "https://chrome.google.com/webstore/detail/";
+
+// The elements order of array below must match the order in enum
+// ExtensionRequestNotification::NotifyType.
+const char* const kNotificationIds[] = {
+    kApprovedNotificationId, kRejectedNotificationId, kInstalledNotificationId};
+constexpr int kNotificationTitles[] = {
+    IDS_ENTERPRISE_EXTENSION_REQUEST_APPROVED_TITLE,
+    IDS_ENTERPRISE_EXTENSION_REQUEST_REJECTED_TITLE,
+    IDS_ENTERPRISE_EXTENSION_REQUEST_FORCE_INSTALLED_TITLE};
+constexpr int kNotificationBodies[] = {
+    IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_INSTALL,
+    IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_VIEW,
+    IDS_ENTERPRISE_EXTENSION_REQUEST_CLICK_TO_VIEW};
+
+}  // namespace
+
+ExtensionRequestNotification::ExtensionRequestNotification() = default;
+
+ExtensionRequestNotification::ExtensionRequestNotification(
+    Profile* profile,
+    const NotifyType notify_type,
+    const ExtensionIds& extension_ids)
+    : profile_(profile),
+      notify_type_(notify_type),
+      extension_ids_(extension_ids) {}
+
+ExtensionRequestNotification::~ExtensionRequestNotification() = default;
+
+void ExtensionRequestNotification::Show() {
+  if (extension_ids_.empty()) {
+    NOTREACHED();
+    return;
+  }
+
+  const base::string16 title = l10n_util::GetPluralStringFUTF16(
+      kNotificationTitles[notify_type_], extension_ids_.size());
+  const base::string16 body = l10n_util::GetPluralStringFUTF16(
+      kNotificationBodies[notify_type_], extension_ids_.size());
+  GURL original_url("https://chrome.google.com/webstore");
+  gfx::Image icon(gfx::CreateVectorIcon(
+      vector_icons::kBusinessIcon, message_center::kSmallImageSize,
+      ui::NativeTheme::GetInstanceForWeb()->GetSystemColor(
+          ui::NativeTheme::kColorId_DefaultIconColor)));
+
+  notification_ = std::make_unique<message_center::Notification>(
+      message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationIds[notify_type_],
+      title, body, icon, /*source=*/base::string16(), original_url,
+      message_center::NotifierId(message_center::NotifierType::APPLICATION,
+                                 kExtensionRequestNotifierId),
+      message_center::RichNotificationData(),
+      new message_center::HandleNotificationClickDelegate(base::BindRepeating(
+          &ExtensionRequestNotification::OnClick, weak_factory_.GetWeakPtr())));
+  notification_->set_never_timeout(true);
+
+  NotificationDisplayService::GetForProfile(profile_)->Display(
+      NotificationHandler::Type::TRANSIENT, *notification_, nullptr);
+}
+
+void ExtensionRequestNotification::Close() {
+  NotificationDisplayService::GetForProfile(profile_)->Close(
+      NotificationHandler::Type::TRANSIENT, kNotificationIds[notify_type_]);
+  notification_.reset();
+}
+
+void ExtensionRequestNotification::OnClick(
+    const base::Optional<int> button_index) {
+  for (const std::string& extension_id : extension_ids_) {
+    NavigateParams params(profile_, GURL(kChromeWebstoreUrl + extension_id),
+                          ui::PAGE_TRANSITION_LINK);
+    params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+    params.window_action = NavigateParams::SHOW_WINDOW;
+    Navigate(&params);
+  }
+  Close();
+}
+
+}  // namespace enterprise_reporting
diff --git a/chrome/browser/enterprise_reporting/notification/extension_request_notification.h b/chrome/browser/enterprise_reporting/notification/extension_request_notification.h
new file mode 100644
index 0000000..70fab98
--- /dev/null
+++ b/chrome/browser/enterprise_reporting/notification/extension_request_notification.h
@@ -0,0 +1,49 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ENTERPRISE_REPORTING_NOTIFICATION_EXTENSION_REQUEST_NOTIFICATION_H_
+#define CHROME_BROWSER_ENTERPRISE_REPORTING_NOTIFICATION_EXTENSION_REQUEST_NOTIFICATION_H_
+
+#include "ui/message_center/public/cpp/notification_delegate.h"
+
+namespace message_center {
+class Notification;
+}
+
+class Profile;
+
+namespace enterprise_reporting {
+
+class ExtensionRequestNotification {
+ public:
+  using ExtensionIds = std::vector<std::string>;
+  enum NotifyType { kApproved = 0, kRejected = 1, kForceInstalled = 2 };
+
+  ExtensionRequestNotification();
+  ExtensionRequestNotification(Profile* profile,
+                               const NotifyType notify_type,
+                               const ExtensionIds& extension_ids);
+  ExtensionRequestNotification(const ExtensionRequestNotification&) = delete;
+  ExtensionRequestNotification& operator=(const ExtensionRequestNotification&) =
+      delete;
+  virtual ~ExtensionRequestNotification();
+
+  void Show();
+  void Close();
+
+ private:
+  void OnClick(const base::Optional<int> button_index);
+
+  std::unique_ptr<message_center::Notification> notification_;
+
+  Profile* profile_;
+  const NotifyType notify_type_ = kApproved;
+  const ExtensionIds extension_ids_;
+
+  base::WeakPtrFactory<ExtensionRequestNotification> weak_factory_{this};
+};
+
+}  // namespace enterprise_reporting
+
+#endif  // CHROME_BROWSER_ENTERPRISE_REPORTING_NOTIFICATION_EXTENSION_REQUEST_NOTIFICATION_H_
diff --git a/chrome/browser/enterprise_reporting/notification/extension_request_notification_unittest.cc b/chrome/browser/enterprise_reporting/notification/extension_request_notification_unittest.cc
new file mode 100644
index 0000000..f6ecddc
--- /dev/null
+++ b/chrome/browser/enterprise_reporting/notification/extension_request_notification_unittest.cc
@@ -0,0 +1,115 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/enterprise_reporting/notification/extension_request_notification.h"
+
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/notifications/notification_display_service_tester.h"
+#include "chrome/browser/notifications/notification_handler.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::HasSubstr;
+
+namespace enterprise_reporting {
+
+constexpr char kChromeWebstoreUrl[] =
+    "https://chrome.google.com/webstore/detail/";
+constexpr char kFakeExtensionId[] = "fake-extension-id";
+
+// The elements order of array below must match the order in enum
+// ExtensionRequestNotification::NotifyType.
+const char* const kNotificationIds[] = {"extension_approved_notificaiton",
+                                        "extension_rejected_notificaiton",
+                                        "extension_installed_notificaiton"};
+const char* const kNotificationTitleKeywords[] = {"approved", "rejected",
+                                                  "installed"};
+const char* const kNotificationBodyKeywords[] = {"to install", "to view",
+                                                 "to view"};
+
+class ExtensionRequestNotificationTest
+    : public BrowserWithTestWindowTest,
+      public testing::WithParamInterface<
+          ExtensionRequestNotification::NotifyType> {
+ public:
+  ExtensionRequestNotificationTest() = default;
+  ~ExtensionRequestNotificationTest() override = default;
+
+  void SetUp() override {
+    BrowserWithTestWindowTest::SetUp();
+    display_service_tester_ =
+        std::make_unique<NotificationDisplayServiceTester>(profile());
+  }
+
+  ExtensionRequestNotification::NotifyType GetNotifyType() {
+    return GetParam();
+  }
+
+  base::Optional<message_center::Notification> GetNotification() {
+    return display_service_tester_->GetNotification(
+        kNotificationIds[GetNotifyType()]);
+  }
+
+  std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    ExtensionRequestNotificationTest,
+    ExtensionRequestNotificationTest,
+    ::testing::Values(ExtensionRequestNotification::kApproved,
+                      ExtensionRequestNotification::kRejected,
+                      ExtensionRequestNotification::kForceInstalled));
+
+TEST_P(ExtensionRequestNotificationTest, NoExtension) {
+  ExtensionRequestNotification request_notification(
+      profile(), GetNotifyType(), ExtensionRequestNotification::ExtensionIds());
+#if DCHECK_IS_ON()
+  EXPECT_DEATH_IF_SUPPORTED(request_notification.Show(), "");
+#else
+  request_notification.Show();
+#endif
+  task_environment()->RunUntilIdle();
+  EXPECT_FALSE(GetNotification().has_value());
+}
+
+TEST_P(ExtensionRequestNotificationTest, HasExtension) {
+  ExtensionRequestNotification request_notification(
+      profile(), GetNotifyType(),
+      ExtensionRequestNotification::ExtensionIds({kFakeExtensionId}));
+  base::RunLoop show_run_loop;
+  display_service_tester_->SetNotificationAddedClosure(
+      show_run_loop.QuitClosure());
+  request_notification.Show();
+  show_run_loop.Run();
+
+  base::Optional<message_center::Notification> notification = GetNotification();
+  ASSERT_TRUE(notification.has_value());
+
+  EXPECT_THAT(base::UTF16ToUTF8(notification->title()),
+              HasSubstr(kNotificationTitleKeywords[GetNotifyType()]));
+  EXPECT_THAT(base::UTF16ToUTF8(notification->message()),
+              HasSubstr(kNotificationBodyKeywords[GetNotifyType()]));
+
+  base::RunLoop close_run_loop;
+  display_service_tester_->SetNotificationClosedClosure(
+      close_run_loop.QuitClosure());
+  display_service_tester_->SimulateClick(
+      NotificationHandler::Type::TRANSIENT, kNotificationIds[GetNotifyType()],
+      base::Optional<int>(), base::Optional<base::string16>());
+  close_run_loop.Run();
+
+  EXPECT_FALSE(GetNotification().has_value());
+  std::string expected_url =
+      std::string(kChromeWebstoreUrl) + std::string(kFakeExtensionId);
+  EXPECT_EQ(GURL(expected_url),
+            browser()->tab_strip_model()->GetWebContentsAt(0)->GetURL());
+}
+
+}  // namespace enterprise_reporting
diff --git a/chrome/browser/enterprise_reporting/report_scheduler.h b/chrome/browser/enterprise_reporting/report_scheduler.h
index d169e7b..dc07250 100644
--- a/chrome/browser/enterprise_reporting/report_scheduler.h
+++ b/chrome/browser/enterprise_reporting/report_scheduler.h
@@ -12,6 +12,7 @@
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "chrome/browser/enterprise_reporting/notification/extension_request_notification.h"
 #include "chrome/browser/enterprise_reporting/report_generator.h"
 #include "chrome/browser/enterprise_reporting/report_uploader.h"
 #include "chrome/browser/profiles/profile_manager_observer.h"
@@ -88,6 +89,11 @@
 
   std::unique_ptr<base::flat_set<base::FilePath>> stale_profiles_;
 
+  // Create an un-used notification instance so that the resources won't be
+  // filtered out in the unit test. This will be removed once the whole
+  // implementation is finished.
+  ExtensionRequestNotification notification_;
+
   DISALLOW_COPY_AND_ASSIGN(ReportScheduler);
 };
 
diff --git a/chrome/browser/extensions/OWNERS b/chrome/browser/extensions/OWNERS
index e0f532e..77d2753 100644
--- a/chrome/browser/extensions/OWNERS
+++ b/chrome/browser/extensions/OWNERS
@@ -6,8 +6,8 @@
 per-file extension_gcm_app_handler*=file://chrome/browser/extensions/api/gcm/OWNERS
 
 # For security review.
-per-file chrome_extensions_browser_interface_binders.cc=set noparent
-per-file chrome_extensions_browser_interface_binders.cc=file://ipc/SECURITY_OWNERS
+per-file chrome_extensions_browser_interface_binders.*=set noparent
+per-file chrome_extensions_browser_interface_binders.*=file://ipc/SECURITY_OWNERS
 
 # For adding/renaming files for Chrome OS apps APIs.
 per-file BUILD.gn=stevenjb@chromium.org
diff --git a/chrome/browser/image_fetcher/BUILD.gn b/chrome/browser/image_fetcher/BUILD.gn
index 77877e0..25b0a79 100644
--- a/chrome/browser/image_fetcher/BUILD.gn
+++ b/chrome/browser/image_fetcher/BUILD.gn
@@ -27,7 +27,5 @@
 }
 
 generate_jni("jni_headers") {
-  sources = [
-    "android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherBridge.java",
-  ]
+  sources = [ "android/java/src/org/chromium/chrome/browser/image_fetcher/ImageFetcherBridge.java" ]
 }
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn
index f3c7ced..c7e94a2 100644
--- a/chrome/browser/media/router/BUILD.gn
+++ b/chrome/browser/media/router/BUILD.gn
@@ -212,9 +212,7 @@
     "//chrome/test:test_support",
     "//testing/gmock",
   ]
-  public_deps = [
-    ":router",
-  ]
+  public_deps = [ ":router" ]
   sources = [
     "test/mock_media_router.cc",
     "test/mock_media_router.h",
@@ -350,9 +348,7 @@
 }
 
 fuzzer_test("dial_internal_message_fuzzer") {
-  sources = [
-    "providers/dial/dial_internal_message_fuzzer.cc",
-  ]
+  sources = [ "providers/dial/dial_internal_message_fuzzer.cc" ]
   deps = [
     ":router",
     "//base",
diff --git a/chrome/browser/media/router/discovery/BUILD.gn b/chrome/browser/media/router/discovery/BUILD.gn
index c5e3bf5..902ab86 100644
--- a/chrome/browser/media/router/discovery/BUILD.gn
+++ b/chrome/browser/media/router/discovery/BUILD.gn
@@ -5,9 +5,7 @@
 assert(!is_android)
 
 static_library("discovery") {
-  inputs = [
-    "$root_gen_dir/chrome/grit/generated_resources.h",
-  ]
+  inputs = [ "$root_gen_dir/chrome/grit/generated_resources.h" ]
   deps = [
     "//base",
     "//base:i18n",
diff --git a/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc b/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc
index f3ff52e..7073d93 100644
--- a/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc
+++ b/chrome/browser/optimization_guide/prediction/prediction_manager_unittest.cc
@@ -575,8 +575,8 @@
       0);
 }
 
-// TODO(https://crbug.com/1034433) Flaky on Mac10.12
-#if defined(OS_MACOSX)
+// TODO(https://crbug.com/1034433) Flaky on Mac10.12 and Windows.
+#if defined(OS_MACOSX) || defined(OS_WIN)
 #define MAYBE_NoPredictionModelForRegisteredOptimizationTarget \
   DISABLED_NoPredictionModelForRegisteredOptimizationTarget
 #else
@@ -1038,8 +1038,8 @@
       PredictionManagerModelStatus::kStoreAvailableModelNotLoaded, 1);
 }
 
-// TODO(https://crbug.com/1034433) Flaky on Mac10.12
-#if defined(OS_MACOSX)
+// TODO(https://crbug.com/1034433) Flaky on Mac10.12 and Windows.
+#if defined(OS_MACOSX) || defined(OS_WIN)
 #define MAYBE_ShouldTargetNavigationStoreUnavailableModelUnknown \
   DISABLED_ShouldTargetNavigationStoreUnavailableModelUnknown
 #else
@@ -1107,8 +1107,8 @@
       "OptimizationGuide.PredictionManager.HostModelFeaturesStored", 0);
 }
 
-// TODO(https://crbug.com/1034433) Flaky on Mac10.12
-#if defined(OS_MACOSX)
+// TODO(https://crbug.com/1034433) Flaky on Mac10.12 and Windows.
+#if defined(OS_MACOSX) || defined(OS_WIN)
 #define MAYBE_UpdateModelWithUnsupportedOptimizationTarget \
   DISABLED_UpdateModelWithUnsupportedOptimizationTarget
 #else
diff --git a/chrome/browser/performance_manager/BUILD.gn b/chrome/browser/performance_manager/BUILD.gn
index ab1114ae..a0a3843 100644
--- a/chrome/browser/performance_manager/BUILD.gn
+++ b/chrome/browser/performance_manager/BUILD.gn
@@ -6,7 +6,5 @@
 import("//third_party/protobuf/proto_library.gni")
 
 proto_library("site_data_proto") {
-  sources = [
-    "persistence/site_data/site_data.proto",
-  ]
+  sources = [ "persistence/site_data/site_data.proto" ]
 }
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index 21b3a49..ec99041 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -508,14 +508,8 @@
 
 // Tests that when closing a Picture-in-Picture window, the video element is
 // reflected as no longer in Picture-in-Picture.
-// TODO(crbug.com/1001421): Flaky on ASan.
-#if defined(ADDRESS_SANITIZER)
-#define MAYBE_CloseWindowWhilePlaying DISABLED_CloseWindowWhilePlaying
-#else
-#define MAYBE_CloseWindowWhilePlaying CloseWindowWhilePlaying
-#endif
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
-                       MAYBE_CloseWindowWhilePlaying) {
+                       CloseWindowWhilePlaying) {
   GURL test_page_url = ui_test_utils::GetTestUrl(
       base::FilePath(base::FilePath::kCurrentDirectory),
       base::FilePath(kPictureInPictureWindowSizePage));
@@ -665,16 +659,8 @@
 
 // Tests that when starting a new Picture-in-Picture session from the same
 // video, the video stays in Picture-in-Picture mode.
-// TODO(crbug.com/1001446): Flaky on ASan.
-#if defined(ADDRESS_SANITIZER)
-#define MAYBE_RequestPictureInPictureTwiceFromSameVideo \
-  DISABLED_RequestPictureInPictureTwiceFromSameVideo
-#else
-#define MAYBE_RequestPictureInPictureTwiceFromSameVideo \
-  RequestPictureInPictureTwiceFromSameVideo
-#endif
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
-                       MAYBE_RequestPictureInPictureTwiceFromSameVideo) {
+                       RequestPictureInPictureTwiceFromSameVideo) {
   GURL test_page_url = ui_test_utils::GetTestUrl(
       base::FilePath(base::FilePath::kCurrentDirectory),
       base::FilePath(kPictureInPictureWindowSizePage));
@@ -730,16 +716,8 @@
 
 // Tests that when starting a new Picture-in-Picture session from the same tab,
 // the previous video is no longer in Picture-in-Picture mode.
-// TODO(crbug.com/1001421): Flaky on ASan.
-#if defined(ADDRESS_SANITIZER)
-#define MAYBE_OpenSecondPictureInPictureStopsFirst \
-  DISABLED_OpenSecondPictureInPictureStopsFirst
-#else
-#define MAYBE_OpenSecondPictureInPictureStopsFirst \
-  OpenSecondPictureInPictureStopsFirst
-#endif
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
-                       MAYBE_OpenSecondPictureInPictureStopsFirst) {
+                       OpenSecondPictureInPictureStopsFirst) {
   GURL test_page_url = ui_test_utils::GetTestUrl(
       base::FilePath(base::FilePath::kCurrentDirectory),
       base::FilePath(kPictureInPictureWindowSizePage));
@@ -1436,14 +1414,8 @@
 
 // Tests that the play/pause icon state is properly updated when a
 // Picture-in-Picture is created after a reload.
-// TODO(crbug.com/1001421): Flaky on ASan.
-#if defined(ADDRESS_SANITIZER)
-#define MAYBE_PlayPauseStateAtCreation DISABLED_PlayPauseStateAtCreation
-#else
-#define MAYBE_PlayPauseStateAtCreation PlayPauseStateAtCreation
-#endif
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
-                       MAYBE_PlayPauseStateAtCreation) {
+                       PlayPauseStateAtCreation) {
   LoadTabAndEnterPictureInPicture(
       browser(), base::FilePath(kPictureInPictureWindowSizePage));
 
@@ -1555,14 +1527,8 @@
 // changing source willproperly update the associated media player id. This is
 // checked by closing the window because the test it at a too high level to be
 // able to check the actual media player id being used.
-// TODO(crbug.com/1001421): Flaky on ASan.
-#if defined(ADDRESS_SANITIZER)
-#define MAYBE_PreloadNoneSrcChangeThenLoad DISABLED_PreloadNoneSrcChangeThenLoad
-#else
-#define MAYBE_PreloadNoneSrcChangeThenLoad PreloadNoneSrcChangeThenLoad
-#endif
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
-                       MAYBE_PreloadNoneSrcChangeThenLoad) {
+                       PreloadNoneSrcChangeThenLoad) {
   GURL test_page_url = ui_test_utils::GetTestUrl(
       base::FilePath(base::FilePath::kCurrentDirectory),
       base::FilePath(FILE_PATH_LITERAL(
@@ -2997,14 +2963,8 @@
   ExpectLeavePictureInPicture(active_web_contents);
 }
 
-// TODO(crbug.com/1002489): Test is flaky on Linux.
-#if defined(OS_LINUX)
-#define MAYBE_UpdateMaxSize DISABLED_UpdateMaxSize
-#else
-#define MAYBE_UpdateMaxSize UpdateMaxSize
-#endif
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
-                       MAYBE_UpdateMaxSize) {
+                       UpdateMaxSize) {
   LoadTabAndEnterPictureInPicture(
       browser(), base::FilePath(kPictureInPictureWindowSizePage));
 
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index e20d7f8..c167871 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -665,6 +665,9 @@
   { key::kHighContrastEnabled,
     ash::prefs::kAccessibilityHighContrastEnabled,
     base::Value::Type::BOOLEAN },
+  { key::kAccessibilityShortcutsEnabled,
+    ash::prefs::kAccessibilityShortcutsEnabled,
+    base::Value::Type::BOOLEAN },
   { key::kVirtualKeyboardEnabled,
     ash::prefs::kAccessibilityVirtualKeyboardEnabled,
     base::Value::Type::BOOLEAN },
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index ba8df24..102bedc 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -429,6 +429,11 @@
     public static final String PRIVACY_ALLOW_PRERENDER_OLD = "allow_prefetch";
 
     /**
+     * Key to cache the enabled bottom toolbar parameter.
+     */
+    public static final String VARIATION_CACHED_BOTTOM_TOOLBAR = "bottom_toolbar_variation";
+
+    /**
      * Whether the promotion for data reduction has been skipped on first invocation.
      * Default value is false.
      */
@@ -442,6 +447,16 @@
 
     public static final String RLZ_NOTIFIED = "rlz_first_search_notified";
 
+    /** Key used to store the default Search Engine Type before choice is presented. */
+    public static final String SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE =
+            "search_engine_choice_default_type_before";
+    /** Key used to store the version of Chrome in which the choice was presented. */
+    public static final String SEARCH_ENGINE_CHOICE_PRESENTED_VERSION =
+            "search_engine_choice_presented_version";
+    /** Key used to store the date of when search engine choice was requested. */
+    public static final String SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP =
+            "search_engine_choice_requested_timestamp";
+
     /**
      * Generic signin and sync promo preferences.
      */
@@ -710,6 +725,9 @@
                 PROMOS_SKIPPED_ON_FIRST_START,
                 REACHED_CODE_PROFILER_GROUP,
                 RLZ_NOTIFIED,
+                SEARCH_ENGINE_CHOICE_DEFAULT_TYPE_BEFORE,
+                SEARCH_ENGINE_CHOICE_PRESENTED_VERSION,
+                SEARCH_ENGINE_CHOICE_REQUESTED_TIMESTAMP,
                 SIGNIN_AND_SYNC_PROMO_SHOW_COUNT,
                 SIGNIN_PROMO_IMPRESSIONS_COUNT_BOOKMARKS,
                 SIGNIN_PROMO_IMPRESSIONS_COUNT_SETTINGS,
@@ -729,6 +747,7 @@
                 TWA_DISCLOSURE_ACCEPTED_PACKAGES,
                 UI_THEME_DARKEN_WEBSITES_ENABLED,
                 UI_THEME_SETTING,
+                VARIATION_CACHED_BOTTOM_TOOLBAR,
                 VERIFIED_DIGITAL_ASSET_LINKS,
                 VR_SHOULD_REGISTER_ASSETS_COMPONENT_ON_STARTUP,
                 WEBAPK_UNINSTALLED_PACKAGES
diff --git a/chrome/browser/profiles/gaia_info_update_service.cc b/chrome/browser/profiles/gaia_info_update_service.cc
index 894f474..893d014 100644
--- a/chrome/browser/profiles/gaia_info_update_service.cc
+++ b/chrome/browser/profiles/gaia_info_update_service.cc
@@ -176,6 +176,5 @@
 
 bool GAIAInfoUpdateService::ShouldUpdate() {
   return identity_manager_->HasPrimaryAccount() ||
-         (identity_manager_->HasUnconsentedPrimaryAccount() &&
-          base::FeatureList::IsEnabled(kPersistUPAInProfileInfoCache));
+         identity_manager_->HasUnconsentedPrimaryAccount();
 }
diff --git a/chrome/browser/profiles/profile_attributes_entry.cc b/chrome/browser/profiles/profile_attributes_entry.cc
index 62035f2..b660629 100644
--- a/chrome/browser/profiles/profile_attributes_entry.cc
+++ b/chrome/browser/profiles/profile_attributes_entry.cc
@@ -51,9 +51,6 @@
 
 }  // namespace
 
-const base::Feature kPersistUPAInProfileInfoCache{
-    "PersistUPAInProfileInfoCache", base::FEATURE_ENABLED_BY_DEFAULT};
-
 const char ProfileAttributesEntry::kSupervisedUserId[] = "managed_user_id";
 const char ProfileAttributesEntry::kIsOmittedFromProfileListKey[] =
     "is_omitted_from_profile_list";
diff --git a/chrome/browser/profiles/profile_attributes_entry.h b/chrome/browser/profiles/profile_attributes_entry.h
index a843931..1502b67 100644
--- a/chrome/browser/profiles/profile_attributes_entry.h
+++ b/chrome/browser/profiles/profile_attributes_entry.h
@@ -32,8 +32,6 @@
   kSignedInWithConsentedPrimaryAccount,
 };
 
-extern const base::Feature kPersistUPAInProfileInfoCache;
-
 class ProfileAttributesEntry {
  public:
   static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
diff --git a/chrome/browser/resource_coordinator/BUILD.gn b/chrome/browser/resource_coordinator/BUILD.gn
index c5e180f..48db683 100644
--- a/chrome/browser/resource_coordinator/BUILD.gn
+++ b/chrome/browser/resource_coordinator/BUILD.gn
@@ -14,6 +14,12 @@
   sources = [ "lifecycle_unit_state.mojom" ]
 }
 
+proto_library("intervention_policy_database_proto") {
+  sources = [
+    "intervention_policy_database.proto",
+  ]
+}
+
 source_set("tab_manager_features") {
   public = [ "tab_manager_features.h" ]
 
diff --git a/chrome/browser/resource_coordinator/intervention_policy_database.cc b/chrome/browser/resource_coordinator/intervention_policy_database.cc
new file mode 100644
index 0000000..e15b9dacb
--- /dev/null
+++ b/chrome/browser/resource_coordinator/intervention_policy_database.cc
@@ -0,0 +1,102 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/intervention_policy_database.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/task/post_task.h"
+#include "base/task_runner_util.h"
+#include "base/values.h"
+#include "chrome/browser/resource_coordinator/utils.h"
+
+namespace resource_coordinator {
+
+InterventionPolicyDatabase::OriginInterventionPolicies::
+    OriginInterventionPolicies(InterventionPolicy discarding_policy,
+                               InterventionPolicy freezing_policy)
+    : discarding_policy(discarding_policy), freezing_policy(freezing_policy) {}
+
+InterventionPolicyDatabase::InterventionPolicyDatabase() {}
+InterventionPolicyDatabase::~InterventionPolicyDatabase() = default;
+
+InterventionPolicyDatabase::InterventionPolicy
+InterventionPolicyDatabase::GetDiscardingPolicy(
+    const url::Origin& origin) const {
+  const auto iter = database_.find(SerializeOriginIntoDatabaseKey(origin));
+  if (iter == database_.end())
+    return OriginInterventions::DEFAULT;
+  return iter->second.discarding_policy;
+}
+
+InterventionPolicyDatabase::InterventionPolicy
+InterventionPolicyDatabase::GetFreezingPolicy(const url::Origin& origin) const {
+  const auto iter = database_.find(SerializeOriginIntoDatabaseKey(origin));
+  if (iter == database_.end())
+    return OriginInterventions::DEFAULT;
+  return iter->second.freezing_policy;
+}
+
+void InterventionPolicyDatabase::InitializeDatabaseWithProtoFile(
+    const base::FilePath& proto_location,
+    const base::Version& version,
+    std::unique_ptr<base::DictionaryValue> manifest) {
+  // TODO(sebmarchand): Validate the version and the manifest?
+  base::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      {base::ThreadPool(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()},
+      base::BindOnce(
+          &InterventionPolicyDatabase::ReadDatabaseFromProtoFileOnSequence,
+          proto_location),
+      base::BindOnce(&InterventionPolicyDatabase::OnReadDatabaseProtoFromFile,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void InterventionPolicyDatabase::AddOriginPoliciesForTesting(
+    const url::Origin& origin,
+    OriginInterventionPolicies policies) {
+  database_.emplace(SerializeOriginIntoDatabaseKey(origin),
+                    std::move(policies));
+}
+
+// static
+InterventionPolicyDatabase::InterventionsMap
+InterventionPolicyDatabase::ReadDatabaseFromProtoFileOnSequence(
+    const base::FilePath& proto_location) {
+  DCHECK(base::PathExists(proto_location));
+
+  InterventionsMap database;
+
+  std::string proto_str;
+  if (!base::ReadFileToString(proto_location, &proto_str)) {
+    DLOG(ERROR) << "Failed to read the interventon policy database.";
+    return database;
+  }
+
+  OriginInterventionsDatabase proto;
+  if (!proto.ParseFromString(proto_str)) {
+    DLOG(ERROR) << "Unable to parse the intervention policy database proto.";
+    return database;
+  }
+
+  database.reserve(proto.origin_interventions_size());
+  for (int i = 0; i < proto.origin_interventions_size(); ++i) {
+    const OriginInterventions& origin_interventions_proto =
+        proto.origin_interventions(i);
+    OriginInterventionPolicies origin_intervention_policies(
+        origin_interventions_proto.discarding_policy(),
+        origin_interventions_proto.freezing_policy());
+    database.emplace(origin_interventions_proto.host_hash(),
+                     std::move(origin_intervention_policies));
+  }
+  return database;
+}
+
+void InterventionPolicyDatabase::OnReadDatabaseProtoFromFile(
+    InterventionsMap database) {
+  database_ = std::move(database);
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/intervention_policy_database.h b/chrome/browser/resource_coordinator/intervention_policy_database.h
new file mode 100644
index 0000000..42b9df1
--- /dev/null
+++ b/chrome/browser/resource_coordinator/intervention_policy_database.h
@@ -0,0 +1,85 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_INTERVENTION_POLICY_DATABASE_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_INTERVENTION_POLICY_DATABASE_H_
+
+#include "base/containers/flat_map.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/version.h"
+#include "chrome/browser/resource_coordinator/intervention_policy_database.pb.h"
+#include "url/origin.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace resource_coordinator {
+
+// Intervention policy database, this should receive data from the
+// InterventionPolicyDatabaseComponentInstallerPolicy component once it's ready.
+//
+// It is meant to be used to assist intervention decisions made for the
+// LifecycleUnits.
+class InterventionPolicyDatabase {
+ public:
+  using InterventionPolicy = OriginInterventions::InterventionPolicy;
+
+  // The intervention policies to use for a given origin.
+  struct OriginInterventionPolicies {
+    OriginInterventionPolicies(InterventionPolicy discarding_policy,
+                               InterventionPolicy freezing_policy);
+
+    InterventionPolicy discarding_policy;
+    InterventionPolicy freezing_policy;
+  };
+
+  InterventionPolicyDatabase();
+  ~InterventionPolicyDatabase();
+
+  InterventionPolicy GetDiscardingPolicy(const url::Origin& origin) const;
+  InterventionPolicy GetFreezingPolicy(const url::Origin& origin) const;
+
+  // Initialize the database with the OriginInterventionsDatabase protobuf
+  // stored in |proto_location|.
+  void InitializeDatabaseWithProtoFile(
+      const base::FilePath& proto_location,
+      const base::Version& version,
+      std::unique_ptr<base::DictionaryValue> manifest);
+
+  void AddOriginPoliciesForTesting(const url::Origin& origin,
+                                   OriginInterventionPolicies policies);
+
+ protected:
+  // Map that associates the MD5 hash of an origin to its polices.
+  using InterventionsMap =
+      base::flat_map<std::string, OriginInterventionPolicies>;
+
+  friend class InterventionPolicyDatabaseTest;
+
+  const InterventionsMap& database_for_testing() { return database_; }
+
+ private:
+  // Asynchronously initialize an |InterventionsMap| object with the content of
+  // the OriginInterventionsDatabase proto stored at |proto_location|.
+  static InterventionsMap ReadDatabaseFromProtoFileOnSequence(
+      const base::FilePath& proto_location);
+
+  // Needs to be called to initialize |database_| with the data read in
+  // InitializeDatabaseWithProtoAsync.
+  void OnReadDatabaseProtoFromFile(InterventionsMap database);
+
+  // The map that stores all the per-origin intervention policies.
+  InterventionsMap database_;
+
+  base::WeakPtrFactory<InterventionPolicyDatabase> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(InterventionPolicyDatabase);
+};
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_INTERVENTION_POLICY_DATABASE_H_
diff --git a/chrome/browser/resource_coordinator/intervention_policy_database.proto b/chrome/browser/resource_coordinator/intervention_policy_database.proto
new file mode 100644
index 0000000..876952e
--- /dev/null
+++ b/chrome/browser/resource_coordinator/intervention_policy_database.proto
@@ -0,0 +1,31 @@
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+// Information about an origin and the intervention it supports.
+// Next Id: 4
+message OriginInterventions {
+  // The MD5 hash of the origin, the value used to generate this hash
+  // should be the ‘host’ part of the origin, e.g. in
+  // “http://example.com/foo” the host is “example.com”.
+  required string host_hash = 1;
+
+  // Policy associated with an intervention. A DEFAULT value indicates
+  // that the existing heuristics should be applied.
+  enum InterventionPolicy {
+    OPT_IN = 0;
+    OPT_OUT = 1;
+    DEFAULT = 2;
+  }
+  // The discarding policy.
+  required InterventionPolicy discarding_policy = 2;
+  // The freezing policy.
+  required InterventionPolicy freezing_policy = 3;
+}
+
+// The database that contains all the origins and the interventions they
+// support.
+// Next Id: 2
+message OriginInterventionsDatabase {
+  repeated OriginInterventions origin_interventions = 1;
+}
diff --git a/chrome/browser/resource_coordinator/intervention_policy_database_unittest.cc b/chrome/browser/resource_coordinator/intervention_policy_database_unittest.cc
new file mode 100644
index 0000000..cb7c389d
--- /dev/null
+++ b/chrome/browser/resource_coordinator/intervention_policy_database_unittest.cc
@@ -0,0 +1,105 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/intervention_policy_database.h"
+
+#include <map>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "base/values.h"
+#include "chrome/browser/resource_coordinator/intervention_policy_database.pb.h"
+#include "chrome/browser/resource_coordinator/utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace resource_coordinator {
+
+namespace {
+
+using InterventionPolicy = InterventionPolicyDatabase::InterventionPolicy;
+using OriginInterventionPolicies =
+    InterventionPolicyDatabase::OriginInterventionPolicies;
+
+// Initialize a protobuf in |path| with the content of |data_map|.
+void WriteProtoToFile(
+    const base::FilePath& path,
+    std::map<url::Origin, OriginInterventionPolicies> data_map) {
+  OriginInterventionsDatabase proto;
+
+  for (const auto& iter : data_map) {
+    OriginInterventions* origin_interventions =
+        proto.add_origin_interventions();
+    EXPECT_TRUE(origin_interventions);
+    origin_interventions->set_host_hash(
+        SerializeOriginIntoDatabaseKey(iter.first));
+    origin_interventions->set_discarding_policy(iter.second.discarding_policy);
+    origin_interventions->set_freezing_policy(iter.second.freezing_policy);
+  }
+  std::string serialized_proto;
+  EXPECT_TRUE(proto.SerializeToString(&serialized_proto));
+  EXPECT_EQ(static_cast<int>(serialized_proto.length()),
+            base::WriteFile(path, serialized_proto.c_str(),
+                            serialized_proto.length()));
+}
+
+}  // namespace
+
+class InterventionPolicyDatabaseTest : public ::testing::Test {
+ protected:
+  InterventionPolicyDatabaseTest() = default;
+
+  void WaitForDatabaseToBeInitialized() {
+    while (intervention_policy_database_.database_for_testing().empty())
+      test_env_.RunUntilIdle();
+  }
+
+  InterventionPolicyDatabase* GetDatabase() {
+    return &intervention_policy_database_;
+  }
+
+ private:
+  base::test::TaskEnvironment test_env_;
+  InterventionPolicyDatabase intervention_policy_database_;
+};
+
+TEST_F(InterventionPolicyDatabaseTest, EndToEnd) {
+  base::ScopedTempDir temp_dir;
+  EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath proto_path;
+  EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir.GetPath(), &proto_path));
+
+  std::map<url::Origin, OriginInterventionPolicies> policy_map;
+  policy_map.emplace(url::Origin::Create(GURL("https://a.com")),
+                     OriginInterventionPolicies(OriginInterventions::OPT_IN,
+                                                OriginInterventions::OPT_IN));
+  policy_map.emplace(url::Origin::Create(GURL("https://b.com")),
+                     OriginInterventionPolicies(OriginInterventions::OPT_IN,
+                                                OriginInterventions::OPT_OUT));
+  policy_map.emplace(url::Origin::Create(GURL("https://c.com")),
+                     OriginInterventionPolicies(OriginInterventions::OPT_OUT,
+                                                OriginInterventions::OPT_OUT));
+  policy_map.emplace(url::Origin::Create(GURL("https://d.com")),
+                     OriginInterventionPolicies(OriginInterventions::OPT_IN,
+                                                OriginInterventions::DEFAULT));
+  WriteProtoToFile(proto_path, policy_map);
+
+  GetDatabase()->InitializeDatabaseWithProtoFile(proto_path, base::Version(),
+                                                 nullptr);
+
+  WaitForDatabaseToBeInitialized();
+
+  for (const auto& iter : policy_map) {
+    EXPECT_EQ(iter.second.discarding_policy,
+              GetDatabase()->GetDiscardingPolicy(iter.first));
+    EXPECT_EQ(iter.second.freezing_policy,
+              GetDatabase()->GetFreezingPolicy(iter.first));
+  }
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/resource_coordinator_parts.cc b/chrome/browser/resource_coordinator/resource_coordinator_parts.cc
index 577b26d..7273896 100644
--- a/chrome/browser/resource_coordinator/resource_coordinator_parts.cc
+++ b/chrome/browser/resource_coordinator/resource_coordinator_parts.cc
@@ -11,7 +11,8 @@
 ResourceCoordinatorParts::ResourceCoordinatorParts()
 #if !defined(OS_ANDROID)
     : tab_manager_(&tab_load_tracker_),
-      tab_lifecycle_unit_source_(tab_manager_.usage_clock())
+      tab_lifecycle_unit_source_(tab_manager_.intervention_policy_database(),
+                                 tab_manager_.usage_clock())
 #endif
 {
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
index 9cf5370..18583cd8 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/permissions/permission_manager.h"
 #include "chrome/browser/permissions/permission_result.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/intervention_policy_database.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_data_store_factory.h"
 #include "chrome/browser/resource_coordinator/tab_activity_watcher.h"
@@ -572,6 +573,10 @@
   if (web_contents()->GetVisibility() == content::Visibility::VISIBLE)
     decision_details->AddReason(DecisionFailureReason::LIVE_STATE_VISIBLE);
 
+  // Check the freezing intervention policy database. Tabs that have opted-in
+  // will be marked as freezable regardless of the other heuristics.
+  CheckFreezingInterventionPolicyDatabase(decision_details);
+
   // Do not freeze tabs using media, irrespective of any opt-in, as this usually
   // breaks functionality.
   CheckMediaUsage(decision_details);
@@ -1078,6 +1083,26 @@
   }
 }
 
+void TabLifecycleUnitSource::TabLifecycleUnit::
+    CheckFreezingInterventionPolicyDatabase(
+        DecisionDetails* decision_details) const {
+  // Apply intervention database opt-in/opt-out (policy is per origin).
+  auto intervention_policy =
+      GetTabSource()->intervention_policy_database()->GetFreezingPolicy(
+          url::Origin::Create(web_contents()->GetLastCommittedURL()));
+
+  switch (intervention_policy) {
+    case OriginInterventions::OPT_IN:
+      decision_details->AddReason(DecisionSuccessReason::GLOBAL_WHITELIST);
+      break;
+    case OriginInterventions::OPT_OUT:
+      decision_details->AddReason(DecisionFailureReason::GLOBAL_BLACKLIST);
+      break;
+    case OriginInterventions::DEFAULT:
+      break;
+  }
+}
+
 LifecycleUnitDiscardReason
 TabLifecycleUnitSource::TabLifecycleUnit::GetDiscardReason() const {
   return discard_reason_;
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit.h
index cf37c74b..c5f3130 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit.h
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit.h
@@ -185,6 +185,11 @@
   // for the tab.
   void CheckFreezingOriginTrial(DecisionDetails* decision_details) const;
 
+  // Updates |decision_details| based on the global intervention policy database
+  // freezing data for the tab.
+  void CheckFreezingInterventionPolicyDatabase(
+      DecisionDetails* decision_details) const;
+
   // List of observers to notify when the discarded state or the auto-
   // discardable state of this tab changes.
   base::ObserverList<TabLifecycleObserver>::Unchecked* observers_;
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
index 2afe2ba..7085f93 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.cc
@@ -173,12 +173,16 @@
 };
 
 TabLifecycleUnitSource::TabLifecycleUnitSource(
+    InterventionPolicyDatabase* intervention_policy_database,
     UsageClock* usage_clock)
     : browser_tab_strip_tracker_(this, nullptr, this),
+      intervention_policy_database_(intervention_policy_database),
       usage_clock_(usage_clock) {
   // In unit tests, tabs might already exist when TabLifecycleUnitSource is
   // instantiated. No TabLifecycleUnit is created for these tabs.
 
+  DCHECK(intervention_policy_database_);
+
   browser_tab_strip_tracker_.Init();
 }
 
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
index a60d2dd..72e1610 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_source.h
@@ -28,6 +28,7 @@
 
 namespace resource_coordinator {
 
+class InterventionPolicyDatabase;
 class TabFreezingEnabledPreferenceMonitor;
 class TabLifecycleObserver;
 class TabLifecycleStateObserver;
@@ -43,6 +44,7 @@
   class LifecycleStateObserver;
 
   TabLifecycleUnitSource(
+      InterventionPolicyDatabase* intervention_policy_database,
       UsageClock* usage_clock);
   ~TabLifecycleUnitSource() override;
 
@@ -63,6 +65,10 @@
   // Pretend that |tab_strip| is the TabStripModel of the focused window.
   void SetFocusedTabStripModelForTesting(TabStripModel* tab_strip);
 
+  InterventionPolicyDatabase* intervention_policy_database() const {
+    return intervention_policy_database_;
+  }
+
   // Returns the state of the tab lifecycles feature enterprise control. This
   // returns true if the feature should be enabled, false otherwise.
   bool tab_lifecycles_enterprise_policy() const {
@@ -187,6 +193,10 @@
   // changes.
   base::ObserverList<TabLifecycleObserver>::Unchecked tab_lifecycle_observers_;
 
+  // The intervention policy database used to assist freezing/discarding
+  // decisions.
+  InterventionPolicyDatabase* intervention_policy_database_;
+
   // A clock that advances when Chrome is in use.
   UsageClock* const usage_clock_;
 
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
index ef2d0c5..043caa9 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_unittest.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h"
 #include "chrome/browser/notifications/notification_permission_context.h"
 #include "chrome/browser/permissions/permission_request_manager.h"
+#include "chrome/browser/resource_coordinator/intervention_policy_database.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit_observer.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer.h"
@@ -609,6 +610,47 @@
       DecisionFailureReason::HEURISTIC_INSUFFICIENT_OBSERVATION, nullptr);
 }
 
+TEST_F(TabLifecycleUnitTest, CannotFreezeTabIfOriginOptedOut) {
+  auto* policy_db = GetTabLifecycleUnitSource()->intervention_policy_database();
+  policy_db->AddOriginPoliciesForTesting(
+      url::Origin::Create(web_contents_->GetLastCommittedURL()),
+      InterventionPolicyDatabase::OriginInterventionPolicies(
+          OriginInterventions::DEFAULT, OriginInterventions::OPT_OUT));
+
+  TabLifecycleUnit tab_lifecycle_unit(GetTabLifecycleUnitSource(), &observers_,
+                                      usage_clock_.get(), web_contents_,
+                                      tab_strip_model_.get());
+  TabLoadTracker::Get()->TransitionStateForTesting(web_contents_,
+                                                   LoadingState::LOADED);
+  DecisionDetails decision_details;
+  EXPECT_FALSE(tab_lifecycle_unit.CanFreeze(&decision_details));
+  EXPECT_FALSE(decision_details.IsPositive());
+  EXPECT_EQ(DecisionFailureReason::GLOBAL_BLACKLIST,
+            decision_details.FailureReason());
+}
+
+TEST_F(TabLifecycleUnitTest, CanFreezeOptedInTabs) {
+  auto* policy_db = GetTabLifecycleUnitSource()->intervention_policy_database();
+  policy_db->AddOriginPoliciesForTesting(
+      url::Origin::Create(web_contents_->GetLastCommittedURL()),
+      {OriginInterventions::DEFAULT, OriginInterventions::OPT_IN});
+
+  TabLifecycleUnit tab_lifecycle_unit(GetTabLifecycleUnitSource(), &observers_,
+                                      usage_clock_.get(), web_contents_,
+                                      tab_strip_model_.get());
+  TabLoadTracker::Get()->TransitionStateForTesting(web_contents_,
+                                                   LoadingState::LOADED);
+
+  // Mark the tab as recently audible, this should protect it from being frozen.
+  tab_lifecycle_unit.SetRecentlyAudible(true);
+
+  DecisionDetails decision_details;
+  EXPECT_TRUE(tab_lifecycle_unit.CanFreeze(&decision_details));
+  EXPECT_TRUE(decision_details.IsPositive());
+  EXPECT_EQ(DecisionSuccessReason::GLOBAL_WHITELIST,
+            decision_details.SuccessReason());
+}
+
 TEST_F(TabLifecycleUnitTest, CannotFreezeAFrozenTab) {
   TabLifecycleUnit tab_lifecycle_unit(GetTabLifecycleUnitSource(), &observers_,
                                       usage_clock_.get(), web_contents_,
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 2fa13cd..ee566a8 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -169,6 +169,7 @@
   proactive_freeze_discard_params_ =
       GetStaticProactiveTabFreezeAndDiscardParams();
   tab_load_tracker_->AddObserver(this);
+  intervention_policy_database_.reset(new InterventionPolicyDatabase());
 
   // TabManager works in the absence of DesktopSessionDurationTracker for tests.
   if (metrics::DesktopSessionDurationTracker::IsInitialized())
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 7722635..1ee8f74 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -19,6 +19,7 @@
 #include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h"
+#include "chrome/browser/resource_coordinator/intervention_policy_database.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit_observer.h"
 #include "chrome/browser/resource_coordinator/lifecycle_unit_source_observer.h"
@@ -152,6 +153,10 @@
   // non-zero only during session restore.
   int restored_tab_count() const { return restored_tab_count_; }
 
+  InterventionPolicyDatabase* intervention_policy_database() {
+    return intervention_policy_database_.get();
+  }
+
   UsageClock* usage_clock() { return &usage_clock_; }
 
   // Returns true if the tab was created by session restore and has not finished
@@ -470,6 +475,10 @@
   // session restore.
   std::unique_ptr<TabManagerStatsCollector> stats_collector_;
 
+  // The intervention policy database, should be initialized by
+  // InterventionPolicyDatabaseComponentInstallerPolicy.
+  std::unique_ptr<InterventionPolicyDatabase> intervention_policy_database_;
+
   // Last time at which a LifecycleUnit was temporarily unfrozen.
   base::TimeTicks last_unfreeze_time_;
 
diff --git a/chrome/browser/resources/chromeos/crostini_upgrader/BUILD.gn b/chrome/browser/resources/chromeos/crostini_upgrader/BUILD.gn
index 0d27180..314b9cb 100644
--- a/chrome/browser/resources/chromeos/crostini_upgrader/BUILD.gn
+++ b/chrome/browser/resources/chromeos/crostini_upgrader/BUILD.gn
@@ -39,7 +39,5 @@
 }
 
 group("polymer3_elements") {
-  deps = [
-    ":app_module",
-  ]
+  deps = [ ":app_module" ]
 }
diff --git a/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn b/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
index 6d58124..f899962 100644
--- a/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
+++ b/chrome/browser/resources/chromeos/internet_config_dialog/BUILD.gn
@@ -18,9 +18,7 @@
 }
 
 js_type_check("closure_compile") {
-  deps = [
-    ":internet_config_dialog",
-  ]
+  deps = [ ":internet_config_dialog" ]
 }
 
 js_library("internet_config_dialog") {
diff --git a/chrome/browser/resources/conflicts/BUILD.gn b/chrome/browser/resources/conflicts/BUILD.gn
index 3e55232..a993915 100644
--- a/chrome/browser/resources/conflicts/BUILD.gn
+++ b/chrome/browser/resources/conflicts/BUILD.gn
@@ -6,9 +6,7 @@
 
 js_type_check("closure_compile") {
   uses_js_modules = true
-  deps = [
-    ":about_conflicts",
-  ]
+  deps = [ ":about_conflicts" ]
 }
 
 js_library("about_conflicts") {
diff --git a/chrome/browser/resources/pdf/BUILD.gn b/chrome/browser/resources/pdf/BUILD.gn
index 0acf118..5118959 100644
--- a/chrome/browser/resources/pdf/BUILD.gn
+++ b/chrome/browser/resources/pdf/BUILD.gn
@@ -18,9 +18,7 @@
 }
 
 js_library("browser_api") {
-  deps = [
-    "//ui/webui/resources/js:assert.m",
-  ]
+  deps = [ "//ui/webui/resources/js:assert.m" ]
   externs_list = [
     "$externs_path/chrome_extensions.js",
     "$externs_path/mime_handler_private.js",
@@ -34,9 +32,7 @@
 }
 
 js_library("open_pdf_params_parser") {
-  deps = [
-    ":pdf_fitting_type",
-  ]
+  deps = [ ":pdf_fitting_type" ]
 }
 
 js_library("pdf_scripting_api") {
@@ -65,9 +61,7 @@
 }
 
 js_library("metrics") {
-  deps = [
-    ":pdf_fitting_type",
-  ]
+  deps = [ ":pdf_fitting_type" ]
   externs_list = [ "$externs_path/metrics_private.js" ]
 }
 
diff --git a/chrome/browser/resources/pdf/elements/BUILD.gn b/chrome/browser/resources/pdf/elements/BUILD.gn
index 1ffa844..b8841ba 100644
--- a/chrome/browser/resources/pdf/elements/BUILD.gn
+++ b/chrome/browser/resources/pdf/elements/BUILD.gn
@@ -34,9 +34,7 @@
 }
 
 js_library("viewer-error-screen") {
-  deps = [
-    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
-  ]
+  deps = [ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m" ]
 }
 
 if (is_chromeos) {
@@ -64,15 +62,11 @@
 }
 
 js_library("viewer-page-selector") {
-  deps = [
-    "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
-  ]
+  deps = [ "//ui/webui/resources/cr_elements/cr_input:cr_input.m" ]
 }
 
 js_library("viewer-password-screen") {
-  deps = [
-    "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
-  ]
+  deps = [ "//ui/webui/resources/cr_elements/cr_input:cr_input.m" ]
 }
 
 js_library("viewer-pdf-toolbar") {
diff --git a/chrome/browser/resources/pdf/ink/BUILD.gn b/chrome/browser/resources/pdf/ink/BUILD.gn
index b1c2be2..ddf46dc4 100644
--- a/chrome/browser/resources/pdf/ink/BUILD.gn
+++ b/chrome/browser/resources/pdf/ink/BUILD.gn
@@ -5,15 +5,11 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
-  deps = [
-    ":ink_api",
-  ]
+  deps = [ ":ink_api" ]
 }
 
 js_library("ink_api") {
-  deps = [
-    "..:annotation_tool",
-  ]
+  deps = [ "..:annotation_tool" ]
   externs_list = [
     "//third_party/ink/build/ink_lib_externs.js",
     "$externs_path/pending.js",
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index 93ccfab..973a2a6 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -30,18 +30,14 @@
     ]
     excludes = [ "chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom.html" ]
 
-    deps = [
-      ":unpak",
-    ]
+    deps = [ ":unpak" ]
   }
 
   unpak("unpak") {
     pak_file = settings_pak_file
     out_folder = unpak_folder
 
-    deps = [
-      ":flattened_resources",
-    ]
+    deps = [ ":flattened_resources" ]
   }
 
   grit("flattened_resources") {
@@ -137,16 +133,12 @@
 }
 
 js_library("lifetime_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
 js_library("open_window_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
 }
 
 js_library("route") {
diff --git a/chrome/browser/resources/settings/a11y_page/BUILD.gn b/chrome/browser/resources/settings/a11y_page/BUILD.gn
index 4ea0b75..0c60419 100644
--- a/chrome/browser/resources/settings/a11y_page/BUILD.gn
+++ b/chrome/browser/resources/settings/a11y_page/BUILD.gn
@@ -32,7 +32,5 @@
 }
 
 js_library("captions_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
 }
diff --git a/chrome/browser/resources/settings/about_page/BUILD.gn b/chrome/browser/resources/settings/about_page/BUILD.gn
index 783647a..d067447 100644
--- a/chrome/browser/resources/settings/about_page/BUILD.gn
+++ b/chrome/browser/resources/settings/about_page/BUILD.gn
@@ -24,8 +24,6 @@
 }
 
 js_library("about_page_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
diff --git a/chrome/browser/resources/settings/autofill_page/BUILD.gn b/chrome/browser/resources/settings/autofill_page/BUILD.gn
index 1afa9c4..c143705 100644
--- a/chrome/browser/resources/settings/autofill_page/BUILD.gn
+++ b/chrome/browser/resources/settings/autofill_page/BUILD.gn
@@ -77,9 +77,7 @@
 }
 
 js_library("credit_card_edit_dialog") {
-  deps = [
-    "//ui/webui/resources/js:i18n_behavior",
-  ]
+  deps = [ "//ui/webui/resources/js:i18n_behavior" ]
   externs_list = [ "$externs_path/autofill_private.js" ]
 }
 
@@ -91,9 +89,7 @@
 }
 
 js_library("credit_card_list_entry") {
-  deps = [
-    "//ui/webui/resources/js:i18n_behavior",
-  ]
+  deps = [ "//ui/webui/resources/js:i18n_behavior" ]
 }
 
 js_library("password_list_item") {
@@ -105,9 +101,7 @@
 }
 
 js_library("password_manager_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
   externs_list = [ "$externs_path/passwords_private.js" ]
 }
 
@@ -140,8 +134,6 @@
 }
 
 js_library("show_password_behavior") {
-  deps = [
-    ":blocking_request_manager",
-  ]
+  deps = [ ":blocking_request_manager" ]
   externs_list = [ "$externs_path/passwords_private.js" ]
 }
diff --git a/chrome/browser/resources/settings/basic_page/BUILD.gn b/chrome/browser/resources/settings/basic_page/BUILD.gn
index 9a638da..a2d6e28 100644
--- a/chrome/browser/resources/settings/basic_page/BUILD.gn
+++ b/chrome/browser/resources/settings/basic_page/BUILD.gn
@@ -5,9 +5,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
-  deps = [
-    ":basic_page",
-  ]
+  deps = [ ":basic_page" ]
 }
 
 js_library("basic_page") {
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_main/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_settings_main/BUILD.gn
index 7bd433c..3f12898 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_main/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_settings_main/BUILD.gn
@@ -5,9 +5,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
-  deps = [
-    ":os_settings_main",
-  ]
+  deps = [ ":os_settings_main" ]
 }
 
 js_library("os_settings_main") {
diff --git a/chrome/browser/resources/settings/controls/BUILD.gn b/chrome/browser/resources/settings/controls/BUILD.gn
index 7baf0b5..b0c95ad 100644
--- a/chrome/browser/resources/settings/controls/BUILD.gn
+++ b/chrome/browser/resources/settings/controls/BUILD.gn
@@ -59,9 +59,7 @@
 }
 
 js_library("pref_control_behavior") {
-  deps = [
-    "../prefs:prefs_types",
-  ]
+  deps = [ "../prefs:prefs_types" ]
 }
 
 js_library("settings_boolean_control_behavior") {
@@ -74,9 +72,7 @@
 }
 
 js_library("settings_checkbox") {
-  deps = [
-    ":settings_boolean_control_behavior",
-  ]
+  deps = [ ":settings_boolean_control_behavior" ]
 }
 
 js_library("settings_dropdown_menu") {
diff --git a/chrome/browser/resources/settings/default_browser_page/BUILD.gn b/chrome/browser/resources/settings/default_browser_page/BUILD.gn
index efe93f1..be47a84 100644
--- a/chrome/browser/resources/settings/default_browser_page/BUILD.gn
+++ b/chrome/browser/resources/settings/default_browser_page/BUILD.gn
@@ -12,9 +12,7 @@
 }
 
 js_library("default_browser_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
 }
 
 js_library("default_browser_page") {
diff --git a/chrome/browser/resources/settings/incompatible_applications_page/BUILD.gn b/chrome/browser/resources/settings/incompatible_applications_page/BUILD.gn
index 78dfe00..7d974d0 100644
--- a/chrome/browser/resources/settings/incompatible_applications_page/BUILD.gn
+++ b/chrome/browser/resources/settings/incompatible_applications_page/BUILD.gn
@@ -13,9 +13,7 @@
 }
 
 js_library("incompatible_applications_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
 }
 
 js_library("incompatible_applications_page") {
diff --git a/chrome/browser/resources/settings/languages_page/BUILD.gn b/chrome/browser/resources/settings/languages_page/BUILD.gn
index 8bc3523..fc4231d 100644
--- a/chrome/browser/resources/settings/languages_page/BUILD.gn
+++ b/chrome/browser/resources/settings/languages_page/BUILD.gn
@@ -15,9 +15,7 @@
 }
 
 js_library("languages_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
   externs_list = [
     "$externs_path/chrome_send.js",
     "$externs_path/input_method_private.js",
diff --git a/chrome/browser/resources/settings/people_page/BUILD.gn b/chrome/browser/resources/settings/people_page/BUILD.gn
index 78ed0b375..901cfd9a 100644
--- a/chrome/browser/resources/settings/people_page/BUILD.gn
+++ b/chrome/browser/resources/settings/people_page/BUILD.gn
@@ -29,15 +29,11 @@
 }
 
 js_library("account_manager_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
 }
 
 js_library("import_data_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
 }
 
 js_library("manage_profile") {
@@ -79,9 +75,7 @@
 }
 
 js_library("profile_info_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
 }
 
 js_library("signout_dialog") {
diff --git a/chrome/browser/resources/settings/prefs/BUILD.gn b/chrome/browser/resources/settings/prefs/BUILD.gn
index 6f61f79..f73bf6a 100644
--- a/chrome/browser/resources/settings/prefs/BUILD.gn
+++ b/chrome/browser/resources/settings/prefs/BUILD.gn
@@ -14,9 +14,7 @@
 }
 
 js_library("pref_util") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
   externs_list = [ "$externs_path/settings_private.js" ]
 }
 
@@ -32,9 +30,7 @@
 }
 
 js_library("prefs_behavior") {
-  deps = [
-    "//ui/webui/resources/js:assert",
-  ]
+  deps = [ "//ui/webui/resources/js:assert" ]
   externs_list = [ "$externs_path/settings_private.js" ]
 }
 
diff --git a/chrome/browser/resources/settings/printing_page/BUILD.gn b/chrome/browser/resources/settings/printing_page/BUILD.gn
index 8382d4b..d035eda 100644
--- a/chrome/browser/resources/settings/printing_page/BUILD.gn
+++ b/chrome/browser/resources/settings/printing_page/BUILD.gn
@@ -16,15 +16,11 @@
 }
 
 js_library("cloud_printers") {
-  deps = [
-    "//ui/webui/resources/js:load_time_data",
-  ]
+  deps = [ "//ui/webui/resources/js:load_time_data" ]
 }
 
 js_library("printing_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
 }
 
 js_library("printing_page") {
diff --git a/chrome/browser/resources/settings/privacy_page/BUILD.gn b/chrome/browser/resources/settings/privacy_page/BUILD.gn
index 64f9d06..7a83433 100644
--- a/chrome/browser/resources/settings/privacy_page/BUILD.gn
+++ b/chrome/browser/resources/settings/privacy_page/BUILD.gn
@@ -71,9 +71,7 @@
 }
 
 js_library("security_keys_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
@@ -97,9 +95,7 @@
 }
 
 js_library("security_keys_pin_field") {
-  deps = [
-    "//ui/webui/resources/js:i18n_behavior",
-  ]
+  deps = [ "//ui/webui/resources/js:i18n_behavior" ]
 }
 
 js_library("security_keys_credential_management_dialog") {
diff --git a/chrome/browser/resources/settings/reset_page/BUILD.gn b/chrome/browser/resources/settings/reset_page/BUILD.gn
index 6395858..6cb4880 100644
--- a/chrome/browser/resources/settings/reset_page/BUILD.gn
+++ b/chrome/browser/resources/settings/reset_page/BUILD.gn
@@ -25,9 +25,7 @@
 }
 
 js_library("reset_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
diff --git a/chrome/browser/resources/settings/search_page/BUILD.gn b/chrome/browser/resources/settings/search_page/BUILD.gn
index 6eeb409..2dc01e4 100644
--- a/chrome/browser/resources/settings/search_page/BUILD.gn
+++ b/chrome/browser/resources/settings/search_page/BUILD.gn
@@ -5,9 +5,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
-  deps = [
-    ":search_page",
-  ]
+  deps = [ ":search_page" ]
 }
 
 js_library("search_page") {
diff --git a/chrome/browser/resources/settings/settings_main/BUILD.gn b/chrome/browser/resources/settings/settings_main/BUILD.gn
index c4eddc9..27ab689 100644
--- a/chrome/browser/resources/settings/settings_main/BUILD.gn
+++ b/chrome/browser/resources/settings/settings_main/BUILD.gn
@@ -5,9 +5,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
-  deps = [
-    ":settings_main",
-  ]
+  deps = [ ":settings_main" ]
 }
 
 js_library("settings_main") {
diff --git a/chrome/browser/resources/settings/settings_menu/BUILD.gn b/chrome/browser/resources/settings/settings_menu/BUILD.gn
index d138e44..61674b7 100644
--- a/chrome/browser/resources/settings/settings_menu/BUILD.gn
+++ b/chrome/browser/resources/settings/settings_menu/BUILD.gn
@@ -5,9 +5,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
-  deps = [
-    ":settings_menu",
-  ]
+  deps = [ ":settings_menu" ]
 }
 
 js_library("settings_menu") {
diff --git a/chrome/browser/resources/settings/settings_ui/BUILD.gn b/chrome/browser/resources/settings/settings_ui/BUILD.gn
index 5352040..ec6c264 100644
--- a/chrome/browser/resources/settings/settings_ui/BUILD.gn
+++ b/chrome/browser/resources/settings/settings_ui/BUILD.gn
@@ -5,9 +5,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
-  deps = [
-    ":settings_ui",
-  ]
+  deps = [ ":settings_ui" ]
 }
 
 js_library("settings_ui") {
diff --git a/chrome/browser/resources/settings/site_settings/BUILD.gn b/chrome/browser/resources/settings/site_settings/BUILD.gn
index 24113bc..1765699 100644
--- a/chrome/browser/resources/settings/site_settings/BUILD.gn
+++ b/chrome/browser/resources/settings/site_settings/BUILD.gn
@@ -55,9 +55,7 @@
 }
 
 js_library("android_info_browser_proxy") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
@@ -106,9 +104,7 @@
 }
 
 js_library("constants") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
 }
 
 js_library("local_data_browser_proxy") {
@@ -131,9 +127,7 @@
 }
 
 js_library("cookie_info") {
-  deps = [
-    "//ui/webui/resources/js:load_time_data",
-  ]
+  deps = [ "//ui/webui/resources/js:load_time_data" ]
 }
 
 js_library("protocol_handlers") {
@@ -281,9 +275,7 @@
 }
 
 js_library("website_usage_private_api") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
+  deps = [ "//ui/webui/resources/js:cr" ]
   externs_list = [ "$externs_path/chrome_send.js" ]
 }
 
diff --git a/chrome/browser/resources/settings/site_settings_page/BUILD.gn b/chrome/browser/resources/settings/site_settings_page/BUILD.gn
index 7467e9e..ac27ac9 100644
--- a/chrome/browser/resources/settings/site_settings_page/BUILD.gn
+++ b/chrome/browser/resources/settings/site_settings_page/BUILD.gn
@@ -5,9 +5,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
-  deps = [
-    ":site_settings_page",
-  ]
+  deps = [ ":site_settings_page" ]
 }
 
 js_library("site_settings_page") {
diff --git a/chrome/browser/resources/ssl/ssl_error_assistant/BUILD.gn b/chrome/browser/resources/ssl/ssl_error_assistant/BUILD.gn
index 1d1d09f..6b3429d 100644
--- a/chrome/browser/resources/ssl/ssl_error_assistant/BUILD.gn
+++ b/chrome/browser/resources/ssl/ssl_error_assistant/BUILD.gn
@@ -16,18 +16,14 @@
   python_path_ssl =
       "$python_path_root/components/security_interstitials/content/"
 
-  inputs = [
-    input_filename,
-  ]
+  inputs = [ input_filename ]
 
   deps = [
     "//components/security_interstitials/content:proto",
     "//third_party/protobuf:py_proto",
   ]
 
-  outputs = [
-    "$output_dir/$output_basename",
-  ]
+  outputs = [ "$output_dir/$output_basename" ]
 
   args = [
     "-w",
diff --git a/chrome/browser/signin/signin_profile_attributes_updater.cc b/chrome/browser/signin/signin_profile_attributes_updater.cc
index 8a4bbea..a2acb3e 100644
--- a/chrome/browser/signin/signin_profile_attributes_updater.cc
+++ b/chrome/browser/signin/signin_profile_attributes_updater.cc
@@ -54,10 +54,7 @@
   CoreAccountInfo account_info =
       identity_manager_->GetUnconsentedPrimaryAccountInfo();
 
-  bool clear_profile =
-      account_info.IsEmpty() ||
-      (!base::FeatureList::IsEnabled(kPersistUPAInProfileInfoCache) &&
-       !identity_manager_->HasPrimaryAccount());
+  bool clear_profile = account_info.IsEmpty();
 
   if (account_info.gaia != entry->GetGAIAId() ||
       !gaia::AreEmailsSame(account_info.email,
@@ -116,10 +113,8 @@
 
 void SigninProfileAttributesUpdater::OnUnconsentedPrimaryAccountChanged(
     const CoreAccountInfo& unconsented_primary_account_info) {
-  if (identity_manager_->HasPrimaryAccount() ||
-      !base::FeatureList::IsEnabled(kPersistUPAInProfileInfoCache)) {
+  if (identity_manager_->HasPrimaryAccount())
     return;
-  }
 
   UpdateProfileAttributes();
 }
diff --git a/chrome/browser/sync/trusted_vault_client_android.cc b/chrome/browser/sync/trusted_vault_client_android.cc
index 6c53226..a8a068d 100644
--- a/chrome/browser/sync/trusted_vault_client_android.cc
+++ b/chrome/browser/sync/trusted_vault_client_android.cc
@@ -12,9 +12,9 @@
 #include "content/public/browser/browser_thread.h"
 
 TrustedVaultClientAndroid::OngoingFetchKeys::OngoingFetchKeys(
-    const std::string& gaia_id,
+    const CoreAccountInfo& account_info,
     base::OnceCallback<void(const std::vector<std::vector<uint8_t>>&)> callback)
-    : gaia_id(gaia_id), callback(std::move(callback)) {}
+    : account_info(account_info), callback(std::move(callback)) {}
 
 TrustedVaultClientAndroid::OngoingFetchKeys::~OngoingFetchKeys() = default;
 
@@ -35,7 +35,7 @@
     const base::android::JavaParamRef<jobjectArray>& keys) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(ongoing_fetch_keys_) << "No ongoing FetchKeys() request";
-  DCHECK_EQ(ongoing_fetch_keys_->gaia_id,
+  DCHECK_EQ(ongoing_fetch_keys_->account_info.gaia,
             base::android::ConvertJavaStringToUTF8(env, gaia_id))
       << "User mismatch in FetchKeys() response";
 
@@ -73,7 +73,7 @@
 }
 
 void TrustedVaultClientAndroid::FetchKeys(
-    const std::string& gaia_id,
+    const CoreAccountInfo& account_info,
     base::OnceCallback<void(const std::vector<std::vector<uint8_t>>&)> cb) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(!ongoing_fetch_keys_)
@@ -83,16 +83,16 @@
 
   // Store for later completion when Java invokes FetchKeysCompleted().
   ongoing_fetch_keys_ =
-      std::make_unique<OngoingFetchKeys>(gaia_id, std::move(cb));
+      std::make_unique<OngoingFetchKeys>(account_info, std::move(cb));
 
   JNIEnv* const env = base::android::AttachCurrentThread();
-  const base::android::ScopedJavaLocalRef<jstring> java_gaia_id =
-      base::android::ConvertUTF8ToJavaString(env, gaia_id);
+  const base::android::ScopedJavaLocalRef<jobject> java_account_info =
+      ConvertToJavaCoreAccountInfo(env, account_info);
 
   // Trigger the fetching keys from the implementation in Java, which will
   // eventually call FetchKeysCompleted().
   Java_TrustedVaultClient_fetchKeys(env, reinterpret_cast<intptr_t>(this),
-                                    java_gaia_id);
+                                    java_account_info);
 }
 
 void TrustedVaultClientAndroid::StoreKeys(
@@ -104,7 +104,7 @@
 }
 
 void TrustedVaultClientAndroid::MarkKeysAsStale(
-    const std::string& gaia_id,
+    const CoreAccountInfo& account_info,
     base::OnceCallback<void(bool)> cb) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(cb);
@@ -117,10 +117,10 @@
   ongoing_mark_keys_as_stale_ = std::move(cb);
 
   JNIEnv* const env = base::android::AttachCurrentThread();
-  const base::android::ScopedJavaLocalRef<jstring> java_gaia_id =
-      base::android::ConvertUTF8ToJavaString(env, gaia_id);
+  const base::android::ScopedJavaLocalRef<jobject> java_account_info =
+      ConvertToJavaCoreAccountInfo(env, account_info);
 
   // The Java implementation will eventually call MarkKeysAsStaleCompleted().
   Java_TrustedVaultClient_markKeysAsStale(env, reinterpret_cast<intptr_t>(this),
-                                          java_gaia_id);
+                                          java_account_info);
 }
diff --git a/chrome/browser/sync/trusted_vault_client_android.h b/chrome/browser/sync/trusted_vault_client_android.h
index 6f980d2..9ca98fea 100644
--- a/chrome/browser/sync/trusted_vault_client_android.h
+++ b/chrome/browser/sync/trusted_vault_client_android.h
@@ -13,6 +13,7 @@
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/callback.h"
+#include "components/signin/public/identity_manager/account_info.h"
 #include "components/sync/driver/trusted_vault_client.h"
 
 // JNI bridge for a Java implementation of the TrustedVaultClient interface,
@@ -48,25 +49,25 @@
   std::unique_ptr<Subscription> AddKeysChangedObserver(
       const base::RepeatingClosure& cb) override;
   void FetchKeys(
-      const std::string& gaia_id,
+      const CoreAccountInfo& account_info,
       base::OnceCallback<void(const std::vector<std::vector<uint8_t>>&)> cb)
       override;
   void StoreKeys(const std::string& gaia_id,
                  const std::vector<std::vector<uint8_t>>& keys,
                  int last_key_version) override;
-  void MarkKeysAsStale(const std::string& gaia_id,
+  void MarkKeysAsStale(const CoreAccountInfo& account_info,
                        base::OnceCallback<void(bool)> cb) override;
 
  private:
   // Struct representing an in-flight FetchKeys() call invoked from C++.
   struct OngoingFetchKeys {
     OngoingFetchKeys(
-        const std::string& gaia_id,
+        const CoreAccountInfo& account_info,
         base::OnceCallback<void(const std::vector<std::vector<uint8_t>>&)>
             callback);
     ~OngoingFetchKeys();
 
-    const std::string gaia_id;
+    const CoreAccountInfo account_info;
     base::OnceCallback<void(const std::vector<std::vector<uint8_t>>&)> callback;
   };
 
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_launcher_controller.cc
index 1f7a8a85..4b69a57 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_launcher_controller.cc
@@ -260,6 +260,19 @@
 
 void AppServiceAppWindowLauncherController::OnInstanceUpdate(
     const apps::InstanceUpdate& update) {
+  if (update.StateChanged() &&
+      update.State() == apps::InstanceState::kDestroyed) {
+    // For Chrome apps edge case, it could be added for the inactive users, and
+    // then removed. Since it is not registered we don't need to do anything
+    // anyways. As such, all which is left to do here is to get rid of our own
+    // reference.
+    WindowList::iterator it =
+        std::find(window_list_.begin(), window_list_.end(), update.Window());
+    if (it != window_list_.end())
+      window_list_.erase(it);
+    return;
+  }
+
   aura::Window* window = update.Window();
   if (!observed_windows_.IsObserving(window))
     return;
@@ -318,18 +331,6 @@
       aura_window_to_app_window_.erase(app_window_it);
     }
   }
-
-  if (update.StateChanged() &&
-      update.State() == apps::InstanceState::kDestroyed) {
-    // For Chrome apps edge case, it could be added for the inactive users, and
-    // then removed. Since it is not registered we don't need to do anything
-    // anyways. As such, all which is left to do here is to get rid of our own
-    // reference.
-    WindowList::iterator it =
-        std::find(window_list_.begin(), window_list_.end(), update.Window());
-    if (it != window_list_.end())
-      window_list_.erase(it);
-  }
 }
 
 void AppServiceAppWindowLauncherController::OnInstanceRegistryWillBeDestroyed(
diff --git a/chrome/browser/ui/ash/launcher/shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/shelf_context_menu.cc
index 17d59e7..d3e84f8d 100644
--- a/chrome/browser/ui/ash/launcher/shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/shelf_context_menu.cc
@@ -115,8 +115,13 @@
   if (command_id == ash::SWAP_WITH_NEXT ||
       command_id == ash::SWAP_WITH_PREVIOUS) {
     // Only show commands to reorder shelf items when ChromeVox is enabled.
-    return chromeos::AccessibilityManager::Get() &&
-           chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled();
+    if (!chromeos::AccessibilityManager::Get() ||
+        !chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
+      return false;
+    }
+    const ash::ShelfModel* model = controller_->shelf_model();
+    return model->CanSwap(model->ItemIndexByID(item_.id),
+                          /*with_next=*/command_id == ash::SWAP_WITH_NEXT);
   }
 
   DCHECK(command_id < ash::COMMAND_ID_COUNT);
diff --git a/chrome/browser/ui/libgtkui/BUILD.gn b/chrome/browser/ui/libgtkui/BUILD.gn
index b1b8e33..7b20289 100644
--- a/chrome/browser/ui/libgtkui/BUILD.gn
+++ b/chrome/browser/ui/libgtkui/BUILD.gn
@@ -84,9 +84,7 @@
     "//ui/strings",
     "//ui/views",
   ]
-  public_deps = [
-    "//chrome/browser:theme_properties",
-  ]
+  public_deps = [ "//chrome/browser:theme_properties" ]
 
   if (use_x11 || ozone_platform_x11) {
     sources += [
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
index 9868bf7..fef58ea 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -592,11 +592,11 @@
     history_ui_favicon_request_handler->GetFaviconImageForPageURL(
         url,
         base::BindOnce(&RecentTabsSubMenuModel::OnFaviconDataAvailable,
-                       weak_ptr_factory_.GetWeakPtr(), command_id),
+                       weak_ptr_factory_for_other_devices_tab_.GetWeakPtr(),
+                       command_id),
 
         favicon::HistoryUiFaviconRequestOrigin::kRecentTabs,
-        open_tabs ? open_tabs->GetIconUrlForPageUrl(url) : GURL(),
-        &other_devices_tab_cancelable_task_tracker_);
+        open_tabs ? open_tabs->GetIconUrlForPageUrl(url) : GURL());
   }
 }
 
@@ -650,7 +650,7 @@
   for (int index = count - 1; index > last_local_model_index_; --index)
     RemoveItemAt(index);
 
-  other_devices_tab_cancelable_task_tracker_.TryCancelAll();
+  weak_ptr_factory_for_other_devices_tab_.InvalidateWeakPtrs();
 
   other_devices_tab_navigation_items_.clear();
 }
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
index 5a97528..911131f8 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h
@@ -176,7 +176,6 @@
   int last_local_model_index_ = kHistorySeparatorIndex;
 
   base::CancelableTaskTracker local_tab_cancelable_task_tracker_;
-  base::CancelableTaskTracker other_devices_tab_cancelable_task_tracker_;
 
   // Time the menu is open for until a recent tab is selected.
   base::ElapsedTimer menu_opened_timer_;
@@ -189,6 +188,8 @@
       foreign_session_updated_subscription_;
 
   base::WeakPtrFactory<RecentTabsSubMenuModel> weak_ptr_factory_{this};
+  base::WeakPtrFactory<RecentTabsSubMenuModel>
+      weak_ptr_factory_for_other_devices_tab_{this};
 
   DISALLOW_COPY_AND_ASSIGN(RecentTabsSubMenuModel);
 };
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
index e4c9275..23d8173 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
@@ -57,12 +57,11 @@
                                  const gfx::Image& user_identity_image) {
   ProfileAttributesEntry* entry = GetProfileAttributesEntry(profile);
   DCHECK(entry);
-  // TODO(crbug.com/1012179): If kPersistUPAInProfileInfoCache feature is on, it
-  // should suffice to call entry->GetAvatarIcon(). For this to work well, this
-  // class needs to observe ProfileAttributesStorage instead of (or on top of)
-  // IdentityManager. Only then we can rely on |entry| being up to date (as the
-  // storage also observes IdentityManager so there's no guarantee on the order
-  // of notifications).
+  // TODO(crbug.com/1012179): it should suffice to call entry->GetAvatarIcon().
+  // For this to work well, this class needs to observe ProfileAttributesStorage
+  // instead of (or on top of) IdentityManager. Only then we can rely on |entry|
+  // being up to date (as the storage also observes IdentityManager so there's
+  // no guarantee on the order of notifications).
   if (entry->IsUsingGAIAPicture() && entry->GetGAIAPicture())
     return *entry->GetGAIAPicture();
 
diff --git a/chrome/browser/ui/webui/favicon_source.cc b/chrome/browser/ui/webui/favicon_source.cc
index 0b8e995c..111fed9 100644
--- a/chrome/browser/ui/webui/favicon_source.cc
+++ b/chrome/browser/ui/webui/favicon_source.cc
@@ -165,10 +165,11 @@
     history_ui_favicon_request_handler->GetRawFaviconForPageURL(
         page_url, desired_size_in_pixel,
         base::BindOnce(&FaviconSource::OnFaviconDataAvailable,
-                       base::Unretained(this), std::move(callback), parsed),
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                       parsed),
         favicon::FaviconRequestPlatform::kDesktop, parsed_history_ui_origin,
         /*icon_url_for_uma=*/
-        GURL(parsed.icon_url), &cancelable_task_tracker_);
+        GURL(parsed.icon_url));
   }
 }
 
diff --git a/chrome/browser/ui/webui/favicon_source.h b/chrome/browser/ui/webui/favicon_source.h
index c359595..b46bf39 100644
--- a/chrome/browser/ui/webui/favicon_source.h
+++ b/chrome/browser/ui/webui/favicon_source.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "components/favicon/core/favicon_service.h"
 #include "content/public/browser/url_data_source.h"
@@ -96,6 +97,8 @@
 
   base::CancelableTaskTracker cancelable_task_tracker_;
 
+  base::WeakPtrFactory<FaviconSource> weak_ptr_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(FaviconSource);
 };
 
diff --git a/chrome/browser/ui/webui/favicon_source_unittest.cc b/chrome/browser/ui/webui/favicon_source_unittest.cc
index 43a30679..78f08ca 100644
--- a/chrome/browser/ui/webui/favicon_source_unittest.cc
+++ b/chrome/browser/ui/webui/favicon_source_unittest.cc
@@ -47,23 +47,21 @@
   MockHistoryUiFaviconRequestHandler() = default;
   ~MockHistoryUiFaviconRequestHandler() override = default;
 
-  MOCK_METHOD7(
+  MOCK_METHOD6(
       GetRawFaviconForPageURL,
       void(const GURL& page_url,
            int desired_size_in_pixel,
            favicon_base::FaviconRawBitmapCallback callback,
            favicon::FaviconRequestPlatform request_platform,
            favicon::HistoryUiFaviconRequestOrigin request_origin_for_uma,
-           const GURL& icon_url_for_uma,
-           base::CancelableTaskTracker* tracker));
+           const GURL& icon_url_for_uma));
 
-  MOCK_METHOD5(
+  MOCK_METHOD4(
       GetFaviconImageForPageURL,
       void(const GURL& page_url,
            favicon_base::FaviconImageCallback callback,
            favicon::HistoryUiFaviconRequestOrigin request_origin_for_uma,
-           const GURL& icon_url_for_uma,
-           base::CancelableTaskTracker* tracker));
+           const GURL& icon_url_for_uma));
 };
 
 class TestFaviconSource : public FaviconSource {
@@ -124,10 +122,10 @@
           return kDummyTaskId;
         });
     ON_CALL(*mock_history_ui_favicon_request_handler_,
-            GetRawFaviconForPageURL(_, _, _, _, _, _, _))
+            GetRawFaviconForPageURL(_, _, _, _, _, _))
         .WillByDefault([](auto, auto,
                           favicon_base::FaviconRawBitmapCallback callback, auto,
-                          auto, auto, auto) {
+                          auto, auto) {
           std::move(callback).Run(favicon_base::FaviconRawBitmapResult());
         });
 
@@ -248,7 +246,7 @@
 
   EXPECT_CALL(
       *mock_history_ui_favicon_request_handler_,
-      GetRawFaviconForPageURL(GURL("https://www.google.com"), _, _, _, _, _, _))
+      GetRawFaviconForPageURL(GURL("https://www.google.com"), _, _, _, _, _))
       .Times(1);
 
   source()->StartDataRequest(
diff --git a/chrome/browser/ui/webui/interventions_internals/BUILD.gn b/chrome/browser/ui/webui/interventions_internals/BUILD.gn
index 424c3a9..cf7280f5 100644
--- a/chrome/browser/ui/webui/interventions_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/interventions_internals/BUILD.gn
@@ -5,11 +5,7 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("mojo_bindings") {
-  sources = [
-    "interventions_internals.mojom",
-  ]
+  sources = [ "interventions_internals.mojom" ]
 
-  public_deps = [
-    "//url/mojom:url_mojom_gurl",
-  ]
+  public_deps = [ "//url/mojom:url_mojom_gurl" ]
 }
diff --git a/chrome/browser/ui/webui/new_tab_page/BUILD.gn b/chrome/browser/ui/webui/new_tab_page/BUILD.gn
index a7f3d9d..e618c3e 100644
--- a/chrome/browser/ui/webui/new_tab_page/BUILD.gn
+++ b/chrome/browser/ui/webui/new_tab_page/BUILD.gn
@@ -5,9 +5,7 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("mojo_bindings") {
-  sources = [
-    "new_tab_page.mojom",
-  ]
+  sources = [ "new_tab_page.mojom" ]
 
   public_deps = [
     "//mojo/public/mojom/base",
diff --git a/chrome/browser/ui/webui/snippets_internals/BUILD.gn b/chrome/browser/ui/webui/snippets_internals/BUILD.gn
index f83f5c2..8981f583 100644
--- a/chrome/browser/ui/webui/snippets_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/snippets_internals/BUILD.gn
@@ -5,7 +5,5 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("mojo_bindings") {
-  sources = [
-    "snippets_internals.mojom",
-  ]
+  sources = [ "snippets_internals.mojom" ]
 }
diff --git a/chrome/chrome_elf/BUILD.gn b/chrome/chrome_elf/BUILD.gn
index 99ef456..abd8ceba 100644
--- a/chrome/chrome_elf/BUILD.gn
+++ b/chrome/chrome_elf/BUILD.gn
@@ -15,25 +15,19 @@
 ##------------------------------------------------------------------------------
 
 process_version_rc_template("chrome_elf_resources") {
-  sources = [
-    "chrome_elf.ver",
-  ]
+  sources = [ "chrome_elf.ver" ]
   output = "$target_gen_dir/chrome_elf_version.rc"
 }
 
 # This manifest matches what GYP produces. It may not even be necessary.
 windows_manifest("chrome_elf_manifest") {
-  sources = [
-    as_invoker_manifest,
-  ]
+  sources = [ as_invoker_manifest ]
 }
 
 # Users of chrome_elf exports can depend on this target, which doesn't
 # pin them to linking either chrome_elf.dll or test_stubs.
 source_set("chrome_elf_main_include") {
-  sources = [
-    "chrome_elf_main.h",
-  ]
+  sources = [ "chrome_elf_main.h" ]
 }
 
 # For code that isn't Chrome-the browser, like test binaries, these stubs stand
@@ -130,9 +124,7 @@
 }
 
 source_set("dll_hash") {
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
   sources = [
     "dll_hash/dll_hash.cc",
     "dll_hash/dll_hash.h",
@@ -140,9 +132,7 @@
 }
 
 executable("dll_hash_main") {
-  sources = [
-    "dll_hash/dll_hash_main.cc",
-  ]
+  sources = [ "dll_hash/dll_hash_main.cc" ]
   deps = [
     ":dll_hash",
     "//build/win:default_exe_manifest",
@@ -159,9 +149,7 @@
     ":nt_registry",  # utils
     "//base:base_static",  # pe_image
   ]
-  public_deps = [
-    "//sandbox",
-  ]
+  public_deps = [ "//sandbox" ]
 }
 
 # This target contains utility functions which must only depend on
@@ -315,9 +303,7 @@
 
 shared_library("main_unittest_dll_1") {
   testonly = true
-  sources = [
-    "third_party_dlls/main_unittest_dll_1.cc",
-  ]
+  sources = [ "third_party_dlls/main_unittest_dll_1.cc" ]
 
   # Disable sanitizer instrumentation in the test DLLs to avoid unwanted
   # exports.
diff --git a/chrome/chrome_elf/chrome_elf_main.cc b/chrome/chrome_elf/chrome_elf_main.cc
index aedbb30..f1ca45a 100644
--- a/chrome/chrome_elf/chrome_elf_main.cc
+++ b/chrome/chrome_elf/chrome_elf_main.cc
@@ -15,9 +15,10 @@
 #include "chrome/install_static/product_install_details.h"
 #include "chrome/install_static/user_data_dir.h"
 
-// This function is a temporary workaround for https://crbug.com/655788. We
-// need to come up with a better way to initialize crash reporting that can
-// happen inside DllMain().
+// This function is exported from the DLL so that it can be called by WinMain
+// after startup has completed in the browser process. For non-browser processes
+// it will be called inside the DLL loader lock so it should do as little as
+// possible to prevent deadlocks.
 void SignalInitializeCrashReporting() {
   if (!elf_crash::InitializeCrashReporting()) {
 #ifdef _DEBUG
@@ -59,24 +60,23 @@
 BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
   if (reason == DLL_PROCESS_ATTACH) {
     install_static::InitializeProductDetailsForPrimaryModule();
-
-    // CRT on initialization installs an exception filter which calls
-    // TerminateProcess. We need to hook CRT's attempt to set an exception.
-    elf_crash::DisableSetUnhandledExceptionFilter();
-
     install_static::InitializeProcessType();
 
-    // If this is not the browser process, all done.
-    if (install_static::IsNonBrowserProcess())
-      return TRUE;
-
-    __try {
-      // Initialize the blocking of third-party DLLs if the initialization of
-      // the safety beacon succeeds.
-      if (third_party_dlls::LeaveSetupBeacon())
-        third_party_dlls::Init();
-    } __except (elf_crash::GenerateCrashDump(GetExceptionInformation())) {
+    if (!install_static::IsNonBrowserProcess()) {
+      __try {
+        // Initialize the blocking of third-party DLLs if the initialization of
+        // the safety beacon succeeds.
+        if (third_party_dlls::LeaveSetupBeacon())
+          third_party_dlls::Init();
+      } __except (elf_crash::GenerateCrashDump(GetExceptionInformation())) {
+      }
+    } else if (!install_static::IsCrashpadHandlerProcess()) {
+      SignalInitializeCrashReporting();
+      // CRT on initialization installs an exception filter which calls
+      // TerminateProcess. We need to hook CRT's attempt to set an exception.
+      elf_crash::DisableSetUnhandledExceptionFilter();
     }
+
   } else if (reason == DLL_PROCESS_DETACH) {
     elf_crash::ShutdownCrashReporting();
   }
diff --git a/chrome/chrome_elf/crash/crash_helper.cc b/chrome/chrome_elf/crash/crash_helper.cc
index 381322a..a02aa37 100644
--- a/chrome/chrome_elf/crash/crash_helper.cc
+++ b/chrome/chrome_elf/crash/crash_helper.cc
@@ -64,6 +64,9 @@
 // NOTE: This function will be called from DllMain during DLL_PROCESS_ATTACH
 // (while we have the loader lock), so do not misbehave.
 bool InitializeCrashReporting() {
+  if (g_crash_helper_enabled)
+    return true;
+
 #ifdef _DEBUG
   assert(g_crash_reports == nullptr);
   assert(g_set_unhandled_exception_filter == nullptr);
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 39864fc..a979974 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -33,6 +33,13 @@
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(OS_CHROMEOS)
+// Enables app activity reporting for child user.
+// Requires |kPerAppTimeLimits| to be enabled.
+const base::Feature kAppActivityReporting{"AppActivityReporting",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
 #if defined(OS_MACOSX)
 // Enable the new multi-profile-aware app shim mode.
 // TODO(https://crbug.com/982024): Delete this flag when feature is complete.
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 90741b5..b3133c2 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -34,7 +34,12 @@
 #if defined(OS_CHROMEOS)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kApkWebAppInstalls;
-#endif  // defined(OS_CHROMEOS)
+#endif
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAppActivityReporting;
+#endif
 
 #if defined(OS_MACOSX)
 COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/common/extensions/BUILD.gn b/chrome/common/extensions/BUILD.gn
index 7cefd88..2460787 100644
--- a/chrome/common/extensions/BUILD.gn
+++ b/chrome/common/extensions/BUILD.gn
@@ -17,7 +17,5 @@
 }
 
 group("test_features") {
-  public_deps = [
-    ":extension_features_unittest",
-  ]
+  public_deps = [ ":extension_features_unittest" ]
 }
diff --git a/chrome/common/extensions/api/BUILD.gn b/chrome/common/extensions/api/BUILD.gn
index 87b6f10..c8761d1 100644
--- a/chrome/common/extensions/api/BUILD.gn
+++ b/chrome/common/extensions/api/BUILD.gn
@@ -66,9 +66,7 @@
   }
 
   root_namespace = chrome_extensions_api_root_namespace
-  deps = [
-    "//extensions/common/api",
-  ]
+  deps = [ "//extensions/common/api" ]
 
   visibility = [ ":api" ]
 }
@@ -79,9 +77,7 @@
   schema_include_rules = chrome_extensions_api_schema_include_rules
 
   root_namespace = chrome_extensions_api_root_namespace
-  deps = [
-    "//extensions/common/api",
-  ]
+  deps = [ "//extensions/common/api" ]
 
   visibility = [ ":api" ]
 }
@@ -89,26 +85,20 @@
 json_features("api_features") {
   feature_type = "APIFeature"
   method_name = "AddChromeAPIFeatures"
-  sources = [
-    "_api_features.json",
-  ]
+  sources = [ "_api_features.json" ]
   visibility = [ ":extensions_features" ]
 }
 
 json_features("permission_features") {
   feature_type = "PermissionFeature"
   method_name = "AddChromePermissionFeatures"
-  sources = [
-    "_permission_features.json",
-  ]
+  sources = [ "_permission_features.json" ]
   visibility = [ ":extensions_features" ]
 }
 
 json_features("manifest_features") {
   feature_type = "ManifestFeature"
   method_name = "AddChromeManifestFeatures"
-  sources = [
-    "_manifest_features.json",
-  ]
+  sources = [ "_manifest_features.json" ]
   visibility = [ ":extensions_features" ]
 }
diff --git a/chrome/common/importer/BUILD.gn b/chrome/common/importer/BUILD.gn
index 9dffb6e..6be16e69 100644
--- a/chrome/common/importer/BUILD.gn
+++ b/chrome/common/importer/BUILD.gn
@@ -5,9 +5,7 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("interfaces") {
-  sources = [
-    "profile_import.mojom",
-  ]
+  sources = [ "profile_import.mojom" ]
 
   public_deps = [
     "//components/autofill/core/common/mojom:mojo_types",
diff --git a/chrome/common/media_router/BUILD.gn b/chrome/common/media_router/BUILD.gn
index 2f25323..1606ee15 100644
--- a/chrome/common/media_router/BUILD.gn
+++ b/chrome/common/media_router/BUILD.gn
@@ -53,9 +53,7 @@
     "//base",
     "//chrome/test:test_support",
   ]
-  public_deps = [
-    ":router",
-  ]
+  public_deps = [ ":router" ]
   sources = [
     "test/test_helper.cc",
     "test/test_helper.h",
diff --git a/chrome/common/media_router/mojom/BUILD.gn b/chrome/common/media_router/mojom/BUILD.gn
index 3a43ecb8..7463f07 100644
--- a/chrome/common/media_router/mojom/BUILD.gn
+++ b/chrome/common/media_router/mojom/BUILD.gn
@@ -18,9 +18,7 @@
 }
 
 mojom("media_router") {
-  sources = [
-    "media_router.mojom",
-  ]
+  sources = [ "media_router.mojom" ]
 
   public_deps = [
     ":media_controller",
@@ -42,13 +40,9 @@
 }
 
 mojom("media_router_test_interfaces") {
-  sources = [
-    "media_router_traits_test_service.mojom",
-  ]
+  sources = [ "media_router_traits_test_service.mojom" ]
 
-  public_deps = [
-    ":media_router",
-  ]
+  public_deps = [ ":media_router" ]
 
   disable_variants = true
 }
diff --git a/chrome/credential_provider/BUILD.gn b/chrome/credential_provider/BUILD.gn
index d65efa9..d171a35 100644
--- a/chrome/credential_provider/BUILD.gn
+++ b/chrome/credential_provider/BUILD.gn
@@ -6,9 +6,7 @@
 action("gcp_installer") {
   script = "build/make_setup.py"
 
-  outputs = [
-    "$root_out_dir/gcp_installer.exe",
-  ]
+  outputs = [ "$root_out_dir/gcp_installer.exe" ]
 
   args = [
     rebase_path("//", root_build_dir),
@@ -26,7 +24,5 @@
 }
 
 group("credential_provider") {
-  deps = [
-    ":gcp_installer",
-  ]
+  deps = [ ":gcp_installer" ]
 }
diff --git a/chrome/credential_provider/common/BUILD.gn b/chrome/credential_provider/common/BUILD.gn
index 1c3689a..ae71a654 100644
--- a/chrome/credential_provider/common/BUILD.gn
+++ b/chrome/credential_provider/common/BUILD.gn
@@ -10,7 +10,5 @@
     "gcp_strings.cc",
     "gcp_strings.h",
   ]
-  deps = [
-    "//build:branding_buildflags",
-  ]
+  deps = [ "//build:branding_buildflags" ]
 }
diff --git a/chrome/credential_provider/eventlog/BUILD.gn b/chrome/credential_provider/eventlog/BUILD.gn
index 7b5f120..6ddc435 100644
--- a/chrome/credential_provider/eventlog/BUILD.gn
+++ b/chrome/credential_provider/eventlog/BUILD.gn
@@ -7,18 +7,14 @@
 import("//chrome/process_version_rc_template.gni")
 
 message_compiler("gcp_eventlog_messages") {
-  sources = [
-    "gcp_eventlog_messages.mc",
-  ]
+  sources = [ "gcp_eventlog_messages.mc" ]
 
   user_mode_logging = false
   compile_generated_code = false
 }
 
 process_version_rc_template("gcp_eventlog_provider_dll_version") {
-  sources = [
-    "gcp_eventlog_provider.ver",
-  ]
+  sources = [ "gcp_eventlog_provider.ver" ]
   output = "$target_gen_dir/gcp_eventlog_provider_dll_version.rc"
 }
 
diff --git a/chrome/credential_provider/gaiacp/BUILD.gn b/chrome/credential_provider/gaiacp/BUILD.gn
index 89f0947..85cef508 100644
--- a/chrome/credential_provider/gaiacp/BUILD.gn
+++ b/chrome/credential_provider/gaiacp/BUILD.gn
@@ -33,9 +33,7 @@
     "reg_utils.h",
   ]
   public_configs = [ ":common_config" ]
-  public_deps = [
-    "//chrome/credential_provider/common:common_constants",
-  ]
+  public_deps = [ "//chrome/credential_provider/common:common_constants" ]
   deps = [
     ":string_resources",
     "//base",
@@ -106,9 +104,7 @@
     "win_http_url_fetcher.h",
   ]
   public_configs = [ ":gaiacp_config" ]
-  public_deps = [
-    ":common",
-  ]
+  public_deps = [ ":common" ]
   deps = [
     ":gaia_credential_provider_idl",
     ":static_resources",
@@ -171,12 +167,8 @@
 action("generate_credential_provider_idl_file") {
   script = "//build/util/version.py"
 
-  inputs = [
-    "gaia_credential_provider_idl.templ",
-  ]
-  outputs = [
-    "$target_gen_dir/gaia_credential_provider.idl",
-  ]
+  inputs = [ "gaia_credential_provider_idl.templ" ]
+  outputs = [ "$target_gen_dir/gaia_credential_provider.idl" ]
 
   args = [
     "-e",
@@ -188,9 +180,7 @@
 
 midl("gaia_credential_provider_idl") {
   dynamic_guid = gaia_credential_provider_clsid
-  deps = [
-    ":generate_credential_provider_idl_file",
-  ]
+  deps = [ ":generate_credential_provider_idl_file" ]
   header_file = "gaia_credential_provider_i.h"
   sources = get_target_outputs(":generate_credential_provider_idl_file")
 }
@@ -247,7 +237,5 @@
 # Compile the generated .rc file.
 source_set("string_resources") {
   sources = get_target_outputs(":generate_strings")
-  public_deps = [
-    ":generate_strings",
-  ]
+  public_deps = [ ":generate_strings" ]
 }
diff --git a/chrome/credential_provider/setup/BUILD.gn b/chrome/credential_provider/setup/BUILD.gn
index 1bfacb7..182c87b 100644
--- a/chrome/credential_provider/setup/BUILD.gn
+++ b/chrome/credential_provider/setup/BUILD.gn
@@ -22,9 +22,7 @@
     "setup_lib.cc",
     "setup_lib.h",
   ]
-  public_deps = [
-    "//base",
-  ]
+  public_deps = [ "//base" ]
   deps = [
     "../gaiacp:common",
     "//chrome/installer/util:with_no_strings",
@@ -33,9 +31,7 @@
 
 grit("setup_resources") {
   source = "gcp_setup_resources.grd"
-  inputs = [
-    "gcp_icon.ico",
-  ]
+  inputs = [ "gcp_icon.ico" ]
   outputs = [
     "grit/gcp_setup_resources.h",
     "grit/gcp_setup_resources.rc",
diff --git a/chrome/install_static/BUILD.gn b/chrome/install_static/BUILD.gn
index 67301b6..8657632 100644
--- a/chrome/install_static/BUILD.gn
+++ b/chrome/install_static/BUILD.gn
@@ -17,9 +17,7 @@
     "//components/version_info:generate_version_info",
   ]
 
-  public_deps = [
-    "//chrome/chrome_elf:nt_registry",
-  ]
+  public_deps = [ "//chrome/chrome_elf:nt_registry" ]
 
   sources = [
     "../app/chrome_dll_resource.h",
@@ -62,9 +60,7 @@
 # A source set for use by the module in a process that creates the process-wide
 # InstallDetails instance (i.e., chrome_elf.dll).
 source_set("primary_module") {
-  sources = [
-    "get_install_details_payload.cc",
-  ]
+  sources = [ "get_install_details_payload.cc" ]
 }
 
 # A source set for use by modules in a process that fetch the process-wide
@@ -76,9 +72,7 @@
     "initialize_from_primary_module.cc",
     "initialize_from_primary_module.h",
   ]
-  deps = [
-    ":install_static_util",
-  ]
+  deps = [ ":install_static_util" ]
 }
 
 test("install_static_unittests") {
diff --git a/chrome/install_static/install_util.cc b/chrome/install_static/install_util.cc
index 07d4542..4238034 100644
--- a/chrome/install_static/install_util.cc
+++ b/chrome/install_static/install_util.cc
@@ -34,6 +34,7 @@
   NACL_BROKER_PROCESS,
   NACL_LOADER_PROCESS,
 #endif
+  CRASHPAD_HANDLER_PROCESS,
 };
 
 // Caches the |ProcessType| of the current process.
@@ -319,6 +320,8 @@
   if (process_type == kNaClLoaderProcess)
     return ProcessType::NACL_LOADER_PROCESS;
 #endif
+  if (process_type == kCrashpadHandler)
+    return ProcessType::CRASHPAD_HANDLER_PROCESS;
   return ProcessType::OTHER_PROCESS;
 }
 
@@ -337,6 +340,8 @@
       return true;
     case ProcessType::OTHER_PROCESS:
       return false;
+    case ProcessType::CRASHPAD_HANDLER_PROCESS:
+      return false;
     case ProcessType::UNINITIALIZED:
       assert(false);
       return false;
@@ -577,6 +582,11 @@
   return g_process_type != ProcessType::BROWSER_PROCESS;
 }
 
+bool IsCrashpadHandlerProcess() {
+  assert(g_process_type != ProcessType::UNINITIALIZED);
+  return g_process_type == ProcessType::CRASHPAD_HANDLER_PROCESS;
+}
+
 bool ProcessNeedsProfileDir(const std::string& process_type) {
   return ProcessNeedsProfileDir(GetProcessType(UTF8ToUTF16(process_type)));
 }
diff --git a/chrome/install_static/install_util.h b/chrome/install_static/install_util.h
index 27a55e3..f3610d31 100644
--- a/chrome/install_static/install_util.h
+++ b/chrome/install_static/install_util.h
@@ -201,6 +201,9 @@
 // process. False otherwise.
 bool IsNonBrowserProcess();
 
+// Returns true if invoked in a Crashpad handler process. False otherwise.
+bool IsCrashpadHandlerProcess();
+
 // Returns true if the |process_type| has the rights to access the profile.
 // False otherwise.
 bool ProcessNeedsProfileDir(const std::string& process_type);
diff --git a/chrome/notification_helper/BUILD.gn b/chrome/notification_helper/BUILD.gn
index 23ab536..aae3153 100644
--- a/chrome/notification_helper/BUILD.gn
+++ b/chrome/notification_helper/BUILD.gn
@@ -61,9 +61,7 @@
 }
 
 process_version_rc_template("version_resources") {
-  sources = [
-    "notification_helper_exe.ver",
-  ]
+  sources = [ "notification_helper_exe.ver" ]
   output = "$target_gen_dir/notification_helper_exe.rc"
 }
 
@@ -85,9 +83,7 @@
     "//testing/gtest",
   ]
 
-  data_deps = [
-    ":notification_helper",
-  ]
+  data_deps = [ ":notification_helper" ]
 
   libs = [ "runtimeobject.lib" ]
 }
diff --git a/chrome/service/OWNERS b/chrome/service/OWNERS
index 8c862b7..ed1bd3c 100644
--- a/chrome/service/OWNERS
+++ b/chrome/service/OWNERS
@@ -1,6 +1,6 @@
 file://cloud_print/OWNERS
 
-per-file service_utility_process_host_receiver_bindings.cc=set noparent
-per-file service_utility_process_host_receiver_bindings.cc=file://ipc/SECURITY_OWNERS
+per-file service_utility_process_host_receiver_bindings.*=set noparent
+per-file service_utility_process_host_receiver_bindings.*=file://ipc/SECURITY_OWNERS
 
 # COMPONENT: Services>CloudPrint
diff --git a/chrome/services/app_service/BUILD.gn b/chrome/services/app_service/BUILD.gn
index 6ed6ae8..d9363ca 100644
--- a/chrome/services/app_service/BUILD.gn
+++ b/chrome/services/app_service/BUILD.gn
@@ -23,9 +23,7 @@
 source_set("unit_tests") {
   testonly = true
 
-  sources = [
-    "app_service_impl_unittest.cc",
-  ]
+  sources = [ "app_service_impl_unittest.cc" ]
 
   deps = [
     ":lib",
diff --git a/chrome/services/app_service/public/cpp/BUILD.gn b/chrome/services/app_service/public/cpp/BUILD.gn
index 2f26d2c..28e4ddb 100644
--- a/chrome/services/app_service/public/cpp/BUILD.gn
+++ b/chrome/services/app_service/public/cpp/BUILD.gn
@@ -10,9 +10,7 @@
     "app_update.h",
   ]
 
-  public_deps = [
-    "//chrome/services/app_service/public/mojom",
-  ]
+  public_deps = [ "//chrome/services/app_service/public/mojom" ]
 }
 
 if (is_chromeos) {
@@ -44,9 +42,7 @@
     "icon_loader.h",
   ]
 
-  public_deps = [
-    "//chrome/services/app_service/public/mojom",
-  ]
+  public_deps = [ "//chrome/services/app_service/public/mojom" ]
 }
 
 source_set("icon_loader_test_support") {
@@ -55,9 +51,7 @@
     "stub_icon_loader.h",
   ]
 
-  deps = [
-    ":icon_loader",
-  ]
+  deps = [ ":icon_loader" ]
 }
 
 source_set("intents") {
diff --git a/chrome/services/app_service/public/mojom/BUILD.gn b/chrome/services/app_service/public/mojom/BUILD.gn
index 39e16e7..9f4c5fa 100644
--- a/chrome/services/app_service/public/mojom/BUILD.gn
+++ b/chrome/services/app_service/public/mojom/BUILD.gn
@@ -5,19 +5,13 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 
 mojom("mojom") {
-  sources = [
-    "app_service.mojom",
-  ]
+  sources = [ "app_service.mojom" ]
 
-  public_deps = [
-    ":types",
-  ]
+  public_deps = [ ":types" ]
 }
 
 mojom("types") {
-  sources = [
-    "types.mojom",
-  ]
+  sources = [ "types.mojom" ]
 
   public_deps = [
     "//mojo/public/mojom/base",
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 31d58e8..410e207 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3808,6 +3808,7 @@
       "../browser/download/download_shelf_unittest.cc",
       "../browser/enterprise_reporting/browser_report_generator_unittest.cc",
       "../browser/enterprise_reporting/extension_info_unittest.cc",
+      "../browser/enterprise_reporting/notification/extension_request_notification_unittest.cc",
       "../browser/enterprise_reporting/policy_info_unittest.cc",
       "../browser/enterprise_reporting/profile_report_generator_unittest.cc",
       "../browser/enterprise_reporting/report_generator_unittest.cc",
@@ -3863,6 +3864,7 @@
       "../browser/resource_coordinator/background_tab_navigation_throttle_unittest.cc",
       "../browser/resource_coordinator/decision_details_unittest.cc",
       "../browser/resource_coordinator/discard_metrics_lifecycle_unit_observer_unittest.cc",
+      "../browser/resource_coordinator/intervention_policy_database_unittest.cc",
       "../browser/resource_coordinator/leveldb_site_characteristics_database_unittest.cc",
       "../browser/resource_coordinator/lifecycle_unit_base_unittest.cc",
       "../browser/resource_coordinator/lifecycle_unit_unittest.cc",
diff --git a/chrome/test/base/js2gtest.gni b/chrome/test/base/js2gtest.gni
index 49fa1cb..f529d22 100644
--- a/chrome/test/base/js2gtest.gni
+++ b/chrome/test/base/js2gtest.gni
@@ -107,9 +107,7 @@
       rebase_path(copied_source_pattern, root_build_dir),
     ]
 
-    deps = [
-      "//v8:v8_shell($v8_snapshot_toolchain)",
-    ]
+    deps = [ "//v8:v8_shell($v8_snapshot_toolchain)" ]
     if (defined(invoker.deps)) {
       deps += invoker.deps
     }
@@ -120,9 +118,7 @@
     copy(copy_target_name) {
       visibility = [ ":$source_set_name" ]
       sources = invoker.extra_js_files
-      outputs = [
-        copied_source_pattern,
-      ]
+      outputs = [ copied_source_pattern ]
     }
   }
 
@@ -155,9 +151,7 @@
       data += invoker.gen_include_files
     }
     if (defined(invoker.extra_js_files)) {
-      data_deps = [
-        ":$copy_target_name",
-      ]
+      data_deps = [ ":$copy_target_name" ]
     }
   }
 }
diff --git a/chrome/test/data/autofill/captured_sites/testcases.json b/chrome/test/data/autofill/captured_sites/testcases.json
index 1e7bffa..53d295c 100644
--- a/chrome/test/data/autofill/captured_sites/testcases.json
+++ b/chrome/test/data/autofill/captured_sites/testcases.json
@@ -62,7 +62,7 @@
     { "site_name": "dicks_sporting_goods" },
     { "site_name": "dish" },
     { "site_name": "dsw" },
-    { "site_name": "duluthtrading" },
+    { "site_name": "duluthtrading", "disabled":true, "bug_number":1041744},
     { "site_name": "ebags" },
     { "site_name": "ebay", "disabled":true, "bug_number":984664 },
     { "site_name": "eddiebauer" },
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 529aa99..a4e6e4f 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3997,6 +3997,16 @@
     ]
   },
 
+  "AccessibilityShortcutsEnabled": {
+    "os": ["chromeos"],
+    "policy_pref_mapping_test": [
+      {
+        "policies": { "AccessibilityShortcutsEnabled": true },
+        "prefs": { "settings.a11y.shortcuts_enabled": {} }
+      }
+    ]
+  },
+
   "SelectToSpeakEnabled": {
     "os": ["chromeos"],
     "policy_pref_mapping_test": [
diff --git a/chrome/tools/build/mac/FILES.cfg b/chrome/tools/build/mac/FILES.cfg
index 2089a89..8f8abf2 100644
--- a/chrome/tools/build/mac/FILES.cfg
+++ b/chrome/tools/build/mac/FILES.cfg
@@ -129,4 +129,23 @@
     'buildtype': ['dev', 'official'],
     'archive': 'devtools-frontend.zip',
   },
+  # Updater files:
+  {
+    'filename': 'GoogleUpdate.app',
+    'buildtype': ['official'],
+    'archive': 'updater.zip',
+    'optional': ['official'], # TODO(crbug.com/1024318): Make non-optional.
+  },
+  {
+    'filename': 'updater_setup',
+    'buildtype': ['official'],
+    'archive': 'updater.zip',
+    'optional': ['official'], # TODO(crbug.com/1024318): Make non-optional.
+  },
+  {
+    'filename': 'chrome/updater/.install.sh',
+    'buildtype': ['official'],
+    'archive': 'updater.zip',
+    'optional': ['official'], # TODO(crbug.com/1024318): Make non-optional.
+  },
 ]
diff --git a/chromecast/browser/OWNERS b/chromecast/browser/OWNERS
index 63fa768..a1ef499 100644
--- a/chromecast/browser/OWNERS
+++ b/chromecast/browser/OWNERS
@@ -1,9 +1,7 @@
 seantopping@chromium.org
 
-per-file cast_overlay_manifests.h=set noparent
-per-file cast_overlay_manifests.h=file://ipc/SECURITY_OWNERS
-per-file cast_overlay_manifests.cc=set noparent
-per-file cast_overlay_manifests.cc=file://ipc/SECURITY_OWNERS
-per-file cast_content_browser_client_receiver_bindings.cc=set noparent
-per-file cast_content_browser_client_receiver_bindings.cc=file://ipc/SECURITY_OWNERS
+per-file cast_overlay_manifests.*=set noparent
+per-file cast_overlay_manifests.*=file://ipc/SECURITY_OWNERS
+per-file cast_content_browser_client_receiver_bindings.*=set noparent
+per-file cast_content_browser_client_receiver_bindings.*=file://ipc/SECURITY_OWNERS
 per-file service_connector.cc=file://ipc/SECURITY_OWNERS
diff --git a/chromecast/browser/android/BUILD.gn b/chromecast/browser/android/BUILD.gn
index 438abf0..9ba32b6c 100644
--- a/chromecast/browser/android/BUILD.gn
+++ b/chromecast/browser/android/BUILD.gn
@@ -25,9 +25,7 @@
 }
 
 java_cpp_template("cast_shell_build_config_gen") {
-  sources = [
-    "apk/templates/BuildConfig.template",
-  ]
+  sources = [ "apk/templates/BuildConfig.template" ]
   package_path = "org/chromium/chromecast/shell"
 
   defines = []
@@ -85,18 +83,15 @@
 
 android_library("cast_intents_java") {
   java_src_dir = "//chromecast/browser/android/apk/src"
-  sources = [
-    "$java_src_dir/org/chromium/chromecast/shell/CastIntents.java",
-  ]
+  sources = [ "$java_src_dir/org/chromium/chromecast/shell/CastIntents.java" ]
 }
 android_aidl("logs_provider_aidl") {
   java_src_dir = "//chromecast/browser/android/apk/src"
   interface_file =
       "$java_src_dir/org/chromium/chromecast/shell/logs_provider_service.aidl"
 
-  sources = [
-    "$java_src_dir/org/chromium/chromecast/shell/IDeviceLogsProvider.aidl",
-  ]
+  sources =
+      [ "$java_src_dir/org/chromium/chromecast/shell/IDeviceLogsProvider.aidl" ]
 }
 
 android_library("reactive_android_java") {
@@ -192,9 +187,7 @@
 
 if (is_android_things_non_public && !build_for_android_things_n) {
   android_library("cast_shell_android_things_sys_info_java") {
-    sources = [
-      "//chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastSysInfoAndroidThings.java",
-    ]
+    sources = [ "//chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastSysInfoAndroidThings.java" ]
     deps = [
       "//base:base_java",
       "//chromecast/internal/android/prebuilt/things:support_lib_java",
@@ -202,12 +195,8 @@
   }
 
   generate_jni("cast_shell_android_things_sys_info_jni_headers") {
-    sources = [
-      "//chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastSysInfoAndroidThings.java",
-    ]
-    deps = [
-      "//chromecast/internal/android/prebuilt/things:support_lib_java",
-    ]
+    sources = [ "//chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastSysInfoAndroidThings.java" ]
+    deps = [ "//chromecast/internal/android/prebuilt/things:support_lib_java" ]
   }
 }
 
diff --git a/chromecast/media/cma/backend/android/BUILD.gn b/chromecast/media/cma/backend/android/BUILD.gn
index a9fc4e2..731325c 100644
--- a/chromecast/media/cma/backend/android/BUILD.gn
+++ b/chromecast/media/cma/backend/android/BUILD.gn
@@ -79,16 +79,12 @@
 }
 
 test("cast_android_cma_backend_unittests") {
-  deps = [
-    ":unit_tests",
-  ]
+  deps = [ ":unit_tests" ]
 }
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "volume_cache_test.cc",
-  ]
+  sources = [ "volume_cache_test.cc" ]
 
   deps = [
     ":cast_media_android",
diff --git a/chromecast/renderer/BUILD.gn b/chromecast/renderer/BUILD.gn
index 59a9f18..4a7c427 100644
--- a/chromecast/renderer/BUILD.gn
+++ b/chromecast/renderer/BUILD.gn
@@ -44,9 +44,7 @@
     "queryable_data_store.h",
   ]
 
-  public_deps = [
-    "//chromecast/renderer/media",
-  ]
+  public_deps = [ "//chromecast/renderer/media" ]
 
   if (chromecast_branding == "public") {
     sources += [ "cast_content_renderer_client_simple.cc" ]
diff --git a/chromeos/components/help_app_ui/BUILD.gn b/chromeos/components/help_app_ui/BUILD.gn
index 7a1f3b4d..5601935 100644
--- a/chromeos/components/help_app_ui/BUILD.gn
+++ b/chromeos/components/help_app_ui/BUILD.gn
@@ -30,13 +30,9 @@
 js2gtest("browser_tests_js") {
   test_type = "mojo_lite_webui"
 
-  sources = [
-    "test/help_app_ui_browsertest.js",
-  ]
+  sources = [ "test/help_app_ui_browsertest.js" ]
 
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 
-  deps = [
-    "//chromeos/constants",
-  ]
+  deps = [ "//chromeos/constants" ]
 }
diff --git a/chromeos/dbus/shill/BUILD.gn b/chromeos/dbus/shill/BUILD.gn
index 459a179..8a3e32c 100644
--- a/chromeos/dbus/shill/BUILD.gn
+++ b/chromeos/dbus/shill/BUILD.gn
@@ -61,9 +61,7 @@
 
 source_set("test_support") {
   testonly = true
-  public_deps = [
-    ":shill",
-  ]
+  public_deps = [ ":shill" ]
   deps = [
     "//base",
     "//base/test:test_support",
diff --git a/cloud_print/BUILD.gn b/cloud_print/BUILD.gn
index 0c554c8..6f855cba 100644
--- a/cloud_print/BUILD.gn
+++ b/cloud_print/BUILD.gn
@@ -25,9 +25,7 @@
 }
 
 test("cloud_print_unittests") {
-  sources = [
-    "virtual_driver/win/port_monitor/port_monitor_unittest.cc",
-  ]
+  sources = [ "virtual_driver/win/port_monitor/port_monitor_unittest.cc" ]
 
   deps = [
     "//base",
diff --git a/cloud_print/common/BUILD.gn b/cloud_print/common/BUILD.gn
index ca0b546d..258cc4e 100644
--- a/cloud_print/common/BUILD.gn
+++ b/cloud_print/common/BUILD.gn
@@ -8,9 +8,7 @@
     "win/cloud_print_utils.h",
   ]
 
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
 }
 
 source_set("install_utils") {
diff --git a/cloud_print/virtual_driver/win/install/BUILD.gn b/cloud_print/virtual_driver/win/install/BUILD.gn
index 4d25527..3359f20 100644
--- a/cloud_print/virtual_driver/win/install/BUILD.gn
+++ b/cloud_print/virtual_driver/win/install/BUILD.gn
@@ -8,9 +8,7 @@
 assert(is_win)
 
 executable("virtual_driver_setup") {
-  sources = [
-    "setup.cc",
-  ]
+  sources = [ "setup.cc" ]
 
   configs -= [ "//build/config/win:console" ]
   configs += [ "//build/config/win:windowed" ]
@@ -31,27 +29,17 @@
 }
 
 copy("copy_gcp_driver_gpd") {
-  sources = [
-    "inf/gcp_driver.gpd",
-  ]
-  outputs = [
-    "$root_build_dir/gcp_driver.gpd",
-  ]
+  sources = [ "inf/gcp_driver.gpd" ]
+  outputs = [ "$root_build_dir/gcp_driver.gpd" ]
 }
 
 copy("copy_gcp_driver_inf") {
-  sources = [
-    "inf/gcp_driver.inf",
-  ]
-  outputs = [
-    "$root_build_dir/gcp_driver.inf",
-  ]
+  sources = [ "inf/gcp_driver.inf" ]
+  outputs = [ "$root_build_dir/gcp_driver.inf" ]
 }
 
 process_version_rc_template("setup_version") {
-  sources = [
-    "virtual_driver_setup_exe.ver",
-  ]
+  sources = [ "virtual_driver_setup_exe.ver" ]
   output = "$target_gen_dir/virtual_driver_setup.rc"
 }
 
diff --git a/cloud_print/virtual_driver/win/port_monitor/BUILD.gn b/cloud_print/virtual_driver/win/port_monitor/BUILD.gn
index 42fa30c..cf9bdb9 100644
--- a/cloud_print/virtual_driver/win/port_monitor/BUILD.gn
+++ b/cloud_print/virtual_driver/win/port_monitor/BUILD.gn
@@ -8,9 +8,7 @@
 assert(is_win)
 
 group("port_monitor") {
-  public_deps = [
-    ":port_monitor_dll",
-  ]
+  public_deps = [ ":port_monitor_dll" ]
 }
 
 shared_library("port_monitor_dll") {
@@ -38,9 +36,7 @@
 }
 
 group("copy_gcp_portmon_binaries") {
-  deps = [
-    ":copy_gcp_portmon_dll",
-  ]
+  deps = [ ":copy_gcp_portmon_dll" ]
   # TODO(pastarmovj): Find some way to reference the pdb file for the 64bit dll
   # simply using it in the sources directive causes gn to error when generating
   # the build files.
@@ -48,15 +44,9 @@
 
 if (current_cpu == "x64") {
   copy("copy_gcp_portmon_dll") {
-    sources = [
-      "$root_out_dir/gcp_portmon64.dll",
-    ]
-    outputs = [
-      "$root_out_dir/gcp_portmon.dll",
-    ]
-    deps = [
-      ":port_monitor_dll",
-    ]
+    sources = [ "$root_out_dir/gcp_portmon64.dll" ]
+    outputs = [ "$root_out_dir/gcp_portmon.dll" ]
+    deps = [ ":port_monitor_dll" ]
   }
 } else {
   # Make sure that we have a copy of gcp_portmon64.dll in the root out
@@ -73,27 +63,15 @@
   if (symbol_level > 0) {
     copy("copy_gcp_portmon_pdb") {
       visibility = [ ":copy_gcp_portmon_dll" ]
-      sources = [
-        "$gcp_portmon64_out_dir/gcp_portmon64.dll.pdb",
-      ]
-      outputs = [
-        "$root_out_dir/{{source_file_part}}",
-      ]
-      deps = [
-        gcp_portmon64_label,
-      ]
+      sources = [ "$gcp_portmon64_out_dir/gcp_portmon64.dll.pdb" ]
+      outputs = [ "$root_out_dir/{{source_file_part}}" ]
+      deps = [ gcp_portmon64_label ]
     }
   }
   copy("copy_gcp_portmon_dll") {
-    sources = [
-      "$gcp_portmon64_out_dir/gcp_portmon64.dll",
-    ]
-    outputs = [
-      "$root_out_dir/{{source_file_part}}",
-    ]
-    deps = [
-      gcp_portmon64_label,
-    ]
+    sources = [ "$gcp_portmon64_out_dir/gcp_portmon64.dll" ]
+    outputs = [ "$root_out_dir/{{source_file_part}}" ]
+    deps = [ gcp_portmon64_label ]
     if (symbol_level > 0) {
       deps += [ ":copy_gcp_portmon_pdb" ]
     }
@@ -116,9 +94,7 @@
 }
 
 process_version_rc_template("resources") {
-  sources = [
-    "../gcp_portmon_dll.ver",
-  ]
+  sources = [ "../gcp_portmon_dll.ver" ]
 
   # Note: target_gen_dir will be different for each toolchain so the output
   # name doesn't need mangling.
diff --git a/components/android_system_error_page/BUILD.gn b/components/android_system_error_page/BUILD.gn
new file mode 100644
index 0000000..a623df7
--- /dev/null
+++ b/components/android_system_error_page/BUILD.gn
@@ -0,0 +1,30 @@
+# 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.
+
+assert(is_android)
+
+static_library("android_system_error_page") {
+  sources = [
+    "error_page_populator.cc",
+    "error_page_populator.h",
+  ]
+
+  configs += [
+    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+    "//build/config/compiler:no_size_t_to_int_warning",
+
+    "//build/config/compiler:noshadowing",
+  ]
+
+  deps = [
+    "//base",
+    "//base:i18n",
+    "//components/resources",
+    "//components/strings",
+    "//net",
+    "//third_party/blink/public:blink",
+    "//ui/base",
+    "//url",
+  ]
+}
diff --git a/components/android_system_error_page/DEPS b/components/android_system_error_page/DEPS
new file mode 100644
index 0000000..d3786b0
--- /dev/null
+++ b/components/android_system_error_page/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+  "+components/grit",
+  "+components/strings",
+  "+net",
+  "+third_party/blink/public",
+  "+ui/base",
+]
diff --git a/components/android_system_error_page/README.md b/components/android_system_error_page/README.md
index 2211ed5..259a5f7 100644
--- a/components/android_system_error_page/README.md
+++ b/components/android_system_error_page/README.md
@@ -1,2 +1,2 @@
 Contains code and resources for displaying network error pages using an Android
-system style.
+system style. The C++ code is intended to be used from the renderer process.
diff --git a/components/android_system_error_page/error_page_populator.cc b/components/android_system_error_page/error_page_populator.cc
new file mode 100644
index 0000000..077a788
--- /dev/null
+++ b/components/android_system_error_page/error_page_populator.cc
@@ -0,0 +1,70 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/android_system_error_page/error_page_populator.h"
+
+#include "base/i18n/rtl.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/grit/components_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "net/base/escape.h"
+#include "net/base/net_errors.h"
+#include "third_party/blink/public/platform/web_url_error.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "url/gurl.h"
+
+namespace android_system_error_page {
+
+namespace {
+constexpr char kThrottledErrorDescription[] =
+    "Request throttled. Visit http://dev.chromium.org/throttling for more "
+    "information.";
+}  // namespace
+
+void PopulateErrorPageHtml(const blink::WebURLError& error,
+                           std::string* error_html) {
+  std::string err;
+  if (error.reason() == net::ERR_TEMPORARILY_THROTTLED)
+    err = kThrottledErrorDescription;
+  else
+    err = net::ErrorToString(error.reason());
+
+  if (!error_html)
+    return;
+
+  // Create the error page based on the error reason.
+  GURL gurl(error.url());
+  std::string url_string = gurl.possibly_invalid_spec();
+  int reason_id = IDS_ANDROID_ERROR_PAGE_WEBPAGE_CAN_NOT_BE_LOADED;
+
+  if (err.empty())
+    reason_id = IDS_ANDROID_ERROR_PAGE_WEBPAGE_TEMPORARILY_DOWN;
+
+  std::string escaped_url = net::EscapeForHTML(url_string);
+  std::vector<std::string> replacements;
+  replacements.push_back(
+      l10n_util::GetStringUTF8(IDS_ANDROID_ERROR_PAGE_WEBPAGE_NOT_AVAILABLE));
+  replacements.push_back(
+      l10n_util::GetStringFUTF8(reason_id, base::UTF8ToUTF16(escaped_url)));
+
+  // Having chosen the base reason, chose what extra information to add.
+  if (reason_id == IDS_ANDROID_ERROR_PAGE_WEBPAGE_TEMPORARILY_DOWN) {
+    replacements.push_back(l10n_util::GetStringUTF8(
+        IDS_ANDROID_ERROR_PAGE_WEBPAGE_TEMPORARILY_DOWN_SUGGESTIONS));
+  } else {
+    replacements.push_back(err);
+  }
+  if (base::i18n::IsRTL())
+    replacements.push_back("direction: rtl;");
+  else
+    replacements.push_back("");
+  *error_html = base::ReplaceStringPlaceholders(
+      ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+          IDR_ANDROID_ERROR_PAGE_LOAD_ERROR_HTML),
+      replacements, nullptr);
+}
+
+}  // namespace android_system_error_page
diff --git a/components/android_system_error_page/error_page_populator.h b/components/android_system_error_page/error_page_populator.h
new file mode 100644
index 0000000..e1b017e
--- /dev/null
+++ b/components/android_system_error_page/error_page_populator.h
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ANDROID_SYSTEM_ERROR_PAGE_ERROR_PAGE_POPULATOR_H_
+#define COMPONENTS_ANDROID_SYSTEM_ERROR_PAGE_ERROR_PAGE_POPULATOR_H_
+
+#include <string>
+
+namespace blink {
+struct WebURLError;
+}
+
+namespace android_system_error_page {
+
+// Populates |error_html| to display an error page with an Android system feel
+// for |error|.
+void PopulateErrorPageHtml(const blink::WebURLError& error,
+                           std::string* error_html);
+
+}  // namespace android_system_error_page
+
+#endif  // COMPONENTS_ANDROID_SYSTEM_ERROR_PAGE_ERROR_PAGE_POPULATOR_H_
diff --git a/components/autofill/android/autofill_provider_android.cc b/components/autofill/android/autofill_provider_android.cc
index 238de06..1a6f12c 100644
--- a/components/autofill/android/autofill_provider_android.cc
+++ b/components/autofill/android/autofill_provider_android.cc
@@ -34,10 +34,27 @@
     const JavaRef<jobject>& jcaller,
     content::WebContents* web_contents)
     : id_(kNoQueryId), web_contents_(web_contents), check_submission_(false) {
-  JNIEnv* env = AttachCurrentThread();
+  OnJavaAutofillProviderChanged(AttachCurrentThread(), jcaller);
+}
+
+void AutofillProviderAndroid::OnJavaAutofillProviderChanged(
+    JNIEnv* env,
+    const JavaRef<jobject>& jcaller) {
+  // If the current Java object isn't null (e.g., because it hasn't been
+  // garbage-collected yet), clear its reference to this object.
+  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+  if (!obj.is_null()) {
+    Java_AutofillProvider_setNativeAutofillProvider(env, obj, 0);
+  }
+
   java_ref_ = JavaObjectWeakGlobalRef(env, jcaller);
-  Java_AutofillProvider_setNativeAutofillProvider(
-      env, jcaller, reinterpret_cast<jlong>(this));
+
+  // If the new Java object isn't null, set its native object to |this|.
+  obj = java_ref_.get(env);
+  if (!obj.is_null()) {
+    Java_AutofillProvider_setNativeAutofillProvider(
+        env, obj, reinterpret_cast<jlong>(this));
+  }
 }
 
 AutofillProviderAndroid::~AutofillProviderAndroid() {
diff --git a/components/autofill/android/autofill_provider_android.h b/components/autofill/android/autofill_provider_android.h
index d99e491..270a05ee 100644
--- a/components/autofill/android/autofill_provider_android.h
+++ b/components/autofill/android/autofill_provider_android.h
@@ -23,6 +23,12 @@
  public:
   AutofillProviderAndroid(const base::android::JavaRef<jobject>& jcaller,
                           content::WebContents* web_contents);
+  // Invoked when the Java-side AutofillProvider counterpart of this object
+  // has been changed (either to null or to a new object).
+  void OnJavaAutofillProviderChanged(
+      JNIEnv* env,
+      const base::android::JavaRef<jobject>& jcaller);
+
   ~AutofillProviderAndroid() override;
 
   // AutofillProvider:
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index 178f307..2868f4b 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -212,6 +212,12 @@
       base::OnceCallback<void(const ClientStatus&, const std::string&)>
           callback) = 0;
 
+  // Return the tag of the element given by |selector|.
+  virtual void GetElementTag(
+      const Selector& selector,
+      base::OnceCallback<void(const ClientStatus&, const std::string&)>
+          callback) = 0;
+
   // Make the next call to WaitForNavigation to expect a navigation event that
   // started after this call.
   virtual void ExpectNavigation() = 0;
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h
index 85132a41..843d4e8 100644
--- a/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -193,6 +193,12 @@
                void(const Selector& selector,
                     base::OnceCallback<void(const ClientStatus&,
                                             const std::string&)> callback));
+
+  MOCK_METHOD2(GetElementTag,
+               void(const Selector& selector,
+                    base::OnceCallback<void(const ClientStatus&,
+                                            const std::string&)> callback));
+
   MOCK_METHOD0(ExpectNavigation, void());
   MOCK_METHOD0(ExpectedNavigationHasStarted, bool());
   MOCK_METHOD1(WaitForNavigation,
diff --git a/components/autofill_assistant/browser/actions/required_fields_fallback_handler.cc b/components/autofill_assistant/browser/actions/required_fields_fallback_handler.cc
index 6c2b1a77..cd91b4f 100644
--- a/components/autofill_assistant/browser/actions/required_fields_fallback_handler.cc
+++ b/components/autofill_assistant/browser/actions/required_fields_fallback_handler.cc
@@ -159,6 +159,21 @@
 
   // Set the next field to its fallback value.
   const RequiredField& required_field = required_fields_[required_fields_index];
+  DVLOG(3) << "Getting element tag for " << required_field.selector;
+  action_delegate_->GetElementTag(
+      required_field.selector,
+      base::BindOnce(&RequiredFieldsFallbackHandler::OnGetFallbackFieldTag,
+                     weak_ptr_factory_.GetWeakPtr(), required_fields_index,
+                     std::move(fallback_data)));
+}
+
+void RequiredFieldsFallbackHandler::OnGetFallbackFieldTag(
+    size_t required_fields_index,
+    std::unique_ptr<FallbackData> fallback_data,
+    const ClientStatus& element_tag_status,
+    const std::string& element_tag) {
+  // Set the next field to its fallback value.
+  const RequiredField& required_field = required_fields_[required_fields_index];
   auto fallback_value = fallback_data->GetValue(required_field.fallback_key);
   if (!fallback_value.has_value()) {
     DVLOG(3) << "No fallback for " << required_field.selector;
@@ -168,12 +183,21 @@
   }
 
   DVLOG(3) << "Setting fallback value for " << required_field.selector;
-  action_delegate_->SetFieldValue(
-      required_field.selector, fallback_value.value(),
-      required_field.simulate_key_presses, required_field.delay_in_millisecond,
-      base::BindOnce(&RequiredFieldsFallbackHandler::OnSetFallbackFieldValue,
-                     weak_ptr_factory_.GetWeakPtr(), required_fields_index,
-                     std::move(fallback_data)));
+  if (element_tag == "SELECT") {
+    action_delegate_->SelectOption(
+        required_field.selector, fallback_value.value(),
+        base::BindOnce(&RequiredFieldsFallbackHandler::OnSetFallbackFieldValue,
+                       weak_ptr_factory_.GetWeakPtr(), required_fields_index,
+                       std::move(fallback_data)));
+  } else {
+    action_delegate_->SetFieldValue(
+        required_field.selector, fallback_value.value(),
+        required_field.simulate_key_presses,
+        required_field.delay_in_millisecond,
+        base::BindOnce(&RequiredFieldsFallbackHandler::OnSetFallbackFieldValue,
+                       weak_ptr_factory_.GetWeakPtr(), required_fields_index,
+                       std::move(fallback_data)));
+  }
 }
 
 void RequiredFieldsFallbackHandler::OnSetFallbackFieldValue(
diff --git a/components/autofill_assistant/browser/actions/required_fields_fallback_handler.h b/components/autofill_assistant/browser/actions/required_fields_fallback_handler.h
index bd9703e3..e071559 100644
--- a/components/autofill_assistant/browser/actions/required_fields_fallback_handler.h
+++ b/components/autofill_assistant/browser/actions/required_fields_fallback_handler.h
@@ -100,6 +100,12 @@
       size_t required_fields_index,
       std::unique_ptr<FallbackData> fallback_data);
 
+  // Called after retrieving tag name from a field.
+  void OnGetFallbackFieldTag(size_t required_fields_index,
+                             std::unique_ptr<FallbackData> fallback_data,
+                             const ClientStatus& element_tag_status,
+                             const std::string& element_tag);
+
   // Called after trying to set form values without Autofill in case of fallback
   // after failed validation.
   void OnSetFallbackFieldValue(size_t required_fields_index,
diff --git a/components/autofill_assistant/browser/actions/use_address_action_unittest.cc b/components/autofill_assistant/browser/actions/use_address_action_unittest.cc
index 00de823..3bd6f8e 100644
--- a/components/autofill_assistant/browser/actions/use_address_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/use_address_action_unittest.cc
@@ -201,7 +201,8 @@
 }
 
 TEST_F(UseAddressActionTest, FallbackFails) {
-  InSequence seq;
+  ON_CALL(mock_action_delegate_, GetElementTag(_, _))
+      .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
 
   ActionProto action_proto = CreateUseAddressAction();
   AddRequiredField(&action_proto, UseAddressProto::RequiredField::FIRST_NAME,
@@ -238,7 +239,8 @@
 }
 
 TEST_F(UseAddressActionTest, FallbackSucceeds) {
-  InSequence seq;
+  ON_CALL(mock_action_delegate_, GetElementTag(_, _))
+      .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
 
   ActionProto action_proto = CreateUseAddressAction();
   AddRequiredField(&action_proto, UseAddressProto::RequiredField::FIRST_NAME,
@@ -254,29 +256,28 @@
                   NotNull(), Eq(Selector({kFakeSelector}).MustBeVisible()), _))
       .WillOnce(RunOnceCallback<2>(OkClientStatus()));
 
-  {
-    InSequence seq;
+  // Validation fails when getting FIRST_NAME.
+  EXPECT_CALL(mock_web_controller_,
+              OnGetFieldValue(Eq(Selector({"#email"})), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetFieldValue(Eq(Selector({"#first_name"})), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetFieldValue(Eq(Selector({"#last_name"})), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
 
-    // Validation fails when getting FIRST_NAME.
-    EXPECT_CALL(mock_web_controller_,
-                OnGetFieldValue(Eq(Selector({"#email"})), _))
-        .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
-    EXPECT_CALL(mock_web_controller_,
-                OnGetFieldValue(Eq(Selector({"#first_name"})), _))
-        .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
-    EXPECT_CALL(mock_web_controller_,
-                OnGetFieldValue(Eq(Selector({"#last_name"})), _))
-        .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
+  // Fallback succeeds.
+  Expectation set_first_name =
+      EXPECT_CALL(mock_action_delegate_,
+                  OnSetFieldValue(Eq(Selector({"#first_name"})), kFirstName, _))
+          .WillOnce(RunOnceCallback<2>(OkClientStatus()));
 
-    // Fallback succeeds.
-    EXPECT_CALL(mock_action_delegate_,
-                OnSetFieldValue(Eq(Selector({"#first_name"})), kFirstName, _))
-        .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+  // Second validation succeeds.
+  EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
+      .After(set_first_name)
+      .WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), "not empty"));
 
-    // Second validation succeeds.
-    EXPECT_CALL(mock_web_controller_, OnGetFieldValue(_, _))
-        .WillRepeatedly(RunOnceCallback<1>(OkClientStatus(), "not empty"));
-  }
   EXPECT_EQ(ProcessedActionStatusProto::ACTION_APPLIED,
             ProcessAction(action_proto));
 }
@@ -302,6 +303,9 @@
 
 TEST_F(UseAddressActionTest,
        AutofillFailureWithRequiredFieldsLaunchesFallback) {
+  ON_CALL(mock_action_delegate_, GetElementTag(_, _))
+      .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
+
   ActionProto action_proto = CreateUseAddressAction();
   AddRequiredField(&action_proto, UseAddressProto::RequiredField::FIRST_NAME,
                    "#first_name");
diff --git a/components/autofill_assistant/browser/actions/use_credit_card_action.cc b/components/autofill_assistant/browser/actions/use_credit_card_action.cc
index 2a2fdb0..6eeecc1 100644
--- a/components/autofill_assistant/browser/actions/use_credit_card_action.cc
+++ b/components/autofill_assistant/browser/actions/use_credit_card_action.cc
@@ -15,6 +15,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill_assistant/browser/actions/action_delegate.h"
@@ -162,6 +163,10 @@
   fallback_data->field_values.emplace(
       (int)UseCreditCardProto::RequiredField::CREDIT_CARD_NUMBER,
       base::UTF16ToUTF8(card.GetRawInfo(autofill::CREDIT_CARD_NUMBER)));
+  fallback_data->field_values.emplace(
+      (int)UseCreditCardProto::RequiredField::CREDIT_CARD_NETWORK,
+      autofill::data_util::GetPaymentRequestData(card.network())
+          .basic_card_issuer_network);
   return fallback_data;
 }
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/use_credit_card_action_unittest.cc b/components/autofill_assistant/browser/actions/use_credit_card_action_unittest.cc
index e6a2486..53f1df9 100644
--- a/components/autofill_assistant/browser/actions/use_credit_card_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/use_credit_card_action_unittest.cc
@@ -159,6 +159,9 @@
 }
 
 TEST_F(UseCreditCardActionTest, FillCreditCardWithFallback) {
+  ON_CALL(mock_action_delegate_, GetElementTag(_, _))
+      .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
+
   ActionProto action = CreateUseCreditCardAction();
   AddRequiredField(
       &action, UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE,
@@ -181,6 +184,9 @@
   AddRequiredField(&action,
                    UseCreditCardProto::RequiredField::CREDIT_CARD_EXP_MM_YY,
                    "#exp_month_year2");
+  AddRequiredField(&action,
+                   UseCreditCardProto::RequiredField::CREDIT_CARD_NETWORK,
+                   "#network");
 
   // First validation fails.
   EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Selector({"#cvc"}), _))
@@ -200,6 +206,8 @@
   EXPECT_CALL(mock_web_controller_,
               OnGetFieldValue(Selector({"#exp_month_year2"}), _))
       .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
+  EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Selector({"#network"}), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), ""));
 
   // Expect fields to be filled
   Expectation set_cvc =
@@ -231,6 +239,10 @@
       EXPECT_CALL(mock_action_delegate_,
                   OnSetFieldValue(Selector({"#exp_month_year2"}), "09/24", _))
           .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+  Expectation set_card_network =
+      EXPECT_CALL(mock_action_delegate_,
+                  OnSetFieldValue(Selector({"#network"}), "visa", _))
+          .WillOnce(RunOnceCallback<2>(OkClientStatus()));
 
   // After fallback, second validation succeeds.
   EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Selector({"#cvc"}), _))
@@ -257,6 +269,9 @@
               OnGetFieldValue(Selector({"#exp_month_year2"}), _))
       .After(set_expyear4)
       .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
+  EXPECT_CALL(mock_web_controller_, OnGetFieldValue(Selector({"#network"}), _))
+      .After(set_card_network)
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), "not empty"));
 
   autofill::CreditCard credit_card;
   credit_card.SetExpirationMonth(9);
@@ -278,6 +293,9 @@
 }
 
 TEST_F(UseCreditCardActionTest, ForcedFallback) {
+  ON_CALL(mock_action_delegate_, GetElementTag(_, _))
+      .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
+
   ActionProto action = CreateUseCreditCardAction();
   auto* cvc_required = AddRequiredField(
       &action, UseCreditCardProto::RequiredField::CREDIT_CARD_VERIFICATION_CODE,
@@ -335,6 +353,9 @@
 
 TEST_F(UseCreditCardActionTest,
        AutofillFailureWithRequiredFieldsLaunchesFallback) {
+  ON_CALL(mock_action_delegate_, GetElementTag(_, _))
+      .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "INPUT"));
+
   ActionProto action_proto = CreateUseCreditCardAction();
   AddRequiredField(
       &action_proto,
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index e1d6040..1d2450a 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -420,6 +420,13 @@
   delegate_->GetWebController()->GetOuterHtml(selector, std::move(callback));
 }
 
+void ScriptExecutor::GetElementTag(
+    const Selector& selector,
+    base::OnceCallback<void(const ClientStatus&, const std::string&)>
+        callback) {
+  delegate_->GetWebController()->GetElementTag(selector, std::move(callback));
+}
+
 void ScriptExecutor::ExpectNavigation() {
   expected_navigation_step_ = ExpectedNavigationStep::EXPECTED;
 }
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 5b12198..f41f34a 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -174,6 +174,10 @@
       const Selector& selector,
       base::OnceCallback<void(const ClientStatus&, const std::string&)>
           callback) override;
+  void GetElementTag(
+      const Selector& selector,
+      base::OnceCallback<void(const ClientStatus&, const std::string&)>
+          callback) override;
   void ExpectNavigation() override;
   bool ExpectedNavigationHasStarted() override;
   bool WaitForNavigation(base::OnceCallback<void(bool)> callback) override;
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index fd80031..5d06133 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -974,6 +974,7 @@
       CREDIT_CARD_CARD_HOLDER_NAME = 5;
       CREDIT_CARD_NUMBER = 6;
       CREDIT_CARD_EXP_MM_YY = 7;
+      CREDIT_CARD_NETWORK = 8;
     }
 
     optional CardField card_field = 1;
diff --git a/components/autofill_assistant/browser/web/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc
index 1e4b695..96a9e80 100644
--- a/components/autofill_assistant/browser/web/web_controller.cc
+++ b/components/autofill_assistant/browser/web/web_controller.cc
@@ -138,6 +138,8 @@
 const char* const kGetOuterHtmlScript =
     "function () { return this.outerHTML; }";
 
+const char* const kGetElementTagScript = "function () { return this.tagName; }";
+
 // Javascript code to query whether the document is ready for interact.
 const char* const kIsDocumentReadyForInteract =
     R"(function () {
@@ -1267,18 +1269,6 @@
                      delay_in_millisecond, std::move(callback)));
 }
 
-void WebController::GetOuterHtml(
-    const Selector& selector,
-    base::OnceCallback<void(const ClientStatus&, const std::string&)>
-        callback) {
-  DVLOG(3) << __func__ << " " << selector;
-  FindElement(
-      selector,
-      /* strict_mode= */ true,
-      base::BindOnce(&WebController::OnFindElementForGetOuterHtml,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
 void WebController::GetVisualViewport(
     base::OnceCallback<void(bool, const RectF&)> callback) {
   devtools_client_->GetRuntime()->Evaluate(
@@ -1384,6 +1374,18 @@
   std::move(callback).Run(true, rect);
 }
 
+void WebController::GetOuterHtml(
+    const Selector& selector,
+    base::OnceCallback<void(const ClientStatus&, const std::string&)>
+        callback) {
+  DVLOG(3) << __func__ << " " << selector;
+  FindElement(
+      selector,
+      /* strict_mode= */ true,
+      base::BindOnce(&WebController::OnFindElementForGetOuterHtml,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
 void WebController::OnFindElementForGetOuterHtml(
     base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
     const ClientStatus& status,
@@ -1421,6 +1423,55 @@
   std::move(callback).Run(OkClientStatus(), value);
 }
 
+void WebController::GetElementTag(
+    const Selector& selector,
+    base::OnceCallback<void(const ClientStatus&, const std::string&)>
+        callback) {
+  DVLOG(3) << __func__ << " " << selector;
+  FindElement(
+      selector,
+      /* strict_mode= */ true,
+      base::BindOnce(&WebController::OnFindElementForGetElementTag,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void WebController::OnFindElementForGetElementTag(
+    base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
+    const ClientStatus& status,
+    std::unique_ptr<ElementFinder::Result> element_result) {
+  if (!status.ok()) {
+    DVLOG(2) << __func__ << " Failed to find element for GetElementTag";
+    std::move(callback).Run(status, "");
+    return;
+  }
+
+  devtools_client_->GetRuntime()->CallFunctionOn(
+      runtime::CallFunctionOnParams::Builder()
+          .SetObjectId(element_result->object_id)
+          .SetFunctionDeclaration(std::string(kGetElementTagScript))
+          .SetReturnByValue(true)
+          .Build(),
+      element_result->node_frame_id,
+      base::BindOnce(&WebController::OnGetElementTag,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void WebController::OnGetElementTag(
+    base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
+    const DevtoolsClient::ReplyStatus& reply_status,
+    std::unique_ptr<runtime::CallFunctionOnResult> result) {
+  ClientStatus status =
+      CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
+  if (!status.ok()) {
+    DVLOG(2) << __func__ << " Failed to get element tag for GetElementTag";
+    std::move(callback).Run(status, "");
+    return;
+  }
+  std::string value;
+  SafeGetStringValue(result->GetResult(), &value);
+  std::move(callback).Run(OkClientStatus(), value);
+}
+
 void WebController::WaitForDocumentToBecomeInteractive(
     int remaining_rounds,
     const std::string& object_id,
diff --git a/components/autofill_assistant/browser/web/web_controller.h b/components/autofill_assistant/browser/web/web_controller.h
index 7131905..acd8dec 100644
--- a/components/autofill_assistant/browser/web/web_controller.h
+++ b/components/autofill_assistant/browser/web/web_controller.h
@@ -159,6 +159,12 @@
       base::OnceCallback<void(const ClientStatus&, const std::string&)>
           callback);
 
+  // Return the tag of |selector|.
+  virtual void GetElementTag(
+      const Selector& selector,
+      base::OnceCallback<void(const ClientStatus&, const std::string&)>
+          callback);
+
   // Gets the visual viewport coordinates and size.
   //
   // The rectangle is expressed in absolute CSS coordinates.
@@ -407,6 +413,15 @@
                                               const std::string&)> callback,
                       const DevtoolsClient::ReplyStatus& reply_status,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
+  void OnFindElementForGetElementTag(
+      base::OnceCallback<void(const ClientStatus&, const std::string&)>
+          callback,
+      const ClientStatus& status,
+      std::unique_ptr<ElementFinder::Result> element_result);
+  void OnGetElementTag(base::OnceCallback<void(const ClientStatus&,
+                                               const std::string&)> callback,
+                       const DevtoolsClient::ReplyStatus& reply_status,
+                       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForPosition(
       base::OnceCallback<void(bool, const RectF&)> callback,
       const ClientStatus& status,
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
index 6229227..4457c76 100644
--- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc
+++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -250,6 +250,29 @@
     done_callback.Run();
   }
 
+  ClientStatus GetElementTag(const Selector& selector,
+                             std::string* element_tag_output) {
+    base::RunLoop run_loop;
+    ClientStatus result;
+    web_controller_->GetElementTag(
+        selector, base::BindOnce(&WebControllerBrowserTest::OnGetElementTag,
+                                 base::Unretained(this), run_loop.QuitClosure(),
+                                 &result, element_tag_output));
+    run_loop.Run();
+    return result;
+  }
+
+  void OnGetElementTag(const base::Closure& done_callback,
+                       ClientStatus* successful_output,
+                       std::string* element_tag_output,
+                       const ClientStatus& status,
+                       const std::string& element_tag) {
+    EXPECT_EQ(ACTION_APPLIED, status.proto_status());
+    *successful_output = status;
+    *element_tag_output = element_tag;
+    done_callback.Run();
+  }
+
   void FindElement(const Selector& selector,
                    ClientStatus* status_out,
                    ElementFinder::Result* result_out) {
@@ -1125,6 +1148,26 @@
   EXPECT_EQ(R"(<div id="divToRemove">Text</div>)", html);
 }
 
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetElementTag) {
+  std::string element_tag;
+
+  // Div.
+  ASSERT_EQ(
+      ACTION_APPLIED,
+      GetElementTag(Selector({"#testOuterHtml"}), &element_tag).proto_status());
+  EXPECT_EQ("DIV", element_tag);
+
+  // Select.
+  ASSERT_EQ(ACTION_APPLIED,
+            GetElementTag(Selector({"#select"}), &element_tag).proto_status());
+  EXPECT_EQ("SELECT", element_tag);
+
+  // Input.
+  ASSERT_EQ(ACTION_APPLIED,
+            GetElementTag(Selector({"#input1"}), &element_tag).proto_status());
+  EXPECT_EQ("INPUT", element_tag);
+}
+
 IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetAndSetFieldValue) {
   std::vector<Selector> selectors;
   std::vector<std::string> expected_values;
diff --git a/components/background_task_scheduler/BUILD.gn b/components/background_task_scheduler/BUILD.gn
index d2fa8da..95eb33e 100644
--- a/components/background_task_scheduler/BUILD.gn
+++ b/components/background_task_scheduler/BUILD.gn
@@ -24,9 +24,7 @@
   # related permissions for WebView while still wanting to avoid collision
   # between WebView and Chrome.
   android_library("background_task_scheduler_task_ids_java") {
-    sources = [
-      "android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java",
-    ]
+    sources = [ "android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java" ]
   }
 
   android_library("background_task_scheduler_java") {
@@ -125,8 +123,6 @@
   proto_java_library("scheduled_task_java") {
     proto_path =
         "android/java/src/org/chromium/components/background_task_scheduler"
-    sources = [
-      "$proto_path/scheduled_task.proto",
-    ]
+    sources = [ "$proto_path/scheduled_task.proto" ]
   }
 }
diff --git a/components/bookmarks/browser/BUILD.gn b/components/bookmarks/browser/BUILD.gn
index 3c5dcad..b9e45ef 100644
--- a/components/bookmarks/browser/BUILD.gn
+++ b/components/bookmarks/browser/BUILD.gn
@@ -52,9 +52,7 @@
     "url_index.h",
   ]
 
-  public_deps = [
-    "//components/bookmarks/common",
-  ]
+  public_deps = [ "//components/bookmarks/common" ]
 
   deps = [
     "//base",
@@ -104,9 +102,7 @@
     "bookmark_test_util.h",
   ]
 
-  deps = [
-    ":browser",
-  ]
+  deps = [ ":browser" ]
 }
 
 bundle_data("unit_tests_bundle_data") {
@@ -116,10 +112,8 @@
     "//components/test/data/bookmarks/meta_info_as_string.json",
     "//components/test/data/bookmarks/model_without_sync.json",
   ]
-  outputs = [
-    "{{bundle_resources_dir}}/" +
-        "{{source_root_relative_dir}}/{{source_file_part}}",
-  ]
+  outputs = [ "{{bundle_resources_dir}}/" +
+              "{{source_root_relative_dir}}/{{source_file_part}}" ]
 }
 
 source_set("unit_tests") {
@@ -159,9 +153,7 @@
 # The fuzzer depends on code that is not built on Mac.
 if (!is_mac) {
   fuzzer_test("bookmark_node_data_read_fuzzer") {
-    sources = [
-      "bookmark_node_data_read_fuzzer.cc",
-    ]
+    sources = [ "bookmark_node_data_read_fuzzer.cc" ]
     deps = [
       ":browser",
       "//base",
diff --git a/components/bookmarks/common/BUILD.gn b/components/bookmarks/common/BUILD.gn
index 8ce4153..5985827 100644
--- a/components/bookmarks/common/BUILD.gn
+++ b/components/bookmarks/common/BUILD.gn
@@ -10,9 +10,7 @@
     "bookmark_pref_names.h",
   ]
 
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
   if (is_android) {
     deps += [ "//components/bookmarks/common/android" ]
   }
diff --git a/components/bookmarks/managed/BUILD.gn b/components/bookmarks/managed/BUILD.gn
index e5b6048..d7ffa23 100644
--- a/components/bookmarks/managed/BUILD.gn
+++ b/components/bookmarks/managed/BUILD.gn
@@ -26,9 +26,7 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "managed_bookmarks_tracker_unittest.cc",
-  ]
+  sources = [ "managed_bookmarks_tracker_unittest.cc" ]
 
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
diff --git a/components/browser_ui/styles/android/BUILD.gn b/components/browser_ui/styles/android/BUILD.gn
index 43073181..d6da1d5f 100644
--- a/components/browser_ui/styles/android/BUILD.gn
+++ b/components/browser_ui/styles/android/BUILD.gn
@@ -6,9 +6,8 @@
 import("//ui/android/features.gni")
 
 android_library("java") {
-  sources = [
-    "java/src/org/chromium/components/browser_ui/styles/ChromeColors.java",
-  ]
+  sources =
+      [ "java/src/org/chromium/components/browser_ui/styles/ChromeColors.java" ]
   deps = [
     ":java_resources",
     "//base:base_java",
diff --git a/components/certificate_matching/BUILD.gn b/components/certificate_matching/BUILD.gn
index aa7e3bf..9d237796 100644
--- a/components/certificate_matching/BUILD.gn
+++ b/components/certificate_matching/BUILD.gn
@@ -18,9 +18,7 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "certificate_principal_pattern_unittest.cc",
-  ]
+  sources = [ "certificate_principal_pattern_unittest.cc" ]
 
   deps = [
     ":certificate_matching",
diff --git a/components/chrome_cleaner/public/proto/BUILD.gn b/components/chrome_cleaner/public/proto/BUILD.gn
index 0f556a43..e6c873c 100644
--- a/components/chrome_cleaner/public/proto/BUILD.gn
+++ b/components/chrome_cleaner/public/proto/BUILD.gn
@@ -5,15 +5,11 @@
 import("//third_party/protobuf/proto_library.gni")
 
 proto_library("proto") {
-  sources = [
-    "chrome_prompt.proto",
-  ]
+  sources = [ "chrome_prompt.proto" ]
 }
 
 proto_library("test_only_proto") {
   testonly = true
   generate_python = false
-  sources = [
-    "chrome_prompt_for_tests.proto",
-  ]
+  sources = [ "chrome_prompt_for_tests.proto" ]
 }
diff --git a/components/chrome_cleaner/test/BUILD.gn b/components/chrome_cleaner/test/BUILD.gn
index 593b2bb..e0d0037 100644
--- a/components/chrome_cleaner/test/BUILD.gn
+++ b/components/chrome_cleaner/test/BUILD.gn
@@ -5,9 +5,7 @@
 source_set("test_name_helper") {
   testonly = true
 
-  sources = [
-    "test_name_helper.h",
-  ]
+  sources = [ "test_name_helper.h" ]
 
   public_deps = [
     "//base:base",
diff --git a/components/contextual_search/content/common/mojom/BUILD.gn b/components/contextual_search/content/common/mojom/BUILD.gn
index 74e032c..70afab4 100644
--- a/components/contextual_search/content/common/mojom/BUILD.gn
+++ b/components/contextual_search/content/common/mojom/BUILD.gn
@@ -6,10 +6,6 @@
 
 mojom("mojom") {
   generate_java = true
-  sources = [
-    "contextual_search_js_api_service.mojom",
-  ]
-  public_deps = [
-    "//url/mojom:url_mojom_gurl",
-  ]
+  sources = [ "contextual_search_js_api_service.mojom" ]
+  public_deps = [ "//url/mojom:url_mojom_gurl" ]
 }
diff --git a/components/contextual_search/core/BUILD.gn b/components/contextual_search/core/BUILD.gn
index de7b3f3..96ef8db 100644
--- a/components/contextual_search/core/BUILD.gn
+++ b/components/contextual_search/core/BUILD.gn
@@ -20,9 +20,7 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "browser/ctr_aggregator_unittest.cc",
-  ]
+  sources = [ "browser/ctr_aggregator_unittest.cc" ]
 
   deps = [
     ":browser",
diff --git a/components/device_event_log/BUILD.gn b/components/device_event_log/BUILD.gn
index 593b58b..738bf29 100644
--- a/components/device_event_log/BUILD.gn
+++ b/components/device_event_log/BUILD.gn
@@ -12,16 +12,12 @@
 
   defines = [ "DEVICE_EVENT_LOG_IMPLEMENTATION" ]
 
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
 }
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "device_event_log_impl_unittest.cc",
-  ]
+  sources = [ "device_event_log_impl_unittest.cc" ]
 
   deps = [
     ":device_event_log",
diff --git a/components/exo/wayland/fuzzer/BUILD.gn b/components/exo/wayland/fuzzer/BUILD.gn
index 15706168..bc613a4 100644
--- a/components/exo/wayland/fuzzer/BUILD.gn
+++ b/components/exo/wayland/fuzzer/BUILD.gn
@@ -36,62 +36,46 @@
 ]
 
 wayland_templater("protocol_dump") {
-  sources = [
-    "misc/dump.tmpl",
-  ]
+  sources = [ "misc/dump.tmpl" ]
   protocols = kDefaultWaylandProtocols
 }
 
 wayland_templater("protocol_graph") {
-  sources = [
-    "misc/graph.dot.tmpl",
-  ]
+  sources = [ "misc/graph.dot.tmpl" ]
   protocols = kDefaultWaylandProtocols
 }
 
 wayland_templater("protocol_docs") {
-  sources = [
-    "misc/docs.md.tmpl",
-  ]
+  sources = [ "misc/docs.md.tmpl" ]
   protocols = kDefaultWaylandProtocols
 }
 
 wayland_templater("actions_tmpl") {
-  sources = [
-    "actions.proto.tmpl",
-  ]
+  sources = [ "actions.proto.tmpl" ]
   protocols = kDefaultWaylandProtocols
 }
 
 wayland_templater("harness_h_tmpl") {
-  sources = [
-    "harness.h.tmpl",
-  ]
+  sources = [ "harness.h.tmpl" ]
   protocols = kDefaultWaylandProtocols
 }
 
 wayland_templater("harness_cc_tmpl") {
-  sources = [
-    "harness.cc.tmpl",
-  ]
+  sources = [ "harness.cc.tmpl" ]
   protocols = kDefaultWaylandProtocols
 }
 
 # We make the seed corpus by enumerating call sequences to all requests
 # using the wayland_sequencer script.
 wayland_templater("corpus") {
-  sources = [
-    "corpus.tmpl",
-  ]
+  sources = [ "corpus.tmpl" ]
   protocols = kDefaultWaylandProtocols
   script_override = "wayland_sequencer.py"
 }
 
 if (use_libfuzzer) {
   fuzzer_test("wayland_fuzzer") {
-    sources = [
-      "fuzzer.cc",
-    ]
+    sources = [ "fuzzer.cc" ]
 
     deps = [
       ":actions",
@@ -112,9 +96,7 @@
 source_set("unit_tests") {
   testonly = true
 
-  sources = [
-    "harness_unittest.cc",
-  ]
+  sources = [ "harness_unittest.cc" ]
 
   deps = [
     ":actions",
@@ -191,7 +173,5 @@
   # output directory to rebase under the source root.
   proto_out_dir = rebase_path(".", "//")
 
-  deps = [
-    ":actions_tmpl",
-  ]
+  deps = [ ":actions_tmpl" ]
 }
diff --git a/components/favicon/core/history_ui_favicon_request_handler.h b/components/favicon/core/history_ui_favicon_request_handler.h
index 6654c5d..3aa9888 100644
--- a/components/favicon/core/history_ui_favicon_request_handler.h
+++ b/components/favicon/core/history_ui_favicon_request_handler.h
@@ -8,10 +8,6 @@
 #include "components/favicon_base/favicon_callback.h"
 #include "components/keyed_service/core/keyed_service.h"
 
-namespace base {
-class CancelableTaskTracker;
-}
-
 class GURL;
 
 namespace favicon {
@@ -51,8 +47,7 @@
       favicon_base::FaviconRawBitmapCallback callback,
       FaviconRequestPlatform request_platform,
       HistoryUiFaviconRequestOrigin request_origin_for_uma,
-      const GURL& icon_url_for_uma,
-      base::CancelableTaskTracker* tracker) = 0;
+      const GURL& icon_url_for_uma) = 0;
 
   // Requests favicon image at |page_url|.
   // Tries to fetch the icon from local storage and falls back to sync, or to
@@ -65,8 +60,7 @@
       const GURL& page_url,
       favicon_base::FaviconImageCallback callback,
       HistoryUiFaviconRequestOrigin request_origin_for_uma,
-      const GURL& icon_url_for_uma,
-      base::CancelableTaskTracker* tracker) = 0;
+      const GURL& icon_url_for_uma) = 0;
 };
 
 }  // namespace favicon
diff --git a/components/favicon/core/history_ui_favicon_request_handler_impl.cc b/components/favicon/core/history_ui_favicon_request_handler_impl.cc
index c065351..662d2bb7 100644
--- a/components/favicon/core/history_ui_favicon_request_handler_impl.cc
+++ b/components/favicon/core/history_ui_favicon_request_handler_impl.cc
@@ -11,7 +11,6 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/task/cancelable_task_tracker.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/favicon/core/features.h"
 #include "components/favicon/core/large_icon_service.h"
@@ -120,8 +119,7 @@
     favicon_base::FaviconRawBitmapCallback callback,
     FaviconRequestPlatform request_platform,
     HistoryUiFaviconRequestOrigin request_origin_for_uma,
-    const GURL& icon_url_for_uma,
-    base::CancelableTaskTracker* tracker) {
+    const GURL& icon_url_for_uma) {
   // First attempt to find the icon locally.
   favicon_service_->GetRawFaviconForPageURL(
       page_url, GetIconTypesForLocalQuery(), desired_size_in_pixel,
@@ -131,16 +129,15 @@
           weak_ptr_factory_.GetWeakPtr(), CanQueryGoogleServer(), page_url,
           desired_size_in_pixel,
           /*response_callback=*/std::move(callback), request_platform,
-          request_origin_for_uma, icon_url_for_uma, base::Time::Now(), tracker),
-      tracker);
+          request_origin_for_uma, icon_url_for_uma, base::Time::Now()),
+      &cancelable_task_tracker_);
 }
 
 void HistoryUiFaviconRequestHandlerImpl::GetFaviconImageForPageURL(
     const GURL& page_url,
     favicon_base::FaviconImageCallback callback,
     HistoryUiFaviconRequestOrigin request_origin_for_uma,
-    const GURL& icon_url_for_uma,
-    base::CancelableTaskTracker* tracker) {
+    const GURL& icon_url_for_uma) {
   // First attempt to find the icon locally.
   favicon_service_->GetFaviconImageForPageURL(
       page_url,
@@ -148,8 +145,8 @@
           &HistoryUiFaviconRequestHandlerImpl::OnImageLocalDataAvailable,
           weak_ptr_factory_.GetWeakPtr(), CanQueryGoogleServer(), page_url,
           /*response_callback=*/std::move(callback), request_origin_for_uma,
-          icon_url_for_uma, base::Time::Now(), tracker),
-      tracker);
+          icon_url_for_uma, base::Time::Now()),
+      &cancelable_task_tracker_);
 }
 
 void HistoryUiFaviconRequestHandlerImpl::OnBitmapLocalDataAvailable(
@@ -161,7 +158,6 @@
     HistoryUiFaviconRequestOrigin origin_for_uma,
     const GURL& icon_url_for_uma,
     base::Time request_start_time_for_uma,
-    base::CancelableTaskTracker* tracker,
     const favicon_base::FaviconRawBitmapResult& bitmap_result) {
   if (bitmap_result.is_valid()) {
     // The icon comes from local storage now even though it may have been
@@ -187,9 +183,11 @@
         /*local_lookup_callback=*/
         base::BindOnce(
             base::IgnoreResult(&FaviconService::GetRawFaviconForPageURL),
+            // base::Unretained() is safe here as RequestFromGoogleServer()
+            // doesn't execute the callback if |this| is deleted.
             base::Unretained(favicon_service_), page_url,
             GetIconTypesForLocalQuery(), desired_size_in_pixel, kFallbackToHost,
-            repeating_response_callback, tracker),
+            repeating_response_callback, &cancelable_task_tracker_),
         origin_for_uma, icon_url_for_uma, request_start_time_for_uma);
     return;
   }
@@ -220,7 +218,6 @@
     HistoryUiFaviconRequestOrigin origin_for_uma,
     const GURL& icon_url_for_uma,
     base::Time request_start_time_for_uma,
-    base::CancelableTaskTracker* tracker,
     const favicon_base::FaviconImageResult& image_result) {
   if (!image_result.image.IsEmpty()) {
     // The icon comes from local storage now even though it may have been
@@ -248,8 +245,10 @@
         /*local_lookup_callback=*/
         base::BindOnce(
             base::IgnoreResult(&FaviconService::GetFaviconImageForPageURL),
+            // base::Unretained() is safe here as RequestFromGoogleServer()
+            // doesn't execture the callback if |this| is deleted.
             base::Unretained(favicon_service_), page_url,
-            repeating_response_callback, tracker),
+            repeating_response_callback, &cancelable_task_tracker_),
         origin_for_uma, icon_url_for_uma, request_start_time_for_uma);
     return;
   }
diff --git a/components/favicon/core/history_ui_favicon_request_handler_impl.h b/components/favicon/core/history_ui_favicon_request_handler_impl.h
index 710c807..6ed7ff3 100644
--- a/components/favicon/core/history_ui_favicon_request_handler_impl.h
+++ b/components/favicon/core/history_ui_favicon_request_handler_impl.h
@@ -9,6 +9,7 @@
 #include <memory>
 
 #include "base/memory/weak_ptr.h"
+#include "base/task/cancelable_task_tracker.h"
 #include "components/favicon/core/history_ui_favicon_request_handler.h"
 #include "components/favicon_base/favicon_types.h"
 
@@ -56,15 +57,12 @@
       favicon_base::FaviconRawBitmapCallback callback,
       FaviconRequestPlatform request_platform,
       HistoryUiFaviconRequestOrigin request_origin_for_uma,
-      const GURL& icon_url_for_uma,
-      base::CancelableTaskTracker* tracker) override;
-
+      const GURL& icon_url_for_uma) override;
   void GetFaviconImageForPageURL(
       const GURL& page_url,
       favicon_base::FaviconImageCallback callback,
       HistoryUiFaviconRequestOrigin request_origin_for_uma,
-      const GURL& icon_url_for_uma,
-      base::CancelableTaskTracker* tracker) override;
+      const GURL& icon_url_for_uma) override;
 
  private:
   // Called after the first attempt to retrieve the icon bitmap from local
@@ -82,7 +80,6 @@
       HistoryUiFaviconRequestOrigin origin_for_uma,
       const GURL& icon_url_for_uma,
       base::Time request_start_time_for_uma,
-      base::CancelableTaskTracker* tracker,
       const favicon_base::FaviconRawBitmapResult& bitmap_result);
 
   // Called after the first attempt to retrieve the icon image from local
@@ -96,12 +93,12 @@
       HistoryUiFaviconRequestOrigin origin_for_uma,
       const GURL& icon_url_for_uma,
       base::Time request_start_time_for_uma,
-      base::CancelableTaskTracker* tracker,
       const favicon_base::FaviconImageResult& image_result);
 
   // Requests an icon from Google favicon server. Since requests work by
   // populating local storage, a |local_lookup_callback| will be needed in case
-  // of success and an |empty_response_callback| in case of failure.
+  // of success and an |empty_response_callback| in case of failure. Neither
+  // callback is run if |this| is deleted before completion.
   void RequestFromGoogleServer(const GURL& page_url,
                                base::OnceClosure empty_response_callback,
                                base::OnceClosure local_lookup_callback,
@@ -137,6 +134,9 @@
   // benefit of grouping.
   std::map<GURL, int> group_callbacks_count_;
 
+  // Needed for using FaviconService.
+  base::CancelableTaskTracker cancelable_task_tracker_;
+
   base::WeakPtrFactory<HistoryUiFaviconRequestHandlerImpl> weak_ptr_factory_{
       this};
 
diff --git a/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc b/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc
index 2653e76..09b02c1 100644
--- a/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc
+++ b/components/favicon/core/history_ui_favicon_request_handler_impl_unittest.cc
@@ -231,7 +231,6 @@
   testing::NiceMock<base::MockCallback<
       HistoryUiFaviconRequestHandlerImpl::CanSendHistoryDataGetter>>
       can_send_history_data_getter_;
-  base::CancelableTaskTracker tracker_;
   base::HistogramTester histogram_tester_;
   base::test::ScopedFeatureList scoped_feature_list_;
   HistoryUiFaviconRequestHandlerImpl history_ui_favicon_request_handler_;
@@ -243,17 +242,16 @@
 TEST_F(HistoryUiFaviconRequestHandlerImplTest, ShouldGetEmptyBitmap) {
   scoped_feature_list_.InitAndDisableFeature(
       kEnableHistoryFaviconsGoogleServerQuery);
-  EXPECT_CALL(
-      mock_favicon_service_,
-      GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
-                              kDefaultDesiredSizeInPixel, _, _, &tracker_));
+  EXPECT_CALL(mock_favicon_service_,
+              GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
+                                      kDefaultDesiredSizeInPixel, _, _, _));
   EXPECT_CALL(synced_favicon_getter_, Run(GURL(kDummyPageUrl)))
       .WillOnce([](auto) { return favicon_base::FaviconRawBitmapResult(); });
   favicon_base::FaviconRawBitmapResult result;
   history_ui_favicon_request_handler_.GetRawFaviconForPageURL(
       GURL(kDummyPageUrl), kDefaultDesiredSizeInPixel,
       base::BindOnce(&StoreBitmap, &result), kDummyPlatform, kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_FALSE(result.is_valid());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -265,17 +263,16 @@
 TEST_F(HistoryUiFaviconRequestHandlerImplTest, ShouldGetSyncBitmap) {
   scoped_feature_list_.InitAndDisableFeature(
       kEnableHistoryFaviconsGoogleServerQuery);
-  EXPECT_CALL(
-      mock_favicon_service_,
-      GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
-                              kDefaultDesiredSizeInPixel, _, _, &tracker_));
+  EXPECT_CALL(mock_favicon_service_,
+              GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
+                                      kDefaultDesiredSizeInPixel, _, _, _));
   EXPECT_CALL(synced_favicon_getter_, Run(GURL(kDummyPageUrl)))
       .WillOnce([](auto) { return CreateTestBitmapResult(); });
   favicon_base::FaviconRawBitmapResult result;
   history_ui_favicon_request_handler_.GetRawFaviconForPageURL(
       GURL(kDummyPageUrl), kDefaultDesiredSizeInPixel,
       base::BindOnce(&StoreBitmap, &result), kDummyPlatform, kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_TRUE(result.is_valid());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -288,10 +285,9 @@
   scoped_feature_list_.InitAndDisableFeature(
       kEnableHistoryFaviconsGoogleServerQuery);
   mock_favicon_service_.StoreMockLocalFavicon(GURL(kDummyPageUrl));
-  EXPECT_CALL(
-      mock_favicon_service_,
-      GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
-                              kDefaultDesiredSizeInPixel, _, _, &tracker_));
+  EXPECT_CALL(mock_favicon_service_,
+              GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
+                                      kDefaultDesiredSizeInPixel, _, _, _));
   EXPECT_CALL(mock_large_icon_service_,
               TouchIconFromGoogleServer(GURL(kDummyIconUrl)));
   EXPECT_CALL(synced_favicon_getter_, Run(_)).Times(0);
@@ -299,7 +295,7 @@
   history_ui_favicon_request_handler_.GetRawFaviconForPageURL(
       GURL(kDummyPageUrl), kDefaultDesiredSizeInPixel,
       base::BindOnce(&StoreBitmap, &result), kDummyPlatform, kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_TRUE(result.is_valid());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -314,10 +310,9 @@
       kEnableHistoryFaviconsGoogleServerQuery, {{"trim_url_path", "false"}});
   mock_large_icon_service_.StoreMockGoogleServerFavicon(GURL(kDummyPageUrl));
   EXPECT_CALL(can_send_history_data_getter_, Run());
-  EXPECT_CALL(
-      mock_favicon_service_,
-      GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
-                              kDefaultDesiredSizeInPixel, _, _, &tracker_))
+  EXPECT_CALL(mock_favicon_service_,
+              GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
+                                      kDefaultDesiredSizeInPixel, _, _, _))
       .Times(2);
   EXPECT_CALL(mock_large_icon_service_,
               GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
@@ -327,7 +322,7 @@
   history_ui_favicon_request_handler_.GetRawFaviconForPageURL(
       GURL(kDummyPageUrl), kDefaultDesiredSizeInPixel,
       base::BindOnce(&StoreBitmap, &result), kDummyPlatform, kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_TRUE(result.is_valid());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -344,10 +339,9 @@
       kEnableHistoryFaviconsGoogleServerQuery, {{"trim_url_path", "true"}});
   mock_large_icon_service_.StoreMockGoogleServerFavicon(GURL(kDummyPageUrl));
   EXPECT_CALL(can_send_history_data_getter_, Run());
-  EXPECT_CALL(
-      mock_favicon_service_,
-      GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
-                              kDefaultDesiredSizeInPixel, _, _, &tracker_))
+  EXPECT_CALL(mock_favicon_service_,
+              GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
+                                      kDefaultDesiredSizeInPixel, _, _, _))
       .Times(2);
   EXPECT_CALL(mock_large_icon_service_,
               GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
@@ -358,7 +352,7 @@
   history_ui_favicon_request_handler_.GetRawFaviconForPageURL(
       GURL(kDummyPageUrl), kDefaultDesiredSizeInPixel,
       base::BindOnce(&StoreBitmap, &result), kDummyPlatform, kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_TRUE(result.is_valid());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -373,13 +367,13 @@
   scoped_feature_list_.InitAndDisableFeature(
       kEnableHistoryFaviconsGoogleServerQuery);
   EXPECT_CALL(mock_favicon_service_,
-              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, &tracker_));
+              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, _));
   EXPECT_CALL(synced_favicon_getter_, Run(GURL(kDummyPageUrl)))
       .WillOnce([](auto) { return favicon_base::FaviconRawBitmapResult(); });
   favicon_base::FaviconImageResult result;
   history_ui_favicon_request_handler_.GetFaviconImageForPageURL(
       GURL(kDummyPageUrl), base::BindOnce(&StoreImage, &result), kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_TRUE(result.image.IsEmpty());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -392,13 +386,13 @@
   scoped_feature_list_.InitAndDisableFeature(
       kEnableHistoryFaviconsGoogleServerQuery);
   EXPECT_CALL(mock_favicon_service_,
-              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, &tracker_));
+              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, _));
   EXPECT_CALL(synced_favicon_getter_, Run(GURL(kDummyPageUrl)))
       .WillOnce([](auto) { return CreateTestBitmapResult(); });
   favicon_base::FaviconImageResult result;
   history_ui_favicon_request_handler_.GetFaviconImageForPageURL(
       GURL(kDummyPageUrl), base::BindOnce(&StoreImage, &result), kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_FALSE(result.image.IsEmpty());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -412,14 +406,14 @@
       kEnableHistoryFaviconsGoogleServerQuery);
   mock_favicon_service_.StoreMockLocalFavicon(GURL(kDummyPageUrl));
   EXPECT_CALL(mock_favicon_service_,
-              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, &tracker_));
+              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, _));
   EXPECT_CALL(mock_large_icon_service_,
               TouchIconFromGoogleServer(GURL(kDummyIconUrl)));
   EXPECT_CALL(synced_favicon_getter_, Run(_)).Times(0);
   favicon_base::FaviconImageResult result;
   history_ui_favicon_request_handler_.GetFaviconImageForPageURL(
       GURL(kDummyPageUrl), base::BindOnce(&StoreImage, &result), kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_FALSE(result.image.IsEmpty());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -435,7 +429,7 @@
   mock_large_icon_service_.StoreMockGoogleServerFavicon(GURL(kDummyPageUrl));
   EXPECT_CALL(can_send_history_data_getter_, Run());
   EXPECT_CALL(mock_favicon_service_,
-              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, &tracker_))
+              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, _))
       .Times(2);
   EXPECT_CALL(mock_large_icon_service_,
               GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
@@ -445,7 +439,7 @@
   favicon_base::FaviconImageResult result;
   history_ui_favicon_request_handler_.GetFaviconImageForPageURL(
       GURL(kDummyPageUrl), base::BindOnce(&StoreImage, &result), kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_FALSE(result.image.IsEmpty());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -463,7 +457,7 @@
   mock_large_icon_service_.StoreMockGoogleServerFavicon(GURL(kDummyPageUrl));
   EXPECT_CALL(can_send_history_data_getter_, Run());
   EXPECT_CALL(mock_favicon_service_,
-              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, &tracker_))
+              GetFaviconImageForPageURL(GURL(kDummyPageUrl), _, _))
       .Times(2);
   EXPECT_CALL(mock_large_icon_service_,
               GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
@@ -473,7 +467,7 @@
   favicon_base::FaviconImageResult result;
   history_ui_favicon_request_handler_.GetFaviconImageForPageURL(
       GURL(kDummyPageUrl), base::BindOnce(&StoreImage, &result), kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_FALSE(result.image.IsEmpty());
   histogram_tester_.ExpectUniqueSample(
       std::string(kAvailabilityHistogramName) + kDummyOriginHistogramSuffix,
@@ -491,10 +485,9 @@
   EXPECT_CALL(can_send_history_data_getter_, Run()).WillOnce([]() {
     return false;
   });
-  EXPECT_CALL(
-      mock_favicon_service_,
-      GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
-                              kDefaultDesiredSizeInPixel, _, _, &tracker_))
+  EXPECT_CALL(mock_favicon_service_,
+              GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
+                                      kDefaultDesiredSizeInPixel, _, _, _))
       .WillOnce([](auto, auto, auto, auto,
                    favicon_base::FaviconRawBitmapCallback callback, auto) {
         std::move(callback).Run(favicon_base::FaviconRawBitmapResult());
@@ -508,7 +501,7 @@
   history_ui_favicon_request_handler_.GetRawFaviconForPageURL(
       GURL(kDummyPageUrl), kDefaultDesiredSizeInPixel,
       base::BindOnce(&StoreBitmap, &result), kDummyPlatform, kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
 }
 
 TEST_F(HistoryUiFaviconRequestHandlerImplTest, ShouldResizeSyncBitmap) {
@@ -518,7 +511,7 @@
       kEnableHistoryFaviconsGoogleServerQuery);
   EXPECT_CALL(mock_favicon_service_,
               GetRawFaviconForPageURL(GURL(kDummyPageUrl), _,
-                                      kDesiredSizeInPixel, _, _, &tracker_))
+                                      kDesiredSizeInPixel, _, _, _))
       .WillOnce([](auto, auto, auto, auto,
                    favicon_base::FaviconRawBitmapCallback callback, auto) {
         std::move(callback).Run(favicon_base::FaviconRawBitmapResult());
@@ -531,7 +524,7 @@
   history_ui_favicon_request_handler_.GetRawFaviconForPageURL(
       GURL(kDummyPageUrl), kDesiredSizeInPixel,
       base::BindOnce(&StoreBitmap, &result), kDummyPlatform, kDummyOrigin,
-      /*icon_url_for_uma=*/GURL(), &tracker_);
+      /*icon_url_for_uma=*/GURL());
   EXPECT_TRUE(result.is_valid());
   EXPECT_EQ(gfx::Size(kDesiredSizeInPixel, kDesiredSizeInPixel),
             result.pixel_size);
diff --git a/components/google/core/common/BUILD.gn b/components/google/core/common/BUILD.gn
index 1f7b4cb..a758f5c 100644
--- a/components/google/core/common/BUILD.gn
+++ b/components/google/core/common/BUILD.gn
@@ -25,9 +25,7 @@
 source_set("unit_tests") {
   testonly = true
 
-  sources = [
-    "google_util_unittest.cc",
-  ]
+  sources = [ "google_util_unittest.cc" ]
 
   deps = [
     ":common",
diff --git a/components/grpc_support/BUILD.gn b/components/grpc_support/BUILD.gn
index d7f8d1a..133aa3015 100644
--- a/components/grpc_support/BUILD.gn
+++ b/components/grpc_support/BUILD.gn
@@ -1,7 +1,5 @@
 source_set("headers") {
-  public = [
-    "include/bidirectional_stream_c.h",
-  ]
+  public = [ "include/bidirectional_stream_c.h" ]
 }
 
 source_set("grpc_support") {
@@ -23,9 +21,7 @@
 # Depends on ":grpc_support" implementation.
 source_set("bidirectional_stream_unittest") {
   testonly = true
-  sources = [
-    "bidirectional_stream_unittest.cc",
-  ]
+  sources = [ "bidirectional_stream_unittest.cc" ]
 
   deps = [
     ":grpc_support",
@@ -34,17 +30,13 @@
     "//net:test_support",
   ]
 
-  public_deps = [
-    "//components/grpc_support/test:get_stream_engine_header",
-  ]
+  public_deps = [ "//components/grpc_support/test:get_stream_engine_header" ]
 }
 
 # Depends on ":headers" to avoid ":grpc_support" implementation.
 source_set("bidirectional_stream_test") {
   testonly = true
-  sources = [
-    "bidirectional_stream_unittest.cc",
-  ]
+  sources = [ "bidirectional_stream_unittest.cc" ]
 
   deps = [
     ":headers",
@@ -53,7 +45,5 @@
     "//net:test_support",
   ]
 
-  public_deps = [
-    "//components/grpc_support/test:get_stream_engine_header",
-  ]
+  public_deps = [ "//components/grpc_support/test:get_stream_engine_header" ]
 }
diff --git a/components/grpc_support/test/BUILD.gn b/components/grpc_support/test/BUILD.gn
index d0b39f6..62b72d2 100644
--- a/components/grpc_support/test/BUILD.gn
+++ b/components/grpc_support/test/BUILD.gn
@@ -1,8 +1,6 @@
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "get_stream_engine.cc",
-  ]
+  sources = [ "get_stream_engine.cc" ]
 
   deps = [
     "//base",
@@ -15,9 +13,7 @@
 
 source_set("get_stream_engine_header") {
   testonly = true
-  sources = [
-    "get_stream_engine.h",
-  ]
+  sources = [ "get_stream_engine.h" ]
 
   deps = [
     "//base",
diff --git a/components/heap_profiling/BUILD.gn b/components/heap_profiling/BUILD.gn
index cc8281c..506f6f8 100644
--- a/components/heap_profiling/BUILD.gn
+++ b/components/heap_profiling/BUILD.gn
@@ -26,21 +26,15 @@
 if (is_android) {
   generate_jni("jni_headers") {
     testonly = true
-    sources = [
-      "javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java",
-    ]
+    sources = [ "javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java" ]
   }
 
   # This library must be included by the apk_under_test in order for the JNI
   # shim to function correctly.
   android_library("heap_profiling_java_test_support") {
     testonly = true
-    sources = [
-      "javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java",
-    ]
-    deps = [
-      "//base:base_java",
-    ]
+    sources = [ "javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java" ]
+    deps = [ "//base:base_java" ]
   }
 }
 
diff --git a/components/history/core/browser/BUILD.gn b/components/history/core/browser/BUILD.gn
index f02b61b..877daac 100644
--- a/components/history/core/browser/BUILD.gn
+++ b/components/history/core/browser/BUILD.gn
@@ -181,10 +181,8 @@
     "//components/test/data/history/thumbnail_wild/Favicons.v5.sizes.sql",
     "//components/test/data/history/thumbnail_wild/Favicons.v6.init.sql",
   ]
-  outputs = [
-    "{{bundle_resources_dir}}/" +
-        "{{source_root_relative_dir}}/{{source_file_part}}",
-  ]
+  outputs = [ "{{bundle_resources_dir}}/" +
+              "{{source_root_relative_dir}}/{{source_file_part}}" ]
 }
 
 source_set("unit_tests") {
diff --git a/components/history/core/common/BUILD.gn b/components/history/core/common/BUILD.gn
index d2f7a71..51fed02 100644
--- a/components/history/core/common/BUILD.gn
+++ b/components/history/core/common/BUILD.gn
@@ -10,16 +10,12 @@
     "thumbnail_score.h",
   ]
 
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
 }
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "thumbnail_score_unittest.cc",
-  ]
+  sources = [ "thumbnail_score_unittest.cc" ]
   deps = [
     ":common",
     "//testing/gtest",
diff --git a/components/language/content/browser/BUILD.gn b/components/language/content/browser/BUILD.gn
index ec73d42..e80814d 100644
--- a/components/language/content/browser/BUILD.gn
+++ b/components/language/content/browser/BUILD.gn
@@ -5,12 +5,8 @@
 import("//build/config/compiler/compiler.gni")
 
 source_set("language_code_locator") {
-  sources = [
-    "language_code_locator.h",
-  ]
-  deps = [
-    "//base",
-  ]
+  sources = [ "language_code_locator.h" ]
+  deps = [ "//base" ]
 }
 
 static_library("browser") {
diff --git a/components/language/content/browser/ulp_language_code_locator/BUILD.gn b/components/language/content/browser/ulp_language_code_locator/BUILD.gn
index 99c5985..15547fe 100644
--- a/components/language/content/browser/ulp_language_code_locator/BUILD.gn
+++ b/components/language/content/browser/ulp_language_code_locator/BUILD.gn
@@ -12,12 +12,8 @@
     "geolanguage-data_rank1.bin",
     "geolanguage-data_rank2.bin",
   ]
-  sources = [
-    "ulp_language_code_locator_helper.h.tmpl",
-  ]
-  outputs = [
-    "$target_gen_dir/ulp_language_code_locator_helper.h",
-  ]
+  sources = [ "ulp_language_code_locator_helper.h.tmpl" ]
+  outputs = [ "$target_gen_dir/ulp_language_code_locator_helper.h" ]
 
   args = [
     "--data",
diff --git a/components/language/ios/browser/BUILD.gn b/components/language/ios/browser/BUILD.gn
index aeb5cd3..c07c701 100644
--- a/components/language/ios/browser/BUILD.gn
+++ b/components/language/ios/browser/BUILD.gn
@@ -23,9 +23,7 @@
 source_set("unit_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
-  sources = [
-    "ios_language_detection_tab_helper_observer_bridge_unittest.mm",
-  ]
+  sources = [ "ios_language_detection_tab_helper_observer_bridge_unittest.mm" ]
   deps = [
     ":browser",
     "//components/translate/core/common",
diff --git a/components/leveldb_proto/BUILD.gn b/components/leveldb_proto/BUILD.gn
index 6dae43b..cdef4cd 100644
--- a/components/leveldb_proto/BUILD.gn
+++ b/components/leveldb_proto/BUILD.gn
@@ -5,9 +5,7 @@
 import("//third_party/protobuf/proto_library.gni")
 
 proto_library("proto") {
-  sources = [
-    "internal/proto/shared_db_metadata.proto",
-  ]
+  sources = [ "internal/proto/shared_db_metadata.proto" ]
 }
 
 component("leveldb_proto") {
@@ -42,9 +40,7 @@
     "public/shared_proto_database_client_list.h",
   ]
   defines = [ "IS_LEVELDB_PROTO_IMPL" ]
-  deps = [
-    ":proto",
-  ]
+  deps = [ ":proto" ]
 
   public_deps = [
     "//base",
@@ -55,9 +51,7 @@
 
 source_set("test_support") {
   testonly = true
-  sources = [
-    "testing/fake_db.h",
-  ]
+  sources = [ "testing/fake_db.h" ]
 
   public_deps = [
     ":leveldb_proto",
diff --git a/components/leveldb_proto/testing/proto/BUILD.gn b/components/leveldb_proto/testing/proto/BUILD.gn
index 52c7233..21a9c9e 100644
--- a/components/leveldb_proto/testing/proto/BUILD.gn
+++ b/components/leveldb_proto/testing/proto/BUILD.gn
@@ -5,7 +5,5 @@
 import("//third_party/protobuf/proto_library.gni")
 
 proto_library("proto") {
-  sources = [
-    "test_db.proto",
-  ]
+  sources = [ "test_db.proto" ]
 }
diff --git a/components/minidump_uploader/BUILD.gn b/components/minidump_uploader/BUILD.gn
index a0f823b..f8e9301 100644
--- a/components/minidump_uploader/BUILD.gn
+++ b/components/minidump_uploader/BUILD.gn
@@ -5,9 +5,7 @@
 import("//build/config/android/rules.gni")
 
 generate_jni("minidump_uploader_jni_headers") {
-  sources = [
-    "android/java/src/org/chromium/components/minidump_uploader/CrashReportMimeWriter.java",
-  ]
+  sources = [ "android/java/src/org/chromium/components/minidump_uploader/CrashReportMimeWriter.java" ]
 }
 
 static_library("minidump_uploader") {
diff --git a/components/open_from_clipboard/BUILD.gn b/components/open_from_clipboard/BUILD.gn
index 0b05b9d..451ed14 100644
--- a/components/open_from_clipboard/BUILD.gn
+++ b/components/open_from_clipboard/BUILD.gn
@@ -34,9 +34,7 @@
     "clipboard_recent_content_features.cc",
     "clipboard_recent_content_features.h",
   ]
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
 }
 
 # Helper classes used by "open_from_clipboard" target. These classes must have
@@ -46,9 +44,7 @@
     "clipboard_recent_content_impl_ios.h",
     "clipboard_recent_content_impl_ios.mm",
   ]
-  deps = [
-    "//base",
-  ]
+  deps = [ "//base" ]
   assert_no_deps = [ "//base:i18n" ]
   if (is_ios) {
     configs += [ "//build/config/compiler:enable_arc" ]
@@ -74,9 +70,7 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "clipboard_recent_content_ios_unittest.mm",
-  ]
+  sources = [ "clipboard_recent_content_ios_unittest.mm" ]
 
   deps = [
     ":open_from_clipboard",
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index c0e023c..65e268c 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -367,12 +367,8 @@
     "generation/password_generator.cc",
     "generation/password_generator.h",
   ]
-  public_deps = [
-    "//components/autofill/core/browser/proto",
-  ]
-  deps = [
-    "//base",
-  ]
+  public_deps = [ "//components/autofill/core/browser/proto" ]
+  deps = [ "//base" ]
 }
 
 if (is_android) {
@@ -385,9 +381,7 @@
 }
 
 fuzzable_proto_library("proto") {
-  sources = [
-    "android_affiliation/affiliation_api.proto",
-  ]
+  sources = [ "android_affiliation/affiliation_api.proto" ]
 }
 
 jumbo_static_library("password_hash_data") {
@@ -506,10 +500,8 @@
     "//components/test/data/password_manager/login_db_v9.sql",
     "//components/test/data/password_manager/login_db_v9_without_use_additional_auth_field.sql",
   ]
-  outputs = [
-    "{{bundle_resources_dir}}/" +
-        "{{source_root_relative_dir}}/{{source_file_part}}",
-  ]
+  outputs = [ "{{bundle_resources_dir}}/" +
+              "{{source_root_relative_dir}}/{{source_file_part}}" ]
 }
 
 source_set("unit_tests") {
@@ -660,9 +652,7 @@
 }
 
 fuzzer_test("csv_reader_fuzzer") {
-  sources = [
-    "import/password_csv_reader_fuzzer.cc",
-  ]
+  sources = [ "import/password_csv_reader_fuzzer.cc" ]
   deps = [
     ":browser",
     ":csv",
@@ -675,9 +665,8 @@
 
 if (use_libfuzzer) {
   fuzzer_test("lookup_affiliation_response_parser_fuzzer") {
-    sources = [
-      "android_affiliation/lookup_affiliation_response_parser_fuzzer.cc",
-    ]
+    sources =
+        [ "android_affiliation/lookup_affiliation_response_parser_fuzzer.cc" ]
     deps = [
       ":browser",
       ":proto",
@@ -688,9 +677,7 @@
   }
 
   fuzzer_test("password_generator_proto_fuzzer") {
-    sources = [
-      "generation/password_generator_proto_fuzzer.cc",
-    ]
+    sources = [ "generation/password_generator_proto_fuzzer.cc" ]
     deps = [
       ":password_generator",
       "//components/autofill/core/browser/proto",
@@ -720,9 +707,7 @@
 
 source_set("affiliation_unittests") {
   testonly = true
-  sources = [
-    "android_affiliation/affiliation_utils_unittest.cc",
-  ]
+  sources = [ "android_affiliation/affiliation_utils_unittest.cc" ]
   deps = [
     ":affiliation",
     "//base",
diff --git a/components/password_manager/core/browser/form_parsing/fuzzer/BUILD.gn b/components/password_manager/core/browser/form_parsing/fuzzer/BUILD.gn
index 9f24aff..038e99d 100644
--- a/components/password_manager/core/browser/form_parsing/fuzzer/BUILD.gn
+++ b/components/password_manager/core/browser/form_parsing/fuzzer/BUILD.gn
@@ -44,9 +44,7 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "data_accessor_unittest.cc",
-  ]
+  sources = [ "data_accessor_unittest.cc" ]
 
   deps = [
     ":fuzzer_support",
@@ -68,9 +66,7 @@
 # new fuzzer has the "_generic" suffix on its target name.
 
 fuzzer_test("password_manager_form_parser_fuzzer") {
-  sources = [
-    "form_parser_fuzzer.cc",
-  ]
+  sources = [ "form_parser_fuzzer.cc" ]
 
   deps = [
     ":fuzzer_support",
@@ -84,9 +80,7 @@
 }
 
 fuzzer_test("password_manager_form_parser_proto_fuzzer") {
-  sources = [
-    "form_parser_proto_fuzzer.cc",
-  ]
+  sources = [ "form_parser_proto_fuzzer.cc" ]
 
   deps = [
     ":form_data_essentials_proto",
@@ -103,7 +97,5 @@
 }
 
 proto_library("form_data_essentials_proto") {
-  sources = [
-    "form_data_essentials.proto",
-  ]
+  sources = [ "form_data_essentials.proto" ]
 }
diff --git a/components/password_manager/core/browser/leak_detection/BUILD.gn b/components/password_manager/core/browser/leak_detection/BUILD.gn
index 7c3dc53..608e98d 100644
--- a/components/password_manager/core/browser/leak_detection/BUILD.gn
+++ b/components/password_manager/core/browser/leak_detection/BUILD.gn
@@ -6,9 +6,7 @@
 import("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni")
 
 fuzzable_proto_library("proto") {
-  sources = [
-    "leak_detection_api.proto",
-  ]
+  sources = [ "leak_detection_api.proto" ]
 }
 
 source_set("leak_detection_interface_headers") {
@@ -97,7 +95,5 @@
 }
 
 group("fuzzers") {
-  deps = [
-    "//components/password_manager/core/browser/leak_detection/fuzzer",
-  ]
+  deps = [ "//components/password_manager/core/browser/leak_detection/fuzzer" ]
 }
diff --git a/components/password_manager/core/browser/leak_detection/fuzzer/BUILD.gn b/components/password_manager/core/browser/leak_detection/fuzzer/BUILD.gn
index 323b1db..0b09d14 100644
--- a/components/password_manager/core/browser/leak_detection/fuzzer/BUILD.gn
+++ b/components/password_manager/core/browser/leak_detection/fuzzer/BUILD.gn
@@ -5,18 +5,12 @@
 }
 
 fuzzer_test("cipher_encrypt_fuzzer") {
-  sources = [
-    "cipher_encrypt_fuzzer.cc",
-  ]
-  deps = [
-    "//components/password_manager/core/browser/leak_detection",
-  ]
+  sources = [ "cipher_encrypt_fuzzer.cc" ]
+  deps = [ "//components/password_manager/core/browser/leak_detection" ]
 }
 
 fuzzer_test("cypher_encrypt_with_key_fuzzer") {
-  sources = [
-    "cypher_encrypt_with_key_fuzzer.cc",
-  ]
+  sources = [ "cypher_encrypt_with_key_fuzzer.cc" ]
   deps = [
     "//components/password_manager/core/browser/leak_detection",
     "//third_party/private-join-and-compute/src:ec_commutative_cipher",
@@ -24,18 +18,12 @@
 }
 
 fuzzer_test("cypher_reencrypt_fuzzer") {
-  sources = [
-    "cypher_reencrypt_fuzzer.cc",
-  ]
-  deps = [
-    "//components/password_manager/core/browser/leak_detection",
-  ]
+  sources = [ "cypher_reencrypt_fuzzer.cc" ]
+  deps = [ "//components/password_manager/core/browser/leak_detection" ]
 }
 
 fuzzer_test("cypher_decrypt_fuzzer") {
-  sources = [
-    "cypher_decrypt_fuzzer.cc",
-  ]
+  sources = [ "cypher_decrypt_fuzzer.cc" ]
   deps = [
     "//components/password_manager/core/browser/leak_detection",
     "//third_party/private-join-and-compute/src:ec_commutative_cipher",
diff --git a/components/password_manager/core/common/BUILD.gn b/components/password_manager/core/common/BUILD.gn
index 3aadb38..426e51d 100644
--- a/components/password_manager/core/common/BUILD.gn
+++ b/components/password_manager/core/common/BUILD.gn
@@ -32,9 +32,7 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "credential_manager_types_unittest.cc",
-  ]
+  sources = [ "credential_manager_types_unittest.cc" ]
 
   if (is_ios) {
     sources += [ "passwords_directory_util_ios_unittest.cc" ]
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 1a04f59..400069f 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -643,6 +643,7 @@
         'CursorHighlightEnabled',
         'CaretHighlightEnabled',
         'MonoAudioEnabled',
+        'AccessibilityShortcutsEnabled',
         'AutoclickEnabled',
         'DeviceLoginScreenDefaultLargeCursorEnabled',
         'DeviceLoginScreenDefaultSpokenFeedbackEnabled',
@@ -10302,6 +10303,31 @@
           If this policy is left unset, high contrast mode is disabled initially but can be enabled by the user anytime.'''
     },
     {
+      'name': 'AccessibilityShortcutsEnabled',
+      'owners': ['amraboelkher@chromium.org', 'emaxx@chromium.org'],
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome_os:81-'],
+      'features': {
+        'can_be_recommended': True,
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': True,
+      'id': 659,
+      'caption': '''Enable accessibility features shortcuts''',
+      'tags': [],
+      'desc': '''Enable accessibility features shortcuts.
+
+          If this policy is set to true, accessibility features shortcuts will always be enabled.
+
+          If this policy is set to false, accessibility features shortcuts will always be disabled.
+
+          If you set this policy, users cannot change or override it.
+
+          If this policy is left unset, accessibility features shortcuts will be enabled by default.'''
+    },
+    {
       'name': 'VirtualKeyboardEnabled',
       'owners': ['file://components/policy/resources/OWNERS'],
       'type': 'main',
@@ -20243,6 +20269,6 @@
   ],
   'placeholders': [],
   'deleted_policy_ids': [412, 546, 562, 569, 578],
-  'highest_id_currently_used': 658,
+  'highest_id_currently_used': 659,
   'highest_atomic_group_id_currently_used': 38
 }
diff --git a/components/search_provider_logos/BUILD.gn b/components/search_provider_logos/BUILD.gn
index 5895f9b..b5653a1 100644
--- a/components/search_provider_logos/BUILD.gn
+++ b/components/search_provider_logos/BUILD.gn
@@ -76,10 +76,8 @@
     "//components/test/data/search_provider_logos/ddljson_ios4.json",
     "//components/test/data/search_provider_logos/ddljson_ios4_fp.json",
   ]
-  outputs = [
-    "{{bundle_resources_dir}}/" +
-        "{{source_root_relative_dir}}/{{source_file_part}}",
-  ]
+  outputs = [ "{{bundle_resources_dir}}/" +
+              "{{source_root_relative_dir}}/{{source_file_part}}" ]
 }
 
 source_set("unit_tests") {
diff --git a/components/send_tab_to_self/BUILD.gn b/components/send_tab_to_self/BUILD.gn
index d00fedc..8fc934e 100644
--- a/components/send_tab_to_self/BUILD.gn
+++ b/components/send_tab_to_self/BUILD.gn
@@ -35,9 +35,7 @@
     "//ui/base",
     "//url",
   ]
-  public_deps = [
-    "//components/send_tab_to_self/proto:send_tab_to_self_proto",
-  ]
+  public_deps = [ "//components/send_tab_to_self/proto:send_tab_to_self_proto" ]
   if (is_android) {
     sources += [
       "send_tab_to_self_infobar_delegate.cc",
diff --git a/components/send_tab_to_self/proto/BUILD.gn b/components/send_tab_to_self/proto/BUILD.gn
index afe1e55..52848e8 100644
--- a/components/send_tab_to_self/proto/BUILD.gn
+++ b/components/send_tab_to_self/proto/BUILD.gn
@@ -6,8 +6,6 @@
 
 proto_library("send_tab_to_self_proto") {
   import_dirs = [ "//components/sync/protocol" ]
-  sources = [
-    "send_tab_to_self.proto",
-  ]
+  sources = [ "send_tab_to_self.proto" ]
   link_deps = [ "//components/sync/protocol:protocol" ]
 }
diff --git a/components/services/heap_profiling/BUILD.gn b/components/services/heap_profiling/BUILD.gn
index 8dcbe7d..9b5f6a0 100644
--- a/components/services/heap_profiling/BUILD.gn
+++ b/components/services/heap_profiling/BUILD.gn
@@ -29,9 +29,7 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "json_exporter_unittest.cc",
-  ]
+  sources = [ "json_exporter_unittest.cc" ]
   deps = [
     ":heap_profiling",
     "//base",
diff --git a/components/services/heap_profiling/public/cpp/BUILD.gn b/components/services/heap_profiling/public/cpp/BUILD.gn
index e016a91..4ca629d5b 100644
--- a/components/services/heap_profiling/public/cpp/BUILD.gn
+++ b/components/services/heap_profiling/public/cpp/BUILD.gn
@@ -28,9 +28,7 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [
-    "switches_unittest.cc",
-  ]
+  sources = [ "switches_unittest.cc" ]
   deps = [
     ":cpp",
     "//base",
diff --git a/components/services/heap_profiling/public/mojom/BUILD.gn b/components/services/heap_profiling/public/mojom/BUILD.gn
index bc27caa..ff36fda 100644
--- a/components/services/heap_profiling/public/mojom/BUILD.gn
+++ b/components/services/heap_profiling/public/mojom/BUILD.gn
@@ -9,7 +9,5 @@
     "heap_profiling_client.mojom",
     "heap_profiling_service.mojom",
   ]
-  deps = [
-    "//mojo/public/mojom/base",
-  ]
+  deps = [ "//mojo/public/mojom/base" ]
 }
diff --git a/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.cc b/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.cc
index 5c769973..dbfd1bc 100644
--- a/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.cc
+++ b/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.cc
@@ -10,21 +10,35 @@
 #include "components/signin/internal/identity_manager/account_tracker_service.h"
 #include "components/signin/internal/identity_manager/gaia_cookie_manager_service.h"
 #include "components/signin/public/base/multilogin_parameters.h"
+#include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
 #include "google_apis/gaia/core_account_id.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 
 namespace signin {
 
+AccountsCookieMutatorImpl::MultiloginHelperWrapper::MultiloginHelperWrapper(
+    std::unique_ptr<OAuthMultiloginHelper> helper)
+    : helper_(std::move(helper)) {}
+
+AccountsCookieMutatorImpl::MultiloginHelperWrapper::~MultiloginHelperWrapper() =
+    default;
+
 AccountsCookieMutatorImpl::AccountsCookieMutatorImpl(
+    SigninClient* signin_client,
+    ProfileOAuth2TokenService* token_service,
     GaiaCookieManagerService* gaia_cookie_manager_service,
     AccountTrackerService* account_tracker_service)
-    : gaia_cookie_manager_service_(gaia_cookie_manager_service),
+    : signin_client_(signin_client),
+      token_service_(token_service),
+      gaia_cookie_manager_service_(gaia_cookie_manager_servi