diff --git a/DEPS b/DEPS
index 78f8850c..5102f66d 100644
--- a/DEPS
+++ b/DEPS
@@ -199,7 +199,7 @@
   # 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': 'ce4c3060f6fbfd5ed410de314f7e83a66fd792d9',
+  'v8_revision': '1e0d126cf79ed826bbf944072b5e9bbb0c572bbd',
   # 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.
@@ -207,7 +207,7 @@
   # 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': '38ddebf9a771aef3a906667595354c7a564edf31',
+  'angle_revision': 'e4e2a847dab3512f10f28f212d8f6911336ed069',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -246,7 +246,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': '8b3601324fde1ba49338dd6279057cd366c25919',
+  'freetype_revision': 'f9f6adb625c48ef15b5d61a3ac1709a068ea95a3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
@@ -266,7 +266,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'e794555edb6fe7cd872ea43c25c415e941669b58',
+  'devtools_frontend_revision': '011b0075cd53a71e094bf9dcfc85e553c5ff9c73',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -875,7 +875,7 @@
 
   # Build tools for Chrome OS.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '93bb4f5a94f3e1d8be7b774b1e6d0b683d097bf8',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'f123f22cb971fbd2cdbffcd67ff2b3a9c019f743',
       'condition': 'checkout_chromeos',
   },
 
@@ -1248,7 +1248,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '23c5b63d1c68730cf0a6bb2a904dbd67f288508c',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '9a43f48ed4cd22ec0f6e1436cd88b829a3b99550',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1537,7 +1537,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@171aaf4db08f1c4a372cc3d81e445f22467074bc',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@08a9885983f136f2ae6aa4bcfd3da0634bcf489c',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 6532a0d..9f61883 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -301,7 +301,7 @@
   '^chrome/browser/chromeos/',
   '^chrome/browser/component_updater/',
   '^chrome/browser/custom_handlers/protocol_handler_registry.cc',
-  '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc',
+  '^chrome/browser/device_identity/chromeos/device_oauth2_token_store_chromeos.cc', # pylint: disable=line-too-long
   '^chrome/browser/devtools/',
   '^chrome/browser/download/',
   '^chrome/browser/extensions/',
@@ -313,12 +313,12 @@
   '^chrome/browser/media/',
   '^chrome/browser/metrics/',
   '^chrome/browser/nacl_host/test/gdb_debug_stub_browsertest.cc',
-  '^chrome/browser/nearby_sharing/client/nearby_share_api_call_flow_impl_unittest.cc',
+  '^chrome/browser/nearby_sharing/client/nearby_share_api_call_flow_impl_unittest.cc', # pylint: disable=line-too-long
   '^chrome/browser/net/',
   '^chrome/browser/notifications/',
   '^chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc',
   '^chrome/browser/offline_pages/',
-  '^chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc',
+  '^chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc', # pylint: disable=line-too-long
   '^chrome/browser/password_manager/',
   '^chrome/browser/payments/payment_manifest_parser_browsertest.cc',
   '^chrome/browser/pdf/pdf_extension_test.cc',
@@ -1492,6 +1492,8 @@
   name_pattern = r'ForTest(s|ing)?'
   # Describes an occurrence of "ForTest*" inside a // comment.
   comment_re = input_api.re.compile(r'//.*%s' % name_pattern)
+  # Describes @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+  annotation_re = input_api.re.compile(r'@VisibleForTesting\(otherwise')
   # Catch calls.
   inclusion_re = input_api.re.compile(r'(%s)\s*\(' % name_pattern)
   # Ignore definitions. (Comments are ignored separately.)
@@ -1516,6 +1518,7 @@
         continue
       if (inclusion_re.search(line) and
           not comment_re.search(line) and
+          not annotation_re.search(line) and
           not exclusion_re.search(line)):
         problems.append(
           '%s:%d\n    %s' % (local_path, line_number, line.strip()))
diff --git a/PRESUBMIT_test_mocks.py b/PRESUBMIT_test_mocks.py
index f3e928c..0a9e5a5 100644
--- a/PRESUBMIT_test_mocks.py
+++ b/PRESUBMIT_test_mocks.py
@@ -61,8 +61,6 @@
   """
 
   DEFAULT_FILES_TO_SKIP = ()
-  # TODO(https://crbug.com/1098562): Remove once no longer used)
-  DEFAULT_BLACK_LIST = ()
 
   def __init__(self):
     self.canned_checks = MockCannedChecks()
@@ -95,11 +93,7 @@
     return self.AffectedFiles(file_filter=file_filter)
 
   def FilterSourceFile(self, file,
-                       files_to_check=(), files_to_skip=(),
-                       # TODO(https://crbug.com/1098562): Remove once no longer used
-                       white_list=(), black_list=()):
-    files_to_check = files_to_check or white_list
-    files_to_skip = files_to_skip or black_list
+                       files_to_check=(), files_to_skip=()):
     local_path = file.LocalPath()
     found_in_files_to_check = not files_to_check
     if files_to_check:
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index f6e9de2e..29738095 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -59,6 +59,7 @@
   standalone_system_webview_apk_tmpl("system_webview_base_bundle_module") {
     target_type = "android_app_bundle_module"
     is_base_module = true
+    bundle_target = ":system_webview_bundle"
 
     if (_verify_android_configuration) {
       expected_android_manifest =
@@ -101,6 +102,7 @@
       target_type = "android_app_bundle_module"
       include_64_bit_webview = false
       is_base_module = true
+      bundle_target = ":system_webview_32_bundle"
     }
 
     system_webview_bundle("system_webview_32_bundle") {
@@ -145,6 +147,7 @@
   trichrome_webview_tmpl("trichrome_webview_base_bundle_module") {
     target_type = "android_app_bundle_module"
     is_base_module = true
+    bundle_target = ":trichrome_webview_bundle"
 
     if (_verify_android_configuration) {
       expected_android_manifest =
@@ -225,6 +228,7 @@
     trichrome_webview_64_32_tmpl("trichrome_webview_64_32_base_bundle_module") {
       target_type = "android_app_bundle_module"
       is_base_module = true
+      bundle_target = ":trichrome_webview_64_32_bundle"
     }
 
     system_webview_bundle("trichrome_webview_64_32_bundle") {
@@ -238,6 +242,7 @@
     trichrome_webview_32_64_tmpl("trichrome_webview_32_64_base_bundle_module") {
       target_type = "android_app_bundle_module"
       is_base_module = true
+      bundle_target = ":trichrome_webview_32_64_bundle"
     }
 
     system_webview_bundle("trichrome_webview_32_64_bundle") {
@@ -275,6 +280,7 @@
     trichrome_webview_32_tmpl("trichrome_webview_32_base_bundle_module") {
       target_type = "android_app_bundle_module"
       is_base_module = true
+      bundle_target = ":trichrome_webview_32_bundle"
     }
 
     system_webview_bundle("trichrome_webview_32_bundle") {
diff --git a/android_webview/nonembedded/BUILD.gn b/android_webview/nonembedded/BUILD.gn
index 88b3944e..fbb00eb 100644
--- a/android_webview/nonembedded/BUILD.gn
+++ b/android_webview/nonembedded/BUILD.gn
@@ -140,6 +140,7 @@
     "java/res_devui/layout/crashes_list_item_body.xml",
     "java/res_devui/layout/crashes_list_item_header.xml",
     "java/res_devui/layout/flag_states.xml",
+    "java/res_devui/layout/flag_ui_warning.xml",
     "java/res_devui/layout/fragment_crashes_list.xml",
     "java/res_devui/layout/fragment_flags.xml",
     "java/res_devui/layout/fragment_home.xml",
diff --git a/android_webview/nonembedded/java/res_devui/layout/flag_ui_warning.xml b/android_webview/nonembedded/java/res_devui/layout/flag_ui_warning.xml
new file mode 100644
index 0000000..9367e64e
--- /dev/null
+++ b/android_webview/nonembedded/java/res_devui/layout/flag_ui_warning.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/flag_ui_warning"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp">
+
+    <!--suppress HardcodedText -->
+    <TextView
+        android:id="@+id/flags_warning"
+        android:text="WARNING: EXPERIMENTAL FEATURES AHEAD!"
+        android:textColor="@color/error_red"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="8dp"
+        android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+    <TextView
+        android:id="@+id/flags_description"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+</LinearLayout>
diff --git a/android_webview/nonembedded/java/res_devui/layout/fragment_flags.xml b/android_webview/nonembedded/java/res_devui/layout/fragment_flags.xml
index 69d6c8ad..f8cee00 100644
--- a/android_webview/nonembedded/java/res_devui/layout/fragment_flags.xml
+++ b/android_webview/nonembedded/java/res_devui/layout/fragment_flags.xml
@@ -11,26 +11,8 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:padding="10dp">
-
-    <!--suppress HardcodedText -->
-    <TextView
-        android:id="@+id/flags_warning"
-        android:text="WARNING: EXPERIMENTAL FEATURES AHEAD!"
-        android:textColor="@color/error_red"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingBottom="5dp"
-        android:paddingTop="5dp"
-        android:textAppearance="?android:attr/textAppearanceLarge"/>
-
-    <TextView
-        android:id="@+id/flags_description"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingBottom="5dp"
-        android:paddingTop="5dp"
-        android:textAppearance="?android:attr/textAppearanceMedium"/>
+    android:paddingStart="8dp"
+    android:paddingEnd="8dp">
 
     <!--suppress HardcodedText -->
     <Button
@@ -38,7 +20,8 @@
         android:id="@+id/reset_flags_button"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="5dp"
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="8dp"
         android:textAppearance="?android:attr/textAppearanceMedium"/>
 
     <!-- horizontal divider -->
diff --git a/android_webview/nonembedded/java/res_devui/layout/toggleable_flag.xml b/android_webview/nonembedded/java/res_devui/layout/toggleable_flag.xml
index deedc1c..640cd65d 100644
--- a/android_webview/nonembedded/java/res_devui/layout/toggleable_flag.xml
+++ b/android_webview/nonembedded/java/res_devui/layout/toggleable_flag.xml
@@ -10,7 +10,6 @@
     android:id="@+id/toggleable_flag"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginTop="15dp"
     android:orientation="vertical">
 
     <!-- A compound drawable will be populated at runtime, but it's OK to configure drawablePadding now. -->
@@ -22,8 +21,8 @@
         android:textStyle="bold"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:drawablePadding="4dp"
-        android:paddingBottom="2dp"
-        android:paddingTop="2dp" />
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"/>
 
     <TextView
         android:id="@+id/flag_description"
diff --git a/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/FlagsFragment.java b/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/FlagsFragment.java
index 6112247..cb7b40f 100644
--- a/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/FlagsFragment.java
+++ b/android_webview/nonembedded/java/src/org/chromium/android_webview/devui/FlagsFragment.java
@@ -24,6 +24,9 @@
 import android.widget.Spinner;
 import android.widget.TextView;
 
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+
 import org.chromium.android_webview.common.DeveloperModeUtils;
 import org.chromium.android_webview.common.Flag;
 import org.chromium.android_webview.common.ProductionSupportedFlagList;
@@ -73,10 +76,6 @@
         activity.setTitle("WebView Flags");
 
         ListView flagsListView = view.findViewById(R.id.flags_list);
-        TextView flagsDescriptionView = view.findViewById(R.id.flags_description);
-        flagsDescriptionView.setText("By enabling these features, you could "
-                + "lose app data or compromise your security or privacy. Enabled features apply to "
-                + "WebViews across all apps on the device.");
 
         // Restore flag overrides from the service process to repopulate the UI, if developer mode
         // is enabled.
@@ -84,7 +83,13 @@
             mOverriddenFlags = DeveloperModeUtils.getFlagOverrides(mContext.getPackageName());
         }
 
-        mListAdapter = new FlagsListAdapter(sortFlagList(ProductionSupportedFlagList.sFlagList));
+        Flag[] sortedFlags = sortFlagList(ProductionSupportedFlagList.sFlagList);
+        Flag[] flagsAndWarningText = new Flag[ProductionSupportedFlagList.sFlagList.length + 1];
+        flagsAndWarningText[0] = null; // the first entry is the warning text
+        for (int i = 0; i < ProductionSupportedFlagList.sFlagList.length; i++) {
+            flagsAndWarningText[i + 1] = sortedFlags[i];
+        }
+        mListAdapter = new FlagsListAdapter(flagsAndWarningText);
         flagsListView.setAdapter(mListAdapter);
 
         Button resetFlagsButton = view.findViewById(R.id.reset_flags_button);
@@ -163,16 +168,22 @@
         public void onNothingSelected(AdapterView<?> parent) {}
     }
 
+    @IntDef({LayoutType.WARNING_MESSAGE, LayoutType.TOGGLEABLE_FLAG})
+    private @interface LayoutType {
+        int WARNING_MESSAGE = 0;
+        int TOGGLEABLE_FLAG = 1;
+        int COUNT = 2;
+    }
+
     /**
      * Adapter to create rows of toggleable Flags.
      */
     private class FlagsListAdapter extends ArrayAdapter<Flag> {
-        public FlagsListAdapter(Flag[] sortedFlags) {
-            super(mContext, R.layout.toggleable_flag, sortedFlags);
+        public FlagsListAdapter(Flag[] flagsAndWarningText) {
+            super(mContext, 0, flagsAndWarningText);
         }
 
-        @Override
-        public View getView(int position, View view, ViewGroup parent) {
+        private View getToggleableFlag(@NonNull Flag flag, View view, ViewGroup parent) {
             // If the the old view is already created then reuse it, else create a new one by layout
             // inflation.
             if (view == null) {
@@ -183,7 +194,6 @@
             TextView flagDescription = view.findViewById(R.id.flag_description);
             Spinner flagToggle = view.findViewById(R.id.flag_toggle);
 
-            Flag flag = getItem(position);
             String label = flag.getName();
             if (flag.getEnabledStateValue() != null) {
                 label += "=" + flag.getEnabledStateValue();
@@ -203,6 +213,43 @@
 
             return view;
         }
+
+        private View getWarningMessage(View view, ViewGroup parent) {
+            // If the the old view is already created then reuse it, else create a new one by layout
+            // inflation.
+            if (view == null) {
+                view = getLayoutInflater().inflate(R.layout.flag_ui_warning, null);
+            }
+
+            TextView flagsDescriptionView = view.findViewById(R.id.flags_description);
+            flagsDescriptionView.setText("By enabling these features, you could "
+                    + "lose app data or compromise your security or privacy. Enabled features "
+                    + "apply to WebViews across all apps on the device.");
+
+            return view;
+        }
+
+        @Override
+        @LayoutType
+        public int getItemViewType(int position) {
+            if (getItem(position) == null) return LayoutType.WARNING_MESSAGE;
+            return LayoutType.TOGGLEABLE_FLAG;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return LayoutType.COUNT;
+        }
+
+        @Override
+        public View getView(int position, View view, ViewGroup parent) {
+            Flag flag = getItem(position);
+            if (getItemViewType(position) == LayoutType.WARNING_MESSAGE) {
+                return getWarningMessage(view, parent);
+            } else {
+                return getToggleableFlag(flag, view, parent);
+            }
+        }
     }
 
     /**
diff --git a/ash/login/parent_access_controller.cc b/ash/login/parent_access_controller.cc
index 407b6ea..e18df07 100644
--- a/ash/login/parent_access_controller.cc
+++ b/ash/login/parent_access_controller.cc
@@ -23,6 +23,7 @@
 base::string16 GetTitle(ParentAccessRequestReason reason) {
   int title_id;
   switch (reason) {
+    case ParentAccessRequestReason::kOnlineLogin:
     case ParentAccessRequestReason::kUnlockTimeLimits:
       title_id = IDS_ASH_LOGIN_PARENT_ACCESS_TITLE;
       break;
@@ -39,6 +40,7 @@
 base::string16 GetDescription(ParentAccessRequestReason reason) {
   int description_id;
   switch (reason) {
+    case ParentAccessRequestReason::kOnlineLogin:
     case ParentAccessRequestReason::kUnlockTimeLimits:
       description_id = IDS_ASH_LOGIN_PARENT_ACCESS_DESCRIPTION;
       break;
@@ -71,8 +73,16 @@
                             action);
 }
 
-void RecordParentAccessUsage(ParentAccessRequestReason reason) {
+void RecordParentAccessUsage(const AccountId& child_account_id,
+                             ParentAccessRequestReason reason) {
   switch (reason) {
+    case ParentAccessRequestReason::kOnlineLogin:
+      UMA_HISTOGRAM_ENUMERATION(
+          ParentAccessController::kUMAParentAccessCodeUsage,
+          child_account_id.empty()
+              ? ParentAccessController::UMAUsage::kAddUserLoginScreen
+              : ParentAccessController::UMAUsage::kReauhLoginScreen);
+      return;
     case ParentAccessRequestReason::kUnlockTimeLimits: {
       UMA_HISTOGRAM_ENUMERATION(
           ParentAccessController::kUMAParentAccessCodeUsage,
@@ -160,7 +170,7 @@
   request.description = GetDescription(reason);
   request.accessible_title = GetAccessibleTitle();
   PinRequestWidget::Show(std::move(request), this);
-  RecordParentAccessUsage(reason);
+  RecordParentAccessUsage(account_id_, reason);
   return true;
 }
 
diff --git a/ash/login/parent_access_controller.h b/ash/login/parent_access_controller.h
index 12b6dde..51d39a5 100644
--- a/ash/login/parent_access_controller.h
+++ b/ash/login/parent_access_controller.h
@@ -35,7 +35,9 @@
     kTimeChangeLoginScreen = 1,
     kTimeChangeInSession = 2,
     kTimezoneChange = 3,
-    kMaxValue = kTimezoneChange,
+    kAddUserLoginScreen = 4,
+    kReauhLoginScreen = 5,
+    kMaxValue = kReauhLoginScreen,
   };
 
   // Histogram to log actions that originated in parent access dialog.
diff --git a/ash/login/parent_access_controller_unittest.cc b/ash/login/parent_access_controller_unittest.cc
index 7d7dd3e..b7568d2 100644
--- a/ash/login/parent_access_controller_unittest.cc
+++ b/ash/login/parent_access_controller_unittest.cc
@@ -57,9 +57,14 @@
 
   void StartParentAccess(ParentAccessRequestReason reason =
                              ParentAccessRequestReason::kUnlockTimeLimits) {
+    StartParentAccess(account_id_, reason);
+  }
+
+  void StartParentAccess(const AccountId& account_id,
+                         ParentAccessRequestReason reason) {
     validation_time_ = base::Time::Now();
     controller_->ShowWidget(
-        account_id_,
+        account_id,
         base::BindOnce(&ParentAccessControllerTest::OnFinished,
                        base::Unretained(this)),
         reason, false, validation_time_);
@@ -182,9 +187,29 @@
   ExpectUMAActionReported(ParentAccessController::UMAAction::kCanceledByUser, 5,
                           5);
 
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::LOGIN_PRIMARY);
+  StartParentAccess(ParentAccessRequestReason::kOnlineLogin);
+  histogram_tester_.ExpectBucketCount(
+      ParentAccessController::kUMAParentAccessCodeUsage,
+      ParentAccessController::UMAUsage::kReauhLoginScreen, 1);
+  SimulateButtonPress(PinRequestView::TestApi(view_).back_button());
+  ExpectUMAActionReported(ParentAccessController::UMAAction::kCanceledByUser, 6,
+                          6);
+
+  GetSessionControllerClient()->SetSessionState(
+      session_manager::SessionState::LOGIN_PRIMARY);
+  StartParentAccess(EmptyAccountId(), ParentAccessRequestReason::kOnlineLogin);
+  histogram_tester_.ExpectBucketCount(
+      ParentAccessController::kUMAParentAccessCodeUsage,
+      ParentAccessController::UMAUsage::kAddUserLoginScreen, 1);
+  SimulateButtonPress(PinRequestView::TestApi(view_).back_button());
+  ExpectUMAActionReported(ParentAccessController::UMAAction::kCanceledByUser, 7,
+                          7);
+
   histogram_tester_.ExpectTotalCount(
-      ParentAccessController::kUMAParentAccessCodeUsage, 5);
-  EXPECT_EQ(5, back_action_);
+      ParentAccessController::kUMAParentAccessCodeUsage, 7);
+  EXPECT_EQ(7, back_action_);
 }
 
 // Tests successful parent access validation flow.
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 9f1d001..5b456c99 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -55,6 +55,7 @@
 #include "chromeos/components/proximity_auth/public/mojom/auth_type.mojom.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
+#include "components/user_manager/known_user.h"
 #include "components/user_manager/user_type.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -932,6 +933,8 @@
   }
 
   state->show_pin = enabled;
+  state->autosubmit_pin_length =
+      user_manager::known_user::GetUserPinLength(user);
 
   LoginBigUserView* big_user =
       TryToFindBigUser(user, true /*require_auth_active*/);
@@ -1773,7 +1776,7 @@
       UserState* state = FindStateForUser(
           view->auth_user()->current_user().basic_user_info.account_id);
       uint32_t to_update_auth;
-      bool show_pinpad = false;
+      LoginAuthUserView::AuthMethodsMetadata auth_metadata;
       if (state->force_online_sign_in) {
         to_update_auth = LoginAuthUserView::AUTH_ONLINE_SIGN_IN;
       } else if (state->disable_auth) {
@@ -1788,10 +1791,10 @@
         // visible, but the keyboard is in a different root window or the view
         // has not been added to the widget. In these cases, the keyboard does
         // not interfere with PIN entry.
-        const bool is_keyboard_visible_for_view =
+        auth_metadata.virtual_keyboard_visible =
             GetKeyboardControllerForView() ? keyboard_shown_ : false;
-        show_pinpad = !is_keyboard_visible_for_view &&
-                      (state->show_pin || state->show_pin_pad_for_password);
+        auth_metadata.show_pinpad_for_pw = state->show_pin_pad_for_password;
+        auth_metadata.autosubmit_pin_length = state->autosubmit_pin_length;
         if (state->show_pin)
           to_update_auth |= LoginAuthUserView::AUTH_PIN;
         if (state->enable_tap_auth)
@@ -1799,7 +1802,7 @@
         if (state->fingerprint_state != FingerprintState::UNAVAILABLE)
           to_update_auth |= LoginAuthUserView::AUTH_FINGERPRINT;
       }
-      view->auth_user()->SetAuthMethods(to_update_auth, show_pinpad);
+      view->auth_user()->SetAuthMethods(to_update_auth, auth_metadata);
     } else if (view->public_account()) {
       view->public_account()->SetAuthEnabled(true /*enabled*/, animate);
     }
@@ -1809,8 +1812,7 @@
     if (!view)
       return;
     if (view->auth_user()) {
-      view->auth_user()->SetAuthMethods(LoginAuthUserView::AUTH_NONE,
-                                        false /*show_pinpad*/);
+      view->auth_user()->SetAuthMethods(LoginAuthUserView::AUTH_NONE);
     } else if (view->public_account()) {
       view->public_account()->SetAuthEnabled(false /*enabled*/, animate);
     }
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 37d68ed..750e493c 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -248,6 +248,7 @@
     bool force_online_sign_in = false;
     bool disable_auth = false;
     bool show_pin_pad_for_password = false;
+    size_t autosubmit_pin_length = 0;
     base::Optional<EasyUnlockIconOptions> easy_unlock_state;
     FingerprintState fingerprint_state;
 
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 875560a..c358846 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -745,8 +745,8 @@
     non_pin_y_start_in_screen = view->GetBoundsInScreen().y();
     pin_start_in_screen = view->pin_view_->GetBoundsInScreen().origin();
 
-    had_pinpad = view->show_pinpad_;
-    had_password = view->HasAuthMethod(LoginAuthUserView::AUTH_PASSWORD);
+    had_pinpad = view->ShouldShowPinPad();
+    had_password = view->ShouldShowPasswordField();
     had_fingerprint = view->HasAuthMethod(LoginAuthUserView::AUTH_FINGERPRINT);
   }
 
@@ -978,21 +978,23 @@
   add_padding(kDistanceFromPinKeyboardToBigUserViewBottomDp);
 
   // Update authentication UI.
-  SetAuthMethods(auth_methods_, false /*show_pinpad*/);
+  SetAuthMethods(auth_methods_);
   user_view_->UpdateForUser(user, false /*animate*/);
 }
 
 LoginAuthUserView::~LoginAuthUserView() = default;
 
 void LoginAuthUserView::SetAuthMethods(uint32_t auth_methods,
-                                       bool show_pinpad) {
-  show_pinpad_ = show_pinpad;
+                                       AuthMethodsMetadata auth_metadata) {
   bool had_password = HasAuthMethod(AUTH_PASSWORD);
 
+  // Apply changes and determine the new state of input fields.
   auth_methods_ = static_cast<AuthMethods>(auth_methods);
-  bool has_password = HasAuthMethod(AUTH_PASSWORD);
-  bool has_pin = HasAuthMethod(AUTH_PIN);
-  bool has_tap = HasAuthMethod(AUTH_TAP);
+  auth_metadata_ = auth_metadata;
+  UpdateInputFieldMode();
+
+  bool has_password = ShouldShowPasswordField();
+  bool has_pinpad = ShouldShowPinPad();
   bool force_online_sign_in = HasAuthMethod(AUTH_ONLINE_SIGN_IN);
   bool has_fingerprint = HasAuthMethod(AUTH_FINGERPRINT);
   bool has_challenge_response = HasAuthMethod(AUTH_CHALLENGE_RESPONSE);
@@ -1008,10 +1010,10 @@
   // Adjust the PIN keyboard visibility before the password textfield's one, so
   // that when both are about to be hidden the focus doesn't jump to the "1"
   // keyboard button, causing unexpected accessibility effects.
-  pin_view_->SetVisible(show_pinpad);
+  pin_view_->SetVisible(has_pinpad);
 
   password_view_->SetEnabled(has_password);
-  password_view_->SetEnabledOnEmptyPassword(has_tap);
+  password_view_->SetEnabledOnEmptyPassword(HasAuthMethod(AUTH_TAP));
   password_view_->SetFocusEnabledForChildViews(has_password);
   password_view_->SetVisible(!hide_auth && has_password);
   password_view_->layer()->SetOpacity(has_password ? 1 : 0);
@@ -1021,31 +1023,20 @@
     password_view_->RequestFocus();
 
   fingerprint_view_->SetVisible(has_fingerprint);
-  fingerprint_view_->SetCanUsePin(has_pin);
+  fingerprint_view_->SetCanUsePin(HasAuthMethod(AUTH_PIN));
   challenge_response_view_->SetVisible(has_challenge_response);
 
   int padding_view_height = kDistanceBetweenPasswordFieldAndPinKeyboardDp;
-  if (has_fingerprint && !show_pinpad) {
+  if (has_fingerprint && !has_pinpad) {
     padding_view_height = kDistanceBetweenPasswordFieldAndFingerprintViewDp;
-  } else if (has_challenge_response && !show_pinpad) {
+  } else if (has_challenge_response && !has_pinpad) {
     padding_view_height =
         kDistanceBetweenPasswordFieldAndChallengeResponseViewDp;
   }
   padding_below_password_view_->SetPreferredSize(
       gfx::Size(kNonEmptyWidthDp, padding_view_height));
 
-  // Note: |has_tap| must have higher priority than |has_pin| when
-  // determining the placeholder.
-  if (has_tap) {
-    password_view_->SetPlaceholderText(
-        l10n_util::GetStringUTF16(IDS_ASH_LOGIN_POD_PASSWORD_TAP_PLACEHOLDER));
-  } else if (has_pin) {
-    password_view_->SetPlaceholderText(
-        l10n_util::GetStringUTF16(IDS_ASH_LOGIN_POD_PASSWORD_PIN_PLACEHOLDER));
-  } else {
-    password_view_->SetPlaceholderText(
-        l10n_util::GetStringUTF16(IDS_ASH_LOGIN_POD_PASSWORD_PLACEHOLDER));
-  }
+  password_view_->SetPlaceholderText(GetPasswordViewPlaceholder());
   const std::string& user_display_email =
       current_user().basic_user_info.display_email;
   password_view_->SetAccessibleName(l10n_util::GetStringFUTF16(
@@ -1055,8 +1046,8 @@
   // Only the active auth user view has a password displayed. If that is the
   // case, then render the user view as if it was always focused, since clicking
   // on it will not do anything (such as swapping users).
-  user_view_->SetForceOpaque(has_password || hide_auth);
-  user_view_->SetTapEnabled(!has_password);
+  user_view_->SetForceOpaque(HasAuthMethod(AUTH_PASSWORD) || hide_auth);
+  user_view_->SetTapEnabled(!HasAuthMethod(AUTH_PASSWORD));
   // Tapping the user view will trigger the online sign-in flow when
   // |force_online_sign_in| is true.
   if (force_online_sign_in)
@@ -1105,8 +1096,9 @@
 void LoginAuthUserView::ApplyAnimationPostLayout() {
   DCHECK(cached_animation_state_);
 
-  bool has_password = HasAuthMethod(AUTH_PASSWORD);
-  bool has_pinpad = show_pinpad_;
+  bool has_password = ShouldShowPasswordField();
+  bool had_password = cached_animation_state_->had_password;
+  bool has_pinpad = ShouldShowPinPad();
   bool has_fingerprint = HasAuthMethod(AUTH_FINGERPRINT);
 
   ////////
@@ -1139,12 +1131,12 @@
   ////////
   // Fade the password view if it is being hidden or shown.
 
-  if (cached_animation_state_->had_password != has_password) {
+  if (had_password != has_password) {
     float opacity_start = 0, opacity_end = 1;
     if (!has_password)
       std::swap(opacity_start, opacity_end);
 
-    if (cached_animation_state_->had_password)
+    if (had_password)
       password_view_->SetVisible(true);
 
     password_view_->layer()->SetOpacity(opacity_start);
@@ -1155,7 +1147,7 @@
       settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
           login_constants::kChangeUserAnimationDurationMs));
       settings.SetTweenType(gfx::Tween::Type::FAST_OUT_SLOW_IN);
-      if (cached_animation_state_->had_password && !has_password) {
+      if (had_password && !has_password) {
         settings.AddObserver(
             new ClearPasswordAndHideAnimationObserver(password_view_));
       }
@@ -1361,4 +1353,49 @@
                          weak_factory_.GetWeakPtr()));
 }
 
+void LoginAuthUserView::UpdateInputFieldMode() {
+  if (!HasAuthMethod(AUTH_PASSWORD)) {
+    input_field_mode_ = InputFieldMode::DISABLED;
+    return;
+  }
+  if (!HasAuthMethod(AUTH_PIN)) {
+    input_field_mode_ = InputFieldMode::PASSWORD_ONLY;
+    return;
+  }
+
+  input_field_mode_ = InputFieldMode::PIN_AND_PASSWORD;
+  return;
+}
+
+bool LoginAuthUserView::ShouldShowPinPad() const {
+  if (auth_metadata_.virtual_keyboard_visible)
+    return false;
+  switch (input_field_mode_) {
+    case InputFieldMode::DISABLED:
+      return false;
+    case InputFieldMode::PASSWORD_ONLY:
+      return auth_metadata_.show_pinpad_for_pw;
+    case InputFieldMode::PIN_AND_PASSWORD:
+      return true;
+  }
+}
+
+bool LoginAuthUserView::ShouldShowPasswordField() const {
+  return input_field_mode_ == InputFieldMode::PASSWORD_ONLY ||
+         input_field_mode_ == InputFieldMode::PIN_AND_PASSWORD;
+}
+
+base::string16 LoginAuthUserView::GetPasswordViewPlaceholder() const {
+  // Note: |AUTH_TAP| must have higher priority than |AUTH_PIN| when
+  // determining the placeholder.
+  if (HasAuthMethod(AUTH_TAP))
+    return l10n_util::GetStringUTF16(
+        IDS_ASH_LOGIN_POD_PASSWORD_TAP_PLACEHOLDER);
+  if (input_field_mode_ == InputFieldMode::PIN_AND_PASSWORD)
+    return l10n_util::GetStringUTF16(
+        IDS_ASH_LOGIN_POD_PASSWORD_PIN_PLACEHOLDER);
+
+  return l10n_util::GetStringUTF16(IDS_ASH_LOGIN_POD_PASSWORD_PLACEHOLDER);
+}
+
 }  // namespace ash
diff --git a/ash/login/ui/login_auth_user_view.h b/ash/login/ui/login_auth_user_view.h
index 33aca56..e38ff89 100644
--- a/ash/login/ui/login_auth_user_view.h
+++ b/ash/login/ui/login_auth_user_view.h
@@ -53,6 +53,26 @@
                              // message to user.
   };
 
+  // Extra control parameters to be passed when setting the auth methods.
+  struct AuthMethodsMetadata {
+    explicit AuthMethodsMetadata() {}
+    // If the virtual keyboard is visible, the pinpad is hidden.
+    bool virtual_keyboard_visible = false;
+    // Whether to show the pinpad for the password field.
+    bool show_pinpad_for_pw = false;
+    // User's pin length to use for autosubmit.
+    size_t autosubmit_pin_length = 0;
+  };
+
+  // Possible states that the input field might be in.
+  // This is determined by the current authentication methods
+  // that a user has.
+  enum class InputFieldMode {
+    DISABLED,          // Not showing any input field.
+    PASSWORD_ONLY,     // No PIN set. Password only field.
+    PIN_AND_PASSWORD,  // PIN set.
+  };
+
   // TestApi is used for tests to get internal implementation details.
   class ASH_EXPORT TestApi {
    public:
@@ -104,10 +124,13 @@
   ~LoginAuthUserView() override;
 
   // Set the displayed set of auth methods. |auth_methods| contains or-ed
-  // together AuthMethod values. |show_pinpad| determines whether the pin pad
-  // should be visible.
-  void SetAuthMethods(uint32_t auth_methods, bool show_pinpad);
+  // together AuthMethod values. |auth_metadata| provides additional control
+  // parameters for the view.
+  void SetAuthMethods(
+      uint32_t auth_methods,
+      AuthMethodsMetadata auth_metadata = AuthMethodsMetadata());
   AuthMethods auth_methods() const { return auth_methods_; }
+  InputFieldMode input_field_mode() const { return input_field_mode_; }
 
   // Add an easy unlock icon.
   void SetEasyUnlockIcon(EasyUnlockIconId id,
@@ -183,10 +206,24 @@
   // starts the asynchronous authentication process against a security token.
   void AttemptAuthenticateWithChallengeResponse();
 
-  AuthMethods auth_methods_ = AUTH_NONE;
+  // Determines the mode of the input field based on the available
+  // authentication methods.
+  void UpdateInputFieldMode();
 
-  // Whether to show the pinpad. Sometimes hidden by the on screen keyboard
-  bool show_pinpad_ = false;
+  // Convenience methods to determine element visibility.
+  bool ShouldShowPinPad() const;
+  bool ShouldShowPasswordField() const;
+
+  // Convenience methods to determine UI text based on the InputFieldMode.
+  base::string16 GetPasswordViewPlaceholder() const;
+
+  // Authentication methods available and extra parameters that control the UI.
+  AuthMethods auth_methods_ = AUTH_NONE;
+  AuthMethodsMetadata auth_metadata_ = AuthMethodsMetadata();
+
+  // Controls which input field is currently being shown.
+  InputFieldMode input_field_mode_ = InputFieldMode::DISABLED;
+
   LoginUserView* user_view_ = nullptr;
   LoginPasswordView* password_view_ = nullptr;
   NonAccessibleView* password_view_container_ = nullptr;
diff --git a/ash/login/ui/login_auth_user_view_unittest.cc b/ash/login/ui/login_auth_user_view_unittest.cc
index cc3f8d2..1f8ea15d 100644
--- a/ash/login/ui/login_auth_user_view_unittest.cc
+++ b/ash/login/ui/login_auth_user_view_unittest.cc
@@ -57,8 +57,15 @@
     SetWidget(CreateWidgetWithContent(container_));
   }
 
-  void SetAuthMethods(uint32_t auth_methods, bool show_pinpad) {
-    view_->SetAuthMethods(auth_methods, show_pinpad);
+  void SetAuthMethods(uint32_t auth_methods,
+                      bool show_pinpad_for_pw = false,
+                      bool virtual_keyboard_visible = false,
+                      size_t autosubmit_pin_length = 0) {
+    LoginAuthUserView::AuthMethodsMetadata auth_metadata;
+    auth_metadata.show_pinpad_for_pw = show_pinpad_for_pw;
+    auth_metadata.virtual_keyboard_visible = virtual_keyboard_visible;
+    auth_metadata.autosubmit_pin_length = autosubmit_pin_length;
+    view_->SetAuthMethods(auth_methods, auth_metadata);
   }
 
   LoginUserInfo user_;
@@ -74,7 +81,8 @@
 // Verifies showing the PIN keyboard makes the user view grow.
 TEST_F(LoginAuthUserViewUnittest, ShowingPinExpandsView) {
   gfx::Size start_size = view_->size();
-  SetAuthMethods(LoginAuthUserView::AUTH_PIN, true /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD |
+                 LoginAuthUserView::AUTH_PIN);
   container_->Layout();
   gfx::Size expanded_size = view_->size();
   EXPECT_GT(expanded_size.height(), start_size.height());
@@ -94,11 +102,11 @@
   EXPECT_FALSE(auth_test.user_view()->HasFocus());
 
   // If the user view is showing a password it must be opaque.
-  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD, false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD);
   EXPECT_TRUE(user_test.is_opaque());
-  SetAuthMethods(LoginAuthUserView::AUTH_NONE, false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_NONE);
   EXPECT_FALSE(user_test.is_opaque());
-  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD, false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD);
   EXPECT_TRUE(user_test.is_opaque());
 }
 
@@ -118,8 +126,8 @@
   EXPECT_CALL(*client,
               AuthenticateUserWithEasyUnlock(
                   user_view->current_user().basic_user_info.account_id));
-  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD | LoginAuthUserView::AUTH_TAP,
-                 false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD |
+                 LoginAuthUserView::AUTH_TAP);
   password_view->Clear();
 
   generator->PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
@@ -137,7 +145,7 @@
 
   // When auth method is |AUTH_ONLINE_SIGN_IN|, the online sign-in message is
   // visible. The password field and PIN keyboard are invisible.
-  SetAuthMethods(LoginAuthUserView::AUTH_ONLINE_SIGN_IN, false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_ONLINE_SIGN_IN);
   EXPECT_TRUE(online_sign_in_message->GetVisible());
   EXPECT_FALSE(password_view->GetVisible());
   EXPECT_FALSE(pin_view->GetVisible());
@@ -152,13 +160,13 @@
   base::RunLoop().RunUntilIdle();
 
   // The online sign-in message is invisible for all other auth methods.
-  SetAuthMethods(LoginAuthUserView::AUTH_NONE, false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_NONE);
   EXPECT_FALSE(online_sign_in_message->GetVisible());
-  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD, false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD);
   EXPECT_FALSE(online_sign_in_message->GetVisible());
-  SetAuthMethods(LoginAuthUserView::AUTH_PIN, true /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_PIN);
   EXPECT_FALSE(online_sign_in_message->GetVisible());
-  SetAuthMethods(LoginAuthUserView::AUTH_TAP, false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_TAP);
   EXPECT_FALSE(online_sign_in_message->GetVisible());
 }
 
@@ -171,20 +179,20 @@
   };
 
   // Set a password.
-  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD, false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD);
   password_test.textfield()->SetText(base::ASCIIToUTF16("Hello"));
 
   // Enable some other auth method (PIN), password is not cleared.
   view_->CaptureStateForAnimationPreLayout();
-  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD | LoginAuthUserView::AUTH_PIN,
-                 true /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_PASSWORD |
+                 LoginAuthUserView::AUTH_PIN);
   EXPECT_TRUE(has_password());
   view_->ApplyAnimationPostLayout();
   EXPECT_TRUE(has_password());
 
   // Disable password, password is cleared.
   view_->CaptureStateForAnimationPreLayout();
-  SetAuthMethods(LoginAuthUserView::AUTH_NONE, false /*show_pinpad*/);
+  SetAuthMethods(LoginAuthUserView::AUTH_NONE);
   EXPECT_TRUE(has_password());
   view_->ApplyAnimationPostLayout();
   EXPECT_FALSE(has_password());
diff --git a/ash/public/cpp/login_types.h b/ash/public/cpp/login_types.h
index ddeeb36..140f743a 100644
--- a/ash/public/cpp/login_types.h
+++ b/ash/public/cpp/login_types.h
@@ -341,6 +341,8 @@
   kChangeTime,
   // Update values on the timezone settings page.
   kChangeTimezone,
+  // Online login flow.
+  kOnlineLogin,
 };
 
 // Parameters and callbacks for a security token PIN request that is to be shown
diff --git a/base/BUILD.gn b/base/BUILD.gn
index e4ca016c..0b0f01a 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2122,6 +2122,7 @@
       "trace_event/trace_config.h",
       "trace_event/trace_config_category_filter.cc",
       "trace_event/trace_config_category_filter.h",
+      "trace_event/trace_conversion_helper.h",
       "trace_event/trace_event.h",
       "trace_event/trace_event_filter.cc",
       "trace_event/trace_event_filter.h",
@@ -3318,6 +3319,7 @@
       "trace_event/trace_arguments_unittest.cc",
       "trace_event/trace_category_unittest.cc",
       "trace_event/trace_config_unittest.cc",
+      "trace_event/trace_conversion_helper_unittest.cc",
       "trace_event/trace_event_filter_test_utils.cc",
       "trace_event/trace_event_filter_test_utils.h",
       "trace_event/trace_event_unittest.cc",
diff --git a/base/PRESUBMIT.py b/base/PRESUBMIT.py
index 03030415..33ec547 100644
--- a/base/PRESUBMIT.py
+++ b/base/PRESUBMIT.py
@@ -43,10 +43,10 @@
     r'^#include "base/trace_event/(?!base_tracing\.h)',
   ]
 
-  white_list = [
+  files_to_check = [
     r".*\.(h|cc|mm)$",
   ]
-  black_list = [
+  files_to_skip = [
     r".*[\\/]test[\\/].*",
     r".*[\\/]trace_event[\\/].*",
     r".*[\\/]tracing[\\/].*",
@@ -56,8 +56,8 @@
   def FilterFile(affected_file):
     return input_api.FilterSourceFile(
       affected_file,
-      white_list=white_list,
-      black_list=black_list)
+      files_to_check=files_to_check,
+      files_to_skip=files_to_skip)
 
   locations = []
   for f in input_api.AffectedSourceFiles(FilterFile):
diff --git a/base/android/java/src/org/chromium/base/IntentUtils.java b/base/android/java/src/org/chromium/base/IntentUtils.java
index 70c20c9..8e64fbd 100644
--- a/base/android/java/src/org/chromium/base/IntentUtils.java
+++ b/base/android/java/src/org/chromium/base/IntentUtils.java
@@ -365,7 +365,6 @@
      * Creates a temporary copy of the extra Bundle, which is required as
      * Intent#getBinderExtra() doesn't exist, but Bundle.getBinder() does.
      */
-    @VisibleForTesting
     public static IBinder safeGetBinderExtra(Intent intent, String name) {
         if (!intent.hasExtra(name)) return null;
         Bundle extras = intent.getExtras();
@@ -381,7 +380,6 @@
      * @param name Key.
      * @param binder Binder object.
      */
-    @VisibleForTesting
     public static void safePutBinderExtra(Intent intent, String name, IBinder binder) {
         if (intent == null) return;
         Bundle bundle = new Bundle();
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
index fd499992..b81c04f 100644
--- a/base/android/java/src/org/chromium/base/ThreadUtils.java
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -8,8 +8,6 @@
 import android.os.Looper;
 import android.os.Process;
 
-import androidx.annotation.VisibleForTesting;
-
 import org.chromium.base.annotations.CalledByNative;
 
 import java.util.concurrent.Callable;
@@ -174,7 +172,6 @@
      * @return The result of the callable
      */
     @Deprecated
-    @VisibleForTesting
     public static <T> T runOnUiThreadBlockingNoException(Callable<T> c) {
         try {
             return runOnUiThreadBlocking(c);
@@ -310,7 +307,6 @@
      * @param task The Runnable to run
      * @param delayMillis The delay in milliseconds until the Runnable will be run
      */
-    @VisibleForTesting
     @Deprecated
     public static void postOnUiThreadDelayed(Runnable task, long delayMillis) {
         getUiThreadHandler().postDelayed(task, delayMillis);
diff --git a/base/debug/elf_reader_unittest.cc b/base/debug/elf_reader_unittest.cc
index 5226d89..5cba8948 100644
--- a/base/debug/elf_reader_unittest.cc
+++ b/base/debug/elf_reader_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/debug/test_elf_image_builder.h"
 #include "base/files/memory_mapped_file.h"
 #include "base/native_library.h"
-#include "base/notreached.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -162,10 +161,6 @@
     case TestElfImageBuilder::NON_RELOCATABLE:
       EXPECT_EQ(0u, GetRelocationOffset(image.elf_start()));
       break;
-
-    default:
-      NOTREACHED();
-      break;
   }
 }
 
diff --git a/base/trace_event/trace_conversion_helper.h b/base/trace_event/trace_conversion_helper.h
new file mode 100644
index 0000000..44b84aa
--- /dev/null
+++ b/base/trace_event/trace_conversion_helper.h
@@ -0,0 +1,111 @@
+// 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 BASE_TRACE_EVENT_TRACE_CONVERSION_HELPER_H_
+#define BASE_TRACE_EVENT_TRACE_CONVERSION_HELPER_H_
+
+#include <sstream>
+#include <string>
+
+#include "base/strings/string_number_conversions.h"
+
+namespace base {
+
+namespace trace_event {
+
+// Helpers for base::trace_event::ValueToString.
+namespace internal {
+
+// Return std::string representation given by |value|'s ostream operator<<.
+template <typename ValueType>
+std::string OstreamValueToString(const ValueType& value) {
+  std::stringstream ss;
+  ss << value;
+  return ss.str();
+}
+
+// Helper class to mark call priority. Lower number has precedence:
+//
+// Example:
+//   void foo(ValueToStringPriority<1>);
+//   void foo(ValueToStringPriority<3>);
+//   foo(ValueToStringPriority<0>());  // Calls |foo(ValueToStringPriority<1>)|.
+template <int N>
+class ValueToStringPriority : public ValueToStringPriority<N + 1> {};
+template <>
+// The number must be the same as in the fallback version of
+// |ValueToStringHelper|.
+class ValueToStringPriority<4> {};
+
+// Use SFINAE to decide how to extract a string from the given parameter.
+
+// Check if |value| can be used as a parameter of |base::NumberToString|. If
+// std::string is not constructible from the returned value of
+// |base::NumberToString| cause compilation error.
+//
+// |base::NumberToString| does not do locale specific formatting and should be
+// faster than using |std::ostream::operator<<|.
+template <typename ValueType>
+decltype(base::NumberToString(std::declval<const ValueType>()), std::string())
+ValueToStringHelper(ValueToStringPriority<0>,
+                    const ValueType& value,
+                    std::string /* unused */) {
+  return base::NumberToString(value);
+}
+
+// If there is |ValueType::ToString| whose return value can be used to construct
+// |std::string|, use this. Else use other methods.
+template <typename ValueType>
+decltype(std::string(std::declval<const ValueType>().ToString()))
+ValueToStringHelper(ValueToStringPriority<1>,
+                    const ValueType& value,
+                    std::string /* unused */) {
+  return value.ToString();
+}
+
+// If |std::ostream::operator<<| can be used, use it. Useful for |void*|.
+template <typename ValueType>
+decltype(
+    std::declval<std::ostream>().operator<<(std::declval<const ValueType>()),
+    std::string())
+ValueToStringHelper(ValueToStringPriority<2>,
+                    const ValueType& value,
+                    std::string /* unused */) {
+  return OstreamValueToString(value);
+}
+
+// Use |ValueType::operator<<| if applicable.
+template <typename ValueType>
+decltype(operator<<(std::declval<std::ostream&>(),
+                    std::declval<const ValueType>()),
+         std::string())
+ValueToStringHelper(ValueToStringPriority<3>,
+                    const ValueType& value,
+                    std::string /* unused */) {
+  return OstreamValueToString(value);
+}
+
+// Fallback returns the |fallback_value|. Needs to have |ValueToStringPriority|
+// with the highest number (to be called last).
+template <typename ValueType>
+std::string ValueToStringHelper(ValueToStringPriority<4>,
+                                const ValueType& /* unused */,
+                                std::string fallback_value) {
+  return fallback_value;
+}
+
+}  // namespace internal
+
+// The function to be used.
+template <typename ValueType>
+std::string ValueToString(const ValueType& value,
+                          std::string fallback_value = "<value>") {
+  return internal::ValueToStringHelper(internal::ValueToStringPriority<0>(),
+                                       value, std::move(fallback_value));
+}
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_CONVERSION_HELPER_H_
diff --git a/base/trace_event/trace_conversion_helper_unittest.cc b/base/trace_event/trace_conversion_helper_unittest.cc
new file mode 100644
index 0000000..c7fd7e0a
--- /dev/null
+++ b/base/trace_event/trace_conversion_helper_unittest.cc
@@ -0,0 +1,113 @@
+// 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 "base/trace_event/trace_conversion_helper.h"
+
+#include <stddef.h>
+
+#include <utility>
+
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(TraceEventConversionHelperTest, OstreamValueToString) {
+  std::string zero = internal::OstreamValueToString(0);
+  EXPECT_EQ("0", zero);
+}
+
+class UseFallback {};
+
+TEST(TraceEventConversionHelperTest, UseFallback) {
+  std::string answer = ValueToString(UseFallback(), "fallback");
+  EXPECT_EQ("fallback", answer);
+}
+
+// std::ostream::operator<<
+TEST(TraceEventConversionHelperTest, StdOstream) {
+  const char* literal = "hello literal";
+  EXPECT_EQ(literal, ValueToString(literal));
+  std::string str = "hello std::string";
+  EXPECT_EQ(str, ValueToString(str));
+  EXPECT_EQ("1", ValueToString(true));
+}
+
+// base::NumberToString
+TEST(TraceEventConversionHelperTest, Number) {
+  EXPECT_EQ("3.14159", ValueToString(3.14159));
+  EXPECT_EQ("0", ValueToString(0.f));
+  EXPECT_EQ("42", ValueToString(42));
+}
+
+class UseToString {
+ public:
+  std::string ToString() const { return "UseToString::ToString"; }
+};
+
+TEST(TraceEventConversionHelperTest, UseToString) {
+  std::string answer = ValueToString(UseToString());
+  EXPECT_EQ("UseToString::ToString", answer);
+}
+
+class UseFallbackNonConstTostring {
+ public:
+  std::string ToString() { return "don't return me, not const"; }
+};
+
+TEST(TraceEventConversionHelperTest, UseFallbackNonConstToString) {
+  std::string answer = ValueToString(UseFallbackNonConstTostring(), "fallback");
+  EXPECT_EQ("fallback", answer);
+}
+
+class ConfusingToStringAPI {
+ public:
+  ConfusingToStringAPI ToString() const { return ConfusingToStringAPI(); }
+};
+
+TEST(TraceEventConversionHelperTest, ConfusingToStringAPI) {
+  std::string answer = ValueToString(ConfusingToStringAPI(), "fallback");
+  EXPECT_EQ("fallback", answer);
+}
+
+// std::ostream::operator<<
+TEST(TraceEventConversionHelperTest, UseOstreamOperator) {
+  // Test that the output is the same as when calling OstreamValueToString.
+  // Different platforms may represent the pointer differently, thus we don't
+  // compare with a value.
+  EXPECT_EQ(internal::OstreamValueToString((void*)0x123),
+            ValueToString((void*)0x123));
+}
+
+class UseOperatorLessLess {};
+
+std::ostream& operator<<(std::ostream& os, const UseOperatorLessLess&) {
+  os << "UseOperatorLessLess";
+  return os;
+}
+
+TEST(TraceEventConversionHelperTest, UseOperatorLessLess) {
+  std::string answer = ValueToString(UseOperatorLessLess());
+  EXPECT_EQ("UseOperatorLessLess", answer);
+}
+
+class HasBoth {
+ public:
+  std::string ToString() const { return "HasBoth::ToString"; }
+};
+
+std::ostream& operator<<(std::ostream& os, const HasBoth&) {
+  os << "HasBoth::OperatorLessLess";
+  return os;
+}
+
+TEST(TraceEventConversionHelperTest, HasBoth) {
+  std::string answer = ValueToString(HasBoth());
+  EXPECT_EQ("HasBoth::ToString", answer);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/traced_value.h b/base/trace_event/traced_value.h
index a7e7ea4a..a708ada 100644
--- a/base/trace_event/traced_value.h
+++ b/base/trace_event/traced_value.h
@@ -231,14 +231,6 @@
   std::string ToFormattedJSON() const;
 };
 
-// Return std::string representation given by |value|'s ostream operator<<.
-template <typename T>
-std::string ValueToString(const T& value) {
-  std::stringstream ss;
-  ss << value;
-  return ss.str();
-}
-
 }  // namespace trace_event
 }  // namespace base
 
diff --git a/base/trace_event/traced_value_unittest.cc b/base/trace_event/traced_value_unittest.cc
index 1caf27bb..652db8f 100644
--- a/base/trace_event/traced_value_unittest.cc
+++ b/base/trace_event/traced_value_unittest.cc
@@ -15,11 +15,6 @@
 namespace base {
 namespace trace_event {
 
-TEST(TraceEventArgumentTest, ValueToString) {
-  std::string zero = ValueToString(0);
-  EXPECT_EQ("0", zero);
-}
-
 TEST(TraceEventArgumentTest, InitializerListCreatedFlatDictionary) {
   std::string json;
   TracedValue::Build({{"bool_var", true},
diff --git a/base/util/timer/wall_clock_timer.h b/base/util/timer/wall_clock_timer.h
index 8c955fe9..752a7b1c 100644
--- a/base/util/timer/wall_clock_timer.h
+++ b/base/util/timer/wall_clock_timer.h
@@ -27,8 +27,9 @@
 //
 // Comparison with OneShotTimer: WallClockTimer runs |user_task_| after |delay_|
 // expires according to usual time, while OneShotTimer runs |user_task_| after
-// |delay_| expires according to TimeTicks which freezes when power suspends
-// (desktop falls asleep).
+// |delay_| expires according to TimeTicks which may freeze on some platforms
+// when power suspends (desktop falls asleep). On platforms where TimeTicks
+// don't freeze, the WallClockTimer has the same behavior as OneShotTimer.
 //
 // The API is not thread safe. All methods must be called from the same
 // sequence (not necessarily the construction sequence), except for the
diff --git a/base/util/timer/wall_clock_timer_unittest.cc b/base/util/timer/wall_clock_timer_unittest.cc
index 961f5c0..1fc91ddc 100644
--- a/base/util/timer/wall_clock_timer_unittest.cc
+++ b/base/util/timer/wall_clock_timer_unittest.cc
@@ -216,4 +216,67 @@
   ::testing::Mock::VerifyAndClearExpectations(&callback);
 }
 
+// On some platforms, TickClock will never freeze. WallClockTimer are still
+// supported on those platforms.
+TEST_F(WallClockTimerTest, NonStopTickClock) {
+  ::testing::StrictMock<base::MockOnceClosure> callback;
+  // Set up a WallClockTimer that will fire in one minute.
+  WallClockTimer wall_clock_timer(&clock_,
+                                  task_environment_.GetMockTickClock());
+  constexpr auto delay = base::TimeDelta::FromMinutes(1);
+  const auto start_time = base::Time::Now();
+  const auto run_time = start_time + delay;
+  clock_.SetNow(start_time);
+  wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
+  EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
+
+  // Pretend that time jumps forward 30 seconds while the machine is suspended.
+  constexpr auto past_time = base::TimeDelta::FromSeconds(30);
+
+  // Fastword with both clocks even the power is suspended.
+  mock_power_monitor_source_->Suspend();
+  clock_.SetNow(clock_.Now() + past_time);
+  task_environment_.FastForwardBy(past_time);
+  mock_power_monitor_source_->Resume();
+
+  // Ensure that the timer has not yet fired.
+  ::testing::Mock::VerifyAndClearExpectations(&callback);
+  EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
+
+  // Expect that the timer fires at the desired run time.
+  EXPECT_CALL(callback, Run());
+  // Both Time::Now() and |task_environment_| MockTickClock::Now()
+  // go forward by (|delay| - |past_time|):
+  FastForwardBy(delay - past_time);
+  ::testing::Mock::VerifyAndClearExpectations(&callback);
+  EXPECT_FALSE(wall_clock_timer.IsRunning());
+}
+
+TEST_F(WallClockTimerTest, NonStopTickClockWithLongPause) {
+  ::testing::StrictMock<base::MockOnceClosure> callback;
+  // Set up a WallClockTimer that will fire in one minute.
+  WallClockTimer wall_clock_timer(&clock_,
+                                  task_environment_.GetMockTickClock());
+  constexpr auto delay = base::TimeDelta::FromMinutes(1);
+  const auto start_time = base::Time::Now();
+  const auto run_time = start_time + delay;
+  clock_.SetNow(start_time);
+  wall_clock_timer.Start(FROM_HERE, run_time, callback.Get());
+  EXPECT_EQ(wall_clock_timer.desired_run_time(), start_time + delay);
+
+  // Pretend that time jumps forward 60 seconds while the machine is suspended.
+  constexpr auto past_time = base::TimeDelta::FromSeconds(60);
+
+  // Fastword with both clocks even the power is suspended. Timer fires at the
+  // moment of power resume.
+  EXPECT_CALL(callback, Run());
+  mock_power_monitor_source_->Suspend();
+  clock_.SetNow(clock_.Now() + past_time);
+  task_environment_.FastForwardBy(past_time);
+  mock_power_monitor_source_->Resume();
+
+  ::testing::Mock::VerifyAndClearExpectations(&callback);
+  EXPECT_FALSE(wall_clock_timer.IsRunning());
+}
+
 }  // namespace util
diff --git a/build/android/lint/baseline.xml b/build/android/lint/baseline.xml
index 630a63a..92209fed 100644
--- a/build/android/lint/baseline.xml
+++ b/build/android/lint/baseline.xml
@@ -254,7 +254,7 @@
         errorLine2="                                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="weblayer/browser/java/org/chromium/weblayer_private/BrowserViewController.java"
-            line="294"
+            line="285"
             column="53"/>
     </issue>
 
@@ -331,7 +331,7 @@
         errorLine2="                       ~~">
         <location
             file="chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java"
-            line="219"
+            line="220"
             column="24"/>
     </issue>
 
@@ -342,7 +342,7 @@
         errorLine2="                                                ~~">
         <location
             file="chrome/browser/download/android/java/src/org/chromium/chrome/browser/download/dialogs/DownloadLaterDialogHelper.java"
-            line="117"
+            line="123"
             column="49"/>
     </issue>
 
@@ -392,17 +392,6 @@
 
     <issue
         id="WrongConstant"
-        message="Must be one of: ApplicationState.UNKNOWN, ApplicationState.HAS_RUNNING_ACTIVITIES, ApplicationState.HAS_PAUSED_ACTIVITIES, ApplicationState.HAS_STOPPED_ACTIVITIES, ApplicationState.HAS_DESTROYED_ACTIVITIES"
-        errorLine1="        onApplicationStateChange(0 /* unused */);"
-        errorLine2="                                 ~">
-        <location
-            file="net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java"
-            line="21"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="WrongConstant"
         message="Must be one of: PasswordsState.UNCHECKED, PasswordsState.CHECKING, PasswordsState.SAFE, PasswordsState.COMPROMISED_EXIST, PasswordsState.OFFLINE, PasswordsState.NO_PASSWORDS, PasswordsState.SIGNED_OUT, PasswordsState.QUOTA_LIMIT, PasswordsState.ERROR"
         errorLine1="        return 0;"
         errorLine2="               ~">
@@ -496,7 +485,7 @@
         errorLine2="                                                                            ~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java"
-            line="272"
+            line="273"
             column="77"/>
     </issue>
 
@@ -705,7 +694,7 @@
         errorLine2="                                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/payments/AndroidPaymentAppFinder.java"
-            line="588"
+            line="604"
             column="55"/>
     </issue>
 
@@ -833,39 +822,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    ThreadUtils.postOnUiThreadDelayed(this, RETRY_DELAY_MS);"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java"
-            line="393"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        if (sAppDetailsDelegate != null) sAppDetailsDelegate.destroy();"
-        errorLine2="                                                             ~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java"
-            line="69"
-            column="62"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        sAppDetailsDelegate.getAppDetailsAsynchronously("
-        errorLine2="                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java"
-            line="104"
-            column="29"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="            mHandler.onOptionsItemSelected(menuItem);"
         errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -1046,7 +1002,7 @@
         errorLine2="                          ~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="238"
+            line="237"
             column="27"/>
     </issue>
 
@@ -1057,7 +1013,7 @@
         errorLine2="                              ~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="239"
+            line="238"
             column="31"/>
     </issue>
 
@@ -1068,7 +1024,7 @@
         errorLine2="                              ~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="240"
+            line="239"
             column="31"/>
     </issue>
 
@@ -1079,7 +1035,7 @@
         errorLine2="                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="470"
+            line="469"
             column="30"/>
     </issue>
 
@@ -1090,7 +1046,7 @@
         errorLine2="                                                ~~~~~~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="562"
+            line="558"
             column="49"/>
     </issue>
 
@@ -1101,7 +1057,7 @@
         errorLine2="                                       ~~~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="563"
+            line="559"
             column="40"/>
     </issue>
 
@@ -1112,7 +1068,7 @@
         errorLine2="                                                                  ~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="578"
+            line="574"
             column="67"/>
     </issue>
 
@@ -1123,7 +1079,7 @@
         errorLine2="                        ~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="616"
+            line="612"
             column="25"/>
     </issue>
 
@@ -1134,7 +1090,7 @@
         errorLine2="                                                                        ~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="633"
+            line="629"
             column="73"/>
     </issue>
 
@@ -1145,7 +1101,7 @@
         errorLine2="                                                                      ~~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="654"
+            line="650"
             column="71"/>
     </issue>
 
@@ -1156,7 +1112,7 @@
         errorLine2="                                                   ~~~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="672"
+            line="668"
             column="52"/>
     </issue>
 
@@ -1167,7 +1123,7 @@
         errorLine2="                       ~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="692"
+            line="687"
             column="24"/>
     </issue>
 
@@ -1178,7 +1134,7 @@
         errorLine2="                              ~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="693"
+            line="688"
             column="31"/>
     </issue>
 
@@ -1189,7 +1145,7 @@
         errorLine2="                              ~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="694"
+            line="689"
             column="31"/>
     </issue>
 
@@ -1200,18 +1156,18 @@
         errorLine2="                                                                     ~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="703"
+            line="698"
             column="70"/>
     </issue>
 
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="                verifiedIndex, suggestion.hashCode(), elapsedTimeSinceInputChange);"
+        errorLine1="                verifiedIndex, suggestion.hashCode(), getElapsedTimeSinceInputChange());"
         errorLine2="                                          ~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="711"
+            line="703"
             column="43"/>
     </issue>
 
@@ -1222,7 +1178,7 @@
         errorLine2="                                               ~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="713"
+            line="705"
             column="48"/>
     </issue>
 
@@ -1233,7 +1189,7 @@
         errorLine2="                           ~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="736"
+            line="728"
             column="28"/>
     </issue>
 
@@ -1244,7 +1200,7 @@
         errorLine2="                                                        ~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="854"
+            line="846"
             column="57"/>
     </issue>
 
@@ -1255,7 +1211,7 @@
         errorLine2="                                    ~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="941"
+            line="933"
             column="37"/>
     </issue>
 
@@ -1266,7 +1222,7 @@
         errorLine2="                              ~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="942"
+            line="934"
             column="31"/>
     </issue>
 
@@ -1277,7 +1233,7 @@
         errorLine2="                                   ~~~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="963"
+            line="955"
             column="36"/>
     </issue>
 
@@ -1288,7 +1244,7 @@
         errorLine2="                       ~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="978"
+            line="970"
             column="24"/>
     </issue>
 
@@ -1299,7 +1255,7 @@
         errorLine2="                               ~~~~~~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="980"
+            line="972"
             column="32"/>
     </issue>
 
@@ -1310,7 +1266,7 @@
         errorLine2="                                                                ~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="980"
+            line="972"
             column="65"/>
     </issue>
 
@@ -1321,7 +1277,7 @@
         errorLine2="                                                                                  ~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="1160"
+            line="1150"
             column="83"/>
     </issue>
 
@@ -1332,73 +1288,7 @@
         errorLine2="                           ~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteMediator.java"
-            line="1161"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable&lt;String>() {"
-        errorLine2="                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/autofill/AutofillDataProvider.java"
-            line="181"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                final AutofillProfile address = new AutofillProfile("
-        errorLine2="                                                ^">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/autofill/AutofillDataProvider.java"
-            line="188"
-            column="49"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable&lt;String>() {"
-        errorLine2="                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/autofill/AutofillDataProvider.java"
-            line="213"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                final CreditCard card = new CreditCard("
-        errorLine2="                                        ^">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/autofill/AutofillDataProvider.java"
-            line="216"
-            column="41"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable&lt;List&lt;AutofillProfile>>() {"
-        errorLine2="                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/autofill/AutofillDataProvider.java"
-            line="319"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable&lt;List&lt;CreditCard>>() {"
-        errorLine2="                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/autofill/AutofillDataProvider.java"
-            line="340"
+            line="1151"
             column="28"/>
     </issue>
 
@@ -3154,116 +3044,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="            mClientManager.setShouldGetPageLoadMetricsForSession(session, true);"
-        errorLine2="            ~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="228"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        IntentUtils.safePutBinderExtra(tempIntent, CustomTabsIntent.EXTRA_SESSION, sessionBinder);"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="246"
-            column="21"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                mClientManager.setHideDomainForSession(session, hidden);"
-        errorLine2="                ~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="280"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                mClientManager.setSpeculateLoadOnCellularForSession(session, prerender);"
-        errorLine2="                ~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="287"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                mClientManager.setSendNavigationInfoForSession(session, true);"
-        errorLine2="                ~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="293"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                mClientManager.setSendBottomBarScrollingStateForSessionn(session, true);"
-        errorLine2="                ~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="301"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                setIgnoreUrlFragmentsForSession(session, value);"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="314"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                mClientManager.setAllowParallelRequestForSession(session, true);"
-        errorLine2="                ~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="391"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                if (success) mClientManager.setAllowResourcePrefetchForSession(session, true);"
-        errorLine2="                             ~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="402"
-            column="30"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        int uid = mClientManager.getUidForSession(session);"
-        errorLine2="                  ~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/customtabs/ChromeCustomTabsConnection.java"
-            line="863"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="        DownloadManagerService.getDownloadManagerService().onDownloadFailed(downloadItem, reason);"
         errorLine2="                                                           ~~~~~~~~~~~~~~~~">
         <location
@@ -3275,55 +3055,11 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="            mOfflinePageUrl = offlinePage.getUrl();"
-        errorLine2="            ~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java"
-            line="108"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            mOfflinePageUrl = offlinePage.getUrl();"
-        errorLine2="                                          ~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java"
-            line="108"
-            column="43"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            long pageCreationTimeMs = offlinePage.getCreationTimeMs();"
-        errorLine2="                                                  ~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java"
-            line="117"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                Date creationDate = new Date(offlinePage.getCreationTimeMs());"
-        errorLine2="                                                         ~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/page_info/ChromePageInfoControllerDelegate.java"
-            line="119"
-            column="58"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="        mOverviewListLayout = (OverviewListLayout) mLayoutManager.getOverviewListLayout();"
         errorLine2="                                                                  ~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java"
-            line="816"
+            line="823"
             column="67"/>
     </issue>
 
@@ -3550,17 +3286,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="        return ThreadUtils.runOnUiThreadBlockingNoException("
-        errorLine2="                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="base/android/java/src/org/chromium/base/task/DefaultTaskExecutor.java"
-            line="66"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="        if (!AndroidSyncSettings.get().isChromeSyncEnabled()) {"
         errorLine2="                                       ~~~~~~~~~~~~~~~~~~~">
         <location
@@ -3946,39 +3671,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="        int scrollTo = mSnapScrollHelper.calculateSnapPosition(initialScroll);"
-        errorLine2="                                         ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java"
-            line="511"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        assert scrollTo == mSnapScrollHelper.calculateSnapPosition(scrollTo);"
-        errorLine2="                                             ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java"
-            line="514"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        ThreadUtils.postOnUiThreadDelayed(this, TIMEOUT_MS);"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedbackCollector.java"
-            line="74"
-            column="21"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="        setKeyboardDelegate(new ActivityKeyboardVisibilityDelegate(getActivity()));"
         errorLine2="        ~~~~~~~~~~~~~~~~~~~">
         <location
@@ -4001,72 +3693,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable&lt;Boolean>() {"
-        errorLine2="                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/icing/GSAContextHelper.java"
-            line="100"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            singleOfflinePage.putParcelable(FETCHED_URI_KEY, Uri.parse(page.getUrl()));"
-        errorLine2="                                                                            ~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/offlinepages/GetAllPagesV1Handler.java"
-            line="80"
-            column="77"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            singleOfflinePage.putLong(DOWNLOAD_TIMESTAMP_KEY, page.getCreationTimeMs());"
-        errorLine2="                                                                   ~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/offlinepages/GetAllPagesV1Handler.java"
-            line="81"
-            column="68"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            singleOfflinePage.putLong(LAST_ACCESSED_TIMESTAMP_KEY, page.getLastAccessTimeMs());"
-        errorLine2="                                                                        ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/offlinepages/GetAllPagesV1Handler.java"
-            line="82"
-            column="73"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            singleOfflinePage.putCharSequence(TITLE_KEY, page.getTitle());"
-        errorLine2="                                                              ~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/offlinepages/GetAllPagesV1Handler.java"
-            line="83"
-            column="63"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            if (item.getUrl().equals(mTab.getUrlString())) {"
-        errorLine2="                     ~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/GetPagesByNamespaceForLivePageSharingCallback.java"
-            line="36"
-            column="22"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="                    ? UrlUtilities.urlsMatchIgnoringFragments(speculatedUrl, url)"
         errorLine2="                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -4364,17 +3990,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="        ThreadUtils.postOnUiThreadDelayed(mThrottlingIntervalTask, mThrottlingIntervalMs);"
-        errorLine2="                    ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="base/android/java/src/org/chromium/base/memory/MemoryPressureMonitor.java"
-            line="227"
-            column="21"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="        save();"
         errorLine2="        ~~~~">
         <location
@@ -4441,127 +4056,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="        String offlinePath = offlinePage.getFilePath();"
-        errorLine2="                                         ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="440"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                offlinePageBridge.isTemporaryNamespace(offlinePage.getClientId().getNamespace());"
-        errorLine2="                                                                   ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="443"
-            column="68"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        String offlinePath = offlinePage.getFilePath();"
-        errorLine2="                                         ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="461"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        String offlinePath = offlinePage.getFilePath();"
-        errorLine2="                                         ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="496"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                offlinePage.getOfflineId(), publishPageCallback);"
-        errorLine2="                            ~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="539"
-            column="29"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        final String pageUrl = page.getUrl();"
-        errorLine2="                                    ~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="560"
-            column="37"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        final String pageTitle = page.getTitle();"
-        errorLine2="                                      ~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="561"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        final File offlinePageFile = new File(page.getFilePath());"
-        errorLine2="                                                   ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="562"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        sharePage(window, pageUrl, pageTitle, page.getFilePath(), offlinePageFile, shareCallback);"
-        errorLine2="                                                   ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="563"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        LoadUrlParams params = new LoadUrlParams(offlinePage.getUrl(), transitionTypeForReload);"
-        errorLine2="                                                             ~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="784"
-            column="62"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                if (page.getClientId().getNamespace().equals(OfflinePageBridge.LAST_N_NAMESPACE)) {"
-        errorLine2="                         ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java"
-            line="887"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="        return VersionNumberGetter.getInstance().getCurrentlyUsedVersion(getContext());"
         errorLine2="                                   ~~~~~~~~~~~">
         <location
@@ -4650,72 +4144,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="                            logEntry.getAutofilledValue(), logEntry.getProfileFullName());"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/policy/providers/PartnerProvider.java"
-            line="78"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                            logEntry.getAutofilledValue(), logEntry.getProfileFullName());"
-        errorLine2="                                                                    ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/policy/providers/PartnerProvider.java"
-            line="78"
-            column="69"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        AutofillLogger.setLogger(autofillLogger);"
-        errorLine2="                       ~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/policy/providers/PartnerProvider.java"
-            line="82"
-            column="24"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            terminateIncognitoSession();"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/policy/providers/PartnerProvider.java"
-            line="106"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                        IntentUtils.safePutBinderExtra("
-        errorLine2="                                    ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseDialogFragment.java"
-            line="221"
-            column="37"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                        IntentUtils.safePutBinderExtra("
-        errorLine2="                                    ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java"
-            line="208"
-            column="37"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="                IconProvider.getIcon(context, R.drawable.ic_vpn_key_grey),"
         errorLine2="                             ~~~~~~~">
         <location
@@ -4980,50 +4408,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="public class PhoneskyDetailsDelegate extends AppDetailsDelegate"
-        errorLine2="                                             ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/banner/PhoneskyDetailsDelegate.java"
-            line="42"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                observer.onAppDetailsRetrieved(data);"
-        errorLine2="                         ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/banner/PhoneskyDetailsDelegate.java"
-            line="104"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        AppData data = new AppData(url, packageName);"
-        errorLine2="                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/banner/PhoneskyDetailsDelegate.java"
-            line="155"
-            column="24"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        data.setPackageInfo(title, imageUrl, rating, installText, detailsIntent, purchaseIntent);"
-        errorLine2="             ~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/banner/PhoneskyDetailsDelegate.java"
-            line="156"
-            column="14"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="        return getBrowserStartupController().isRunningInServiceManagerMode();"
         errorLine2="               ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -5035,182 +4419,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="        UniqueIdentificationGeneratorFactory.registerGenerator(SyncController.GENERATOR_ID,"
-        errorLine2="                                             ~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java"
-            line="172"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        UniqueIdentificationGeneratorFactory.registerGenerator(SyncController.GENERATOR_ID,"
-        errorLine2="                                             ~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/init/ProcessInitializationHandlerInternal.java"
-            line="44"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        LocationUtils.setFactory(() -> new LocationUtilsInternal(mExternalAuthUtils));"
-        errorLine2="                      ~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/init/ProcessInitializationHandlerInternal.java"
-            line="51"
-            column="23"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            page = new OfflinePageItem(mPage.getUrl(), mPage.getOfflineId(),"
-        errorLine2="                                             ~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="39"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            page = new OfflinePageItem(mPage.getUrl(), mPage.getOfflineId(),"
-        errorLine2="                                                             ~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="39"
-            column="62"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    mPage.getClientId().getNamespace(), mPage.getClientId().getId(),"
-        errorLine2="                          ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="40"
-            column="27"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    mPage.getClientId().getNamespace(), mPage.getClientId().getId(),"
-        errorLine2="                                                              ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="40"
-            column="63"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    mPage.getTitle(), newFilePath, mPage.getFileSize(), mPage.getCreationTimeMs(),"
-        errorLine2="                          ~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="41"
-            column="27"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    mPage.getTitle(), newFilePath, mPage.getFileSize(), mPage.getCreationTimeMs(),"
-        errorLine2="                                                         ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="41"
-            column="58"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    mPage.getTitle(), newFilePath, mPage.getFileSize(), mPage.getCreationTimeMs(),"
-        errorLine2="                                                                              ~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="41"
-            column="79"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    mPage.getAccessCount(), mPage.getLastAccessTimeMs(), mPage.getRequestOrigin());"
-        errorLine2="                          ~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="42"
-            column="27"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    mPage.getAccessCount(), mPage.getLastAccessTimeMs(), mPage.getRequestOrigin());"
-        errorLine2="                                                  ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="42"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="                    mPage.getAccessCount(), mPage.getLastAccessTimeMs(), mPage.getRequestOrigin());"
-        errorLine2="                                                                               ~~~~~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/offlinepages/PublishPageCallback.java"
-            line="42"
-            column="80"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        requestCoordinatorBridge.getRequestsInQueue(new Callback&lt;SavePageRequest[]&gt;() {"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/offlinepages/QueryPagesV1Handler.java"
-            line="94"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            ClientId clientId = page.getClientId();"
-        errorLine2="                                     ~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/offlinepages/QueryPagesV1Handler.java"
-            line="128"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="            singleUriResult.putParcelable(FETCHED_URI_KEY, Uri.parse(page.getUrl()));"
-        errorLine2="                                                                          ~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/offlinepages/QueryPagesV1Handler.java"
-            line="141"
-            column="75"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="        String distillerUrl = DomDistillerUrlUtils.getDistillerViewUrlFromUrl("
         errorLine2="                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -5233,34 +4441,12 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="        requestCoordinatorBridge.getRequestsInQueue(queuedRequests -> {"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~">
+        errorLine1="                new SettingsSecureBasedIdentificationGenerator(getContext()), false);"
+        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="clank/java/src/org/chromium/chrome/browser/offlinepages/RemovePagesV1Handler.java"
-            line="76"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        requestCoordinatorBridge.getRequestsInQueue(queuedRequests -> {"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/org/chromium/chrome/browser/offlinepages/RemovePagesV2Handler.java"
-            line="74"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
-        errorLine1="        super(context);"
-        errorLine2="        ~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/omaha/RequestGeneratorImpl.java"
-            line="36"
-            column="9"/>
+            file="chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java"
+            line="52"
+            column="17"/>
     </issue>
 
     <issue
@@ -5303,7 +4489,7 @@
         errorLine2="                        ~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetPropertyModelBuilder.java"
-            line="202"
+            line="203"
             column="25"/>
     </issue>
 
@@ -5453,17 +4639,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="                &amp;&amp; TextUtils.equals(item.getClientId().getNamespace(),"
-        errorLine2="                                         ~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsOfflineModelObserver.java"
-            line="129"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="                requestId, new AwContents.VisualStateCallback() {"
         errorLine2="                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
@@ -5644,7 +4819,7 @@
         errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionProxyView.java"
-            line="94"
+            line="95"
             column="22"/>
     </issue>
 
@@ -5655,7 +4830,7 @@
         errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="content/public/android/java/src/org/chromium/content/browser/input/ThreadedInputConnectionProxyView.java"
-            line="96"
+            line="97"
             column="22"/>
     </issue>
 
@@ -5673,17 +4848,6 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="            tile.setOfflinePageOfflineId(item == null ? null : item.getOfflineId());"
-        errorLine2="                                                                    ~~~~~~~~~~~~">
-        <location
-            file="chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java"
-            line="614"
-            column="69"/>
-    </issue>
-
-    <issue
-        id="VisibleForTests"
-        message="This method should only be accessed from tests or within private scope"
         errorLine1="        return suggestion.getType() == OmniboxSuggestionType.TILE_SUGGESTION;"
         errorLine2="                          ~~~~~~~">
         <location
@@ -6453,50 +5617,6 @@
 
     <issue
         id="SupportAnnotationUsage"
-        message="This annotation does not apply for type org.chromium.base.Callback&lt;java.lang.Integer>; expected int or long"
-        errorLine1="            @LocationSettingsDialogOutcome Callback&lt;Integer> callback) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/location/LocationUtilsInternal.java"
-            line="96"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="SupportAnnotationUsage"
-        message="This annotation does not apply for type org.chromium.base.Callback&lt;java.lang.Integer>; expected int or long"
-        errorLine1="        @LocationSettingsDialogOutcome"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/location/LocationUtilsInternal.java"
-            line="123"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="SupportAnnotationUsage"
-        message="This annotation does not apply for type org.chromium.base.Callback&lt;java.lang.Integer>; expected int or long"
-        errorLine1="                WindowAndroid window, @LocationSettingsDialogOutcome Callback&lt;Integer> callback,"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/location/LocationUtilsInternal.java"
-            line="129"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="SupportAnnotationUsage"
-        message="This annotation does not apply for type org.chromium.base.Callback&lt;java.lang.Integer>; expected int or long"
-        errorLine1="                WindowAndroid window, @LocationSettingsDialogOutcome Callback&lt;Integer> callback,"
-        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="clank/java/src/com/google/android/apps/chrome/location/LocationUtilsInternal.java"
-            line="143"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="SupportAnnotationUsage"
         message="This annotation does not apply for type String; expected int or long"
         errorLine1="        @QuickActionCategory"
         errorLine2="        ~~~~~~~~~~~~~~~~~~~~">
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 7b5f2a13..12e30c6 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -948,12 +948,7 @@
 if (enable_java_templates) {
   template("android_lint") {
     action_with_pydeps(target_name) {
-      forward_variables_from(invoker,
-                             [
-                               "data_deps",
-                               "public_deps",
-                               "testonly",
-                             ])
+      forward_variables_from(invoker, [ "testonly" ])
       if (!defined(deps)) {
         deps = []
       }
@@ -982,6 +977,7 @@
               "${_target_label}__header",
             ]
           } else {
+            # Keep non-java deps as they may generate files used by lint.
             deps += [ _dep ]
           }
         }
@@ -999,15 +995,16 @@
         _suppressions_file = "//build/android/lint/suppressions.xml"
       }
 
-      _min_sdk_version = default_min_sdk_version
       if (defined(invoker.min_sdk_version)) {
         _min_sdk_version = invoker.min_sdk_version
+      } else {
+        _min_sdk_version = default_min_sdk_version
       }
 
       _lint_binary_path = "$lint_android_sdk_root/cmdline-tools/latest/bin/lint"
       _cache_dir = "$root_build_dir/android_lint_cache"
 
-      # Save these generated xml files in a consistent location for debugging.
+      # Save generated xml files in a consistent location for debugging.
       _lint_gen_dir = "$target_gen_dir/$target_name"
 
       script = "//build/android/gyp/lint.py"
diff --git a/build/util/PRESUBMIT.py b/build/util/PRESUBMIT.py
index 271afbb..6100379 100644
--- a/build/util/PRESUBMIT.py
+++ b/build/util/PRESUBMIT.py
@@ -7,7 +7,7 @@
 
 
 def _GetBlacklist(input_api):
-  blacklist = []
+  files_to_skip = []
   affected_files = input_api.change.AffectedFiles()
   version_script_change = next(
       (f for f in affected_files
@@ -15,7 +15,7 @@
       None)
 
   if version_script_change is None:
-    blacklist.append('version_test\\.py$')
+    files_to_skip.append('version_test\\.py$')
 
   android_chrome_version_script_change = next(
       (f for f in affected_files if re.search(
@@ -23,21 +23,21 @@
           '\\/android_chrome_version_test\\.py$', f.LocalPath())), None)
 
   if android_chrome_version_script_change is None:
-    blacklist.append('android_chrome_version_test\\.py$')
+    files_to_skip.append('android_chrome_version_test\\.py$')
 
-  return blacklist
+  return files_to_skip
 
 
 def _GetPythonUnitTests(input_api, output_api):
   # No need to test if files are unchanged
-  blacklist = _GetBlacklist(input_api)
+  files_to_skip = _GetBlacklist(input_api)
 
   return input_api.canned_checks.GetUnitTestsRecursively(
       input_api,
       output_api,
       input_api.PresubmitLocalPath(),
-      whitelist=['.*_test\\.py$'],
-      blacklist=blacklist)
+      files_to_check=['.*_test\\.py$'],
+      files_to_skip=files_to_skip)
 
 
 def CommonChecks(input_api, output_api):
diff --git a/cc/PRESUBMIT.py b/cc/PRESUBMIT.py
index 28ac4ed6..c375a37 100644
--- a/cc/PRESUBMIT.py
+++ b/cc/PRESUBMIT.py
@@ -21,7 +21,8 @@
   return input_api.canned_checks.CheckChangeLintsClean(
       input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
 
-def CheckAsserts(input_api, output_api, allowlist=CC_SOURCE_FILES, denylist=None):
+def CheckAsserts(input_api, output_api, allowlist=CC_SOURCE_FILES,
+                 denylist=None):
   denylist = tuple(denylist or input_api.DEFAULT_FILES_TO_SKIP)
   source_file_filter = lambda x: input_api.FilterSourceFile(x, allowlist,
       denylist)
diff --git a/chrome/PRESUBMIT.py b/chrome/PRESUBMIT.py
index 19f7f55..578b4b7b 100644
--- a/chrome/PRESUBMIT.py
+++ b/chrome/PRESUBMIT.py
@@ -36,9 +36,9 @@
 
 def _CheckChangeLintsClean(input_api, output_api):
   """Makes sure that the chrome/ code is cpplint clean."""
-  black_list = input_api.DEFAULT_BLACK_LIST + EXCLUDE
+  files_to_skip = input_api.DEFAULT_FILES_TO_SKIP + EXCLUDE
   sources = lambda x: input_api.FilterSourceFile(
-    x, white_list=INCLUDE_CPP_FILES_ONLY, black_list=black_list)
+    x, files_to_check=INCLUDE_CPP_FILES_ONLY, files_to_skip=files_to_skip)
   return input_api.canned_checks.CheckChangeLintsClean(
       input_api, output_api, sources)
 
@@ -80,7 +80,7 @@
   ios_macros = []
   def SourceFilter(affected_file):
     return input_api.FilterSourceFile(affected_file, INCLUDE_SOURCE_FILES_ONLY,
-                                      input_api.DEFAULT_BLACK_LIST)
+                                      input_api.DEFAULT_FILES_TO_SKIP)
   for f in input_api.AffectedSourceFiles(SourceFilter):
     ios_macros.extend(_CheckNoOSIOSMacrosInChromeFile(input_api, f))
 
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 5d310a2..a15d8d8 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1251,7 +1251,6 @@
   "java/src/org/chromium/chrome/browser/payments/BasicCardUtils.java",
   "java/src/org/chromium/chrome/browser/payments/CardEditor.java",
   "java/src/org/chromium/chrome/browser/payments/ContactEditor.java",
-  "java/src/org/chromium/chrome/browser/payments/PaymentAppComparator.java",
   "java/src/org/chromium/chrome/browser/payments/PaymentAppFactoryDelegate.java",
   "java/src/org/chromium/chrome/browser/payments/PaymentAppFactoryInterface.java",
   "java/src/org/chromium/chrome/browser/payments/PaymentAppService.java",
@@ -1287,6 +1286,7 @@
   "java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java",
   "java/src/org/chromium/chrome/browser/payments/ui/DimmingDialog.java",
   "java/src/org/chromium/chrome/browser/payments/ui/LineItem.java",
+  "java/src/org/chromium/chrome/browser/payments/ui/PaymentAppComparator.java",
   "java/src/org/chromium/chrome/browser/payments/ui/PaymentInformation.java",
   "java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestBottomBar.java",
   "java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestHeader.java",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java
index 30f916c..74d881d 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinator.java
@@ -40,7 +40,6 @@
     private static final String INTENT_IDENTFIER = "INTENT";
     private static final String BUY_MOVIE_TICKETS_INTENT = "BUY_MOVIE_TICKET";
     private static final String RENT_CAR_INTENT = "RENT_CAR";
-    private static final String PASSWORD_CHANGE_INTENT = "PASSWORD_CHANGE";
     private static final String FLIGHTS_INTENT = "FLIGHTS_CHECKIN";
     private static final String FOOD_ORDERING_INTENT = "FOOD_ORDERING";
     private static final String VOICE_SEARCH_INTENT = "TELEPORT";
@@ -238,10 +237,6 @@
                 termsTextView.setText(R.string.autofill_assistant_init_message_short);
                 titleTextView.setText(R.string.autofill_assistant_init_message_rent_car);
                 break;
-            case PASSWORD_CHANGE_INTENT:
-                termsTextView.setText(R.string.autofill_assistant_init_message_short);
-                titleTextView.setText(R.string.autofill_assistant_init_message_password_change);
-                break;
             case SHOPPING_INTENT:
             case SHOPPING_ASSISTED_CHECKOUT_INTENT:
                 termsTextView.setText(R.string.autofill_assistant_init_message_short);
diff --git a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd
index c7168cfcd..d122756 100644
--- a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd
+++ b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd
@@ -177,9 +177,6 @@
       <message name="IDS_AUTOFILL_ASSISTANT_INIT_MESSAGE_RENT_CAR" desc="Onboarding message describing autofill assistant's capability for car rentals.">
         Rent a car\nin just a few taps
       </message>
-      <message name="IDS_AUTOFILL_ASSISTANT_INIT_MESSAGE_PASSWORD_CHANGE" desc="Onboarding message describing autofill assistant's capability for password change.">
-        Let Google Assistant help you\nchange your password
-      </message>
       <message name="IDS_AUTOFILL_ASSISTANT_INIT_MESSAGE_BUY_MOVIE_TICKETS" desc="Onboarding message describing autofill assistant's capability for movie tickets.">
         Buy movie tickets\nin just a few taps
       </message>
diff --git a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings_grd/IDS_AUTOFILL_ASSISTANT_INIT_MESSAGE_PASSWORD_CHANGE.png.sha1 b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings_grd/IDS_AUTOFILL_ASSISTANT_INIT_MESSAGE_PASSWORD_CHANGE.png.sha1
deleted file mode 100644
index 457235a..0000000
--- a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings_grd/IDS_AUTOFILL_ASSISTANT_INIT_MESSAGE_PASSWORD_CHANGE.png.sha1
+++ /dev/null
Binary files differ
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
index 0bf4a95f..ade54a9 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -75,7 +75,7 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.compositor.layouts.phone.StackLayout;
-import org.chromium.chrome.browser.feed.FeedSurfaceCoordinator;
+import org.chromium.chrome.browser.feed.FeedSurfaceMediator;
 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -988,7 +988,7 @@
         Assert.assertEquals(expectedRecordCount,
                 RecordHistogram.getHistogramTotalCountForTesting(
                         StartSurfaceConfiguration.getHistogramName(
-                                FeedSurfaceCoordinator.FEED_CONTENT_FIRST_LOADED_TIME_MS_UMA,
+                                FeedSurfaceMediator.FEED_CONTENT_FIRST_LOADED_TIME_MS_UMA,
                                 isInstantStart)));
         Assert.assertEquals(isInstantReturn() ? 1 : 0,
                 RecordHistogram.getHistogramTotalCountForTesting(
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
index a53f66bf..e42f2c2 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceCoordinator.java
@@ -47,7 +47,6 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.user_education.UserEducationHelper;
-import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.util.GlobalDiscardableReferencePool;
 import org.chromium.components.browser_ui.widget.displaystyle.UiConfig;
@@ -64,9 +63,6 @@
  * Provides a surface that displays an interest feed rendered list of content suggestions.
  */
 public class FeedSurfaceCoordinator implements FeedSurfaceProvider {
-    @VisibleForTesting
-    public static final String FEED_CONTENT_FIRST_LOADED_TIME_MS_UMA = "FeedContentFirstLoadedTime";
-
     private final Activity mActivity;
     private final SnackbarManager mSnackbarManager;
     @Nullable
@@ -502,9 +498,7 @@
     }
 
     public void onOverviewShownAtLaunch(long activityCreationTimeMs) {
-        StartSurfaceConfiguration.recordHistogram(FEED_CONTENT_FIRST_LOADED_TIME_MS_UMA,
-                mMediator.getContentFirstAvailableTimeMs() - activityCreationTimeMs,
-                mIsPlaceholderShown);
+        mMediator.onOverviewShownAtLaunch(activityCreationTimeMs, mIsPlaceholderShown);
     }
 
     Tracker getFeatureEngagementTracker() {
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
index faae547..38a93cb 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedSurfaceMediator.java
@@ -39,6 +39,7 @@
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.signin.SigninPromoUtil;
 import org.chromium.chrome.browser.suggestions.SuggestionsMetrics;
+import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration;
 import org.chromium.components.browser_ui.widget.listmenu.ListMenu;
 import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
 import org.chromium.components.feature_engagement.Tracker;
@@ -56,10 +57,14 @@
  * A mediator for the {@link FeedSurfaceCoordinator} responsible for interacting with the
  * native library and handling business logic.
  */
-class FeedSurfaceMediator implements NewTabPageLayout.ScrollDelegate,
-                                     ContextMenuManager.TouchEnabledDelegate,
-                                     TemplateUrlServiceObserver, ListMenu.Delegate,
-                                     HomepagePromoStateListener, IdentityManager.Observer {
+@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+public class FeedSurfaceMediator
+        implements NewTabPageLayout.ScrollDelegate, ContextMenuManager.TouchEnabledDelegate,
+                   TemplateUrlServiceObserver, ListMenu.Delegate, HomepagePromoStateListener,
+                   IdentityManager.Observer {
+    @VisibleForTesting
+    public static final String FEED_CONTENT_FIRST_LOADED_TIME_MS_UMA = "FeedContentFirstLoadedTime";
+
     private static final float IPH_TRIGGER_BAR_TRANSITION_FRACTION = 1.0f;
     private static final float IPH_STREAM_MIN_SCROLL_FRACTION = 0.10f;
     private static final float IPH_FEED_HEADER_MAX_POS_FRACTION = 0.35f;
@@ -85,7 +90,17 @@
     private int mThumbnailWidth;
     private int mThumbnailHeight;
     private int mThumbnailScrollY;
+
+    /** Whether the Feed content is loading. */
+    private boolean mIsLoadingFeed;
+    /** Cached parameters for recording the histogram of "FeedContentFirstLoadedTime". */
+    private boolean mIsInstantStart;
+    private long mActivityCreationTimeMs;
     private long mContentFirstAvailableTimeMs;
+    // Whether missing a histogram record when onOverviewShownAtLaunch() is called. It is possible
+    // that Feed content is still loading at that time and the {@link mContentFirstAvailableTimeMs}
+    // hasn't been set yet.
+    private boolean mHasPendingUmaRecording;
 
     /**
      * @param coordinator The {@link FeedSurfaceCoordinator} that interacts with this class.
@@ -145,6 +160,7 @@
         }
 
         if (mFeedEnabled) {
+            mIsLoadingFeed = true;
             mCoordinator.createStream();
             if (mSnapScrollHelper != null) {
                 mSnapScrollHelper.setView(mCoordinator.getStream().getView());
@@ -191,7 +207,12 @@
             public void onAddFinished() {
                 if (mContentFirstAvailableTimeMs == 0) {
                     mContentFirstAvailableTimeMs = SystemClock.elapsedRealtime();
+                    if (mHasPendingUmaRecording) {
+                        maybeRecordContentLoadingTime();
+                        mHasPendingUmaRecording = false;
+                    }
                 }
+                mIsLoadingFeed = false;
             }
         };
         stream.addOnContentChangedListener(mStreamContentChangedListener);
@@ -569,10 +590,6 @@
         updateSectionHeader();
     }
 
-    long getContentFirstAvailableTimeMs() {
-        return mContentFirstAvailableTimeMs;
-    }
-
     /**
      * The {@link SignInPromo} for the Feed.
      * TODO(huayinz): Update content and visibility through a ModelChangeProcessor.
@@ -618,4 +635,22 @@
     SignInPromo getSignInPromoForTesting() {
         return mSignInPromo;
     }
+
+    void onOverviewShownAtLaunch(long activityCreationTimeMs, boolean isInstantStart) {
+        assert mActivityCreationTimeMs == 0;
+        mActivityCreationTimeMs = activityCreationTimeMs;
+        mIsInstantStart = isInstantStart;
+
+        if (!maybeRecordContentLoadingTime() && mIsLoadingFeed) {
+            mHasPendingUmaRecording = true;
+        }
+    }
+
+    private boolean maybeRecordContentLoadingTime() {
+        if (mActivityCreationTimeMs == 0 || mContentFirstAvailableTimeMs == 0) return false;
+
+        StartSurfaceConfiguration.recordHistogram(FEED_CONTENT_FIRST_LOADED_TIME_MS_UMA,
+                mContentFirstAvailableTimeMs - mActivityCreationTimeMs, mIsInstantStart);
+        return true;
+    }
 }
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java
index ceccb17..2b40ba1 100644
--- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java
+++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurface.java
@@ -168,8 +168,10 @@
      *  Clear all the data related to all surfaces.
      */
     public static void clearAll() {
+        FeedStreamSurface[] surfaces = null;
         if (sSurfaces != null) {
-            for (FeedStreamSurface surface : sSurfaces) {
+            surfaces = sSurfaces.toArray(new FeedStreamSurface[sSurfaces.size()]);
+            for (FeedStreamSurface surface : surfaces) {
                 surface.surfaceClosed();
             }
             sSurfaces = null;
@@ -179,6 +181,12 @@
         if (processScope != null) {
             processScope.resetAccount();
         }
+
+        if (surfaces != null) {
+            for (FeedStreamSurface surface : surfaces) {
+                surface.surfaceOpened();
+            }
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/PRESUBMIT.py b/chrome/android/java/src/PRESUBMIT.py
index ebbd009..4f60ad2 100644
--- a/chrome/android/java/src/PRESUBMIT.py
+++ b/chrome/android/java/src/PRESUBMIT.py
@@ -52,8 +52,7 @@
 
 
 def _CheckNotificationConstructors(input_api, output_api):
-  # "Blacklist" because the following files are excluded from the check.
-  blacklist = (
+  files_to_skip = (
       'chrome/android/java/src/org/chromium/chrome/browser/notifications/'
       'ChromeNotificationWrapperBuilder.java',
       'chrome/android/java/src/org/chromium/chrome/browser/notifications/'
@@ -70,14 +69,13 @@
 
   See https://crbug.com/678670 for more information.
   '''
-  return _CheckReIgnoreComment(input_api, output_api, error_msg, blacklist,
+  return _CheckReIgnoreComment(input_api, output_api, error_msg, files_to_skip,
                                NEW_NOTIFICATION_BUILDER_RE)
 
 
 def _CheckAlertDialogBuilder(input_api, output_api):
-  # "Blacklist" because the following files are excluded from the check. In
-  # general, preference and FRE related UIs are not relevant to VR mode.
-  blacklist = (
+  # In general, preference and FRE related UIs are not relevant to VR mode.
+  files_to_skip = (
       BROWSER_ROOT + 'browserservices/ClearDataDialogActivity.java',
       BROWSER_ROOT + 'browsing_data/ConfirmImportantSitesDialogFragment.java',
       BROWSER_ROOT + 'browsing_data/OtherFormsOfHistoryDialogFragment.java',
@@ -117,7 +115,7 @@
   //src/chrome/android/java/src/org/chromium/chrome/browser/vr/VR_JAVA_OWNERS
   '''
   error_files = []
-  result = _CheckReIgnoreComment(input_api, output_api, error_msg, blacklist,
+  result = _CheckReIgnoreComment(input_api, output_api, error_msg, files_to_skip,
                                  NEW_ALERTDIALOG_BUILDER_RE, error_files)
 
   wrong_builder_errors = []
@@ -142,8 +140,7 @@
 
 
 def _CheckCompatibleAlertDialogBuilder(input_api, output_api):
-  # "Blacklist" because the following files are excluded from the check.
-  blacklist = (
+  files_to_skip = (
       BROWSER_ROOT + 'autofill/AutofillPopupBridge.java',
       BROWSER_ROOT + 'autofill/keyboard_accessory/'
                      'AutofillKeyboardAccessoryBridge.java',
@@ -171,11 +168,11 @@
   If you are in doubt, contact
   //src/chrome/android/java/src/org/chromium/chrome/browser/vr/VR_JAVA_OWNERS
   '''
-  return _CheckReIgnoreComment(input_api, output_api, error_msg, blacklist,
+  return _CheckReIgnoreComment(input_api, output_api, error_msg, files_to_skip,
                                NEW_COMPATIBLE_ALERTDIALOG_BUILDER_RE)
 
 
-def _CheckReIgnoreComment(input_api, output_api, error_msg, blacklist,
+def _CheckReIgnoreComment(input_api, output_api, error_msg, files_to_skip,
                           regular_expression, error_files=None):
 
   def CheckLine(current_file, line_number, line, problems, error_files):
@@ -191,7 +188,7 @@
 
   problems = []
   sources = lambda x: input_api.FilterSourceFile(
-      x, white_list=(r'.*\.java$',), black_list=blacklist)
+      x, files_to_check=(r'.*\.java$',), files_to_skip=files_to_skip)
   for f in input_api.AffectedFiles(include_deletes=False,
                                    file_filter=sources):
     previous_line = ''
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java
index 2f86dade..adb89c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.autofill;
 
-import androidx.annotation.VisibleForTesting;
-
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 
@@ -26,12 +24,10 @@
             mProfileFullName = profileFullName;
         }
 
-        @VisibleForTesting
         public String getAutofilledValue() {
             return mAutofilledValue;
         }
 
-        @VisibleForTesting
         public String getProfileFullName() {
             return mProfileFullName;
         }
@@ -48,12 +44,10 @@
     private static Logger sLogger;
     private static Logger sLoggerForTest;
 
-    @VisibleForTesting
     public static void setLogger(Logger logger) {
         sLogger = logger;
     }
 
-    @VisibleForTesting
     public static void setLoggerForTesting(Logger logger) {
         sLoggerForTest = logger;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppData.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppData.java
index dbe7d450..d0f1447b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppData.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppData.java
@@ -7,8 +7,6 @@
 import android.app.PendingIntent;
 import android.content.Intent;
 
-import androidx.annotation.VisibleForTesting;
-
 /**
  * Stores information about a particular app.
  */
@@ -30,7 +28,6 @@
      * @param siteUrl     URL for the site requesting the banner.
      * @param packageName Name of the package associated with the app.
      */
-    @VisibleForTesting
     public AppData(String siteUrl, String packageName) {
         mSiteUrl = siteUrl;
         mPackageName = packageName;
@@ -110,7 +107,6 @@
      * @param detailsIntent     Intent to fire to launch the details page for the app
      * @param installIntent     Intent to fire to trigger the purchase/install process.
      */
-    @VisibleForTesting
     public void setPackageInfo(String title, String imageUrl, float rating,
             String installButtonText, PendingIntent detailsIntent, Intent installIntent) {
         mTitle = title;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppDetailsDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppDetailsDelegate.java
index 3c9f4e93..4dc3bbc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppDetailsDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppDetailsDelegate.java
@@ -4,12 +4,9 @@
 
 package org.chromium.chrome.browser.banners;
 
-import androidx.annotation.VisibleForTesting;
-
 /**
  * Fetches data about the given app.
  */
-@VisibleForTesting
 public abstract class AppDetailsDelegate {
     /**
      * Class to inform when the app's details have been retrieved.
@@ -19,7 +16,6 @@
          * Called when the task has finished.
          * @param data Data about the requested package.  Will be null if retrieval failed.
          */
-        @VisibleForTesting
         public void onAppDetailsRetrieved(AppData data);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
index ce99b0e..5c6e617 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/BaseCustomTabActivity.java
@@ -303,7 +303,8 @@
             }
         };
 
-        new Thread(inflateTask).start();
+        // Run inflation task on UI thread due to threading issues in M85. See crbug.com/1112352
+        inflateTask.run();
     }
 
     private void onLayoutInflated(ViewGroup mainView) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index 4f8c5fb..3ce0238 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -198,7 +198,7 @@
 
     private final HiddenTabHolder mHiddenTabHolder = new HiddenTabHolder();
     protected final SessionDataHolder mSessionDataHolder;
-    @VisibleForTesting
+    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
     final ClientManager mClientManager;
     protected final boolean mLogRequests;
     private final AtomicBoolean mWarmupHasBeenCalled = new AtomicBoolean();
@@ -1082,7 +1082,6 @@
         return ExternalAuthUtils.getInstance().isGoogleSigned(packageName);
     }
 
-    @VisibleForTesting
     void setIgnoreUrlFragmentsForSession(CustomTabsSessionToken session, boolean value) {
         mClientManager.setIgnoreFragmentsForSession(session, value);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactory.java
index 356478f..9780f57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactory.java
@@ -49,7 +49,6 @@
      * @param force         if set to true, will override any existing generator for this type. Else
      *                      discards calls where a generator exists.
      */
-    @VisibleForTesting
     public static void registerGenerator(String generatorType, UniqueIdentificationGenerator gen,
                                          boolean force) {
         synchronized (LOCK) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java
index f551cae..3016eee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.offlinepages;
 
-import androidx.annotation.VisibleForTesting;
-
 /**
  * Simple object representing an offline page.
  */
@@ -37,61 +35,51 @@
     }
 
     /** @return URL of the offline page. */
-    @VisibleForTesting
     public String getUrl() {
         return mUrl;
     }
 
     /** @return offline id for this offline page. */
-    @VisibleForTesting
     public long getOfflineId() {
         return mOfflineId;
     }
 
     /** @return Client Id related to the offline page. */
-    @VisibleForTesting
     public ClientId getClientId() {
         return mClientId;
     }
 
     /** @return Title of the page. */
-    @VisibleForTesting
     public String getTitle() {
         return mTitle;
     }
 
     /** @return File Path to the offline copy of the page. */
-    @VisibleForTesting
     public String getFilePath() {
         return mFilePath;
     }
 
     /** @return Size of the offline copy of the page. */
-    @VisibleForTesting
     public long getFileSize() {
         return mFileSize;
     }
 
     /** @return Time in milliseconds the offline page was created. */
-    @VisibleForTesting
     public long getCreationTimeMs() {
         return mCreationTimeMs;
     }
 
     /** @return Number of times that the offline page has been accessed. */
-    @VisibleForTesting
     public int getAccessCount() {
         return mAccessCount;
     }
 
     /** @return Last time in milliseconds the offline page has been accessed. */
-    @VisibleForTesting
     public long getLastAccessTimeMs() {
         return mLastAccessTimeMs;
     }
 
     /** @return The originating application of the request. */
-    @VisibleForTesting
     public String getRequestOrigin() {
         return mRequestOrigin;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/RequestCoordinatorBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/RequestCoordinatorBridge.java
index 583115d4..83dc5abf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/RequestCoordinatorBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/RequestCoordinatorBridge.java
@@ -51,8 +51,7 @@
      *
      * @return A list of {@link SavePageRequest} representing all the queued requests.
      */
-    @VisibleForTesting
-    public void getRequestsInQueue(Callback<SavePageRequest[]> callback) {
+    void getRequestsInQueue(Callback<SavePageRequest[]> callback) {
         RequestCoordinatorBridgeJni.get().getRequestsInQueue(mProfile, callback);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
index 3f63211..49f45c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
@@ -45,8 +45,7 @@
 
     private final Context mApplicationContext;
 
-    @VisibleForTesting
-    public RequestGenerator(Context context) {
+    protected RequestGenerator(Context context) {
         mApplicationContext = context.getApplicationContext();
         UniqueIdentificationGeneratorFactory.registerGenerator(
                 SettingsSecureBasedIdentificationGenerator.GENERATOR_ID,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index dd4807d..dc5dbde0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -32,7 +32,6 @@
 import org.chromium.chrome.browser.payments.ui.ContactDetailsSection;
 import org.chromium.chrome.browser.payments.ui.LineItem;
 import org.chromium.chrome.browser.payments.ui.PaymentInformation;
-import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.OptionSection.FocusChangedObserver;
 import org.chromium.chrome.browser.payments.ui.PaymentRequestUI;
 import org.chromium.chrome.browser.payments.ui.PaymentRequestUI.SelectionResult;
 import org.chromium.chrome.browser.payments.ui.PaymentUIsManager;
@@ -49,7 +48,6 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
 import org.chromium.chrome.browser.ui.favicon.FaviconHelper;
-import org.chromium.components.autofill.Completable;
 import org.chromium.components.autofill.EditableOption;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
 import org.chromium.components.embedder_support.util.UrlConstants;
@@ -113,7 +111,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -129,7 +126,7 @@
                    PaymentAppFactoryDelegate, PaymentAppFactoryParams,
                    PaymentRequestUpdateEventListener, PaymentApp.AbortCallback,
                    PaymentApp.InstrumentDetailsCallback,
-                   PaymentResponseHelper.PaymentResponseRequesterDelegate, FocusChangedObserver,
+                   PaymentResponseHelper.PaymentResponseRequesterDelegate,
                    NormalizedAddressRequestDelegate, PaymentDetailsConverter.MethodChecker,
                    PaymentUIsManager.Delegate {
     /**
@@ -234,13 +231,7 @@
         void onRendererClosedMojoConnection();
     }
 
-    /** Limit in the number of suggested items in a section. */
-    public static final int SUGGESTIONS_LIMIT = 4;
-
     private static final String TAG = "PaymentRequest";
-    // Reverse order of the comparator to sort in descending order of completeness scores.
-    private static final Comparator<Completable> COMPLETENESS_COMPARATOR =
-            (a, b) -> (PaymentAppComparator.compareCompletablesByCompleteness(b, a));
 
     private ComponentPaymentRequestImpl mComponentPaymentRequestImpl;
 
@@ -250,8 +241,6 @@
     private boolean mRequestPayerPhone;
     private boolean mRequestPayerEmail;
 
-    private final Comparator<PaymentApp> mPaymentAppComparator;
-
     private static PaymentRequestServiceObserverForTest sObserverForTest;
     private static boolean sIsLocalCanMakePaymentQueryQuotaEnforcedForTest;
 
@@ -452,8 +441,7 @@
 
         if (sObserverForTest != null) sObserverForTest.onPaymentRequestCreated(this);
         mPaymentUIsManager = new PaymentUIsManager(/*delegate=*/this,
-                /*params=*/this, mWebContents, mIsOffTheRecord);
-        mPaymentAppComparator = new PaymentAppComparator(/*params=*/this);
+                /*params=*/this, mWebContents, mIsOffTheRecord, mJourneyLogger);
     }
 
     // Implement ComponentPaymentRequestDelegate:
@@ -628,7 +616,7 @@
                 && (mURLPaymentMethodIdentifiersSupported
                         || mSkipUiForNonUrlPaymentMethodIdentifiers)
                 && mPaymentUIsManager.getPaymentMethodsSection().getSize() >= 1
-                && onlySingleAppCanProvideAllRequiredInformation()
+                && mPaymentUIsManager.onlySingleAppCanProvideAllRequiredInformation()
                 // Skip to payment app only if it can be pre-selected.
                 && selectedApp != null
                 // Skip to payment app only if user gesture is provided when it is required to
@@ -636,37 +624,6 @@
                 && (mIsUserGestureShow || !selectedApp.isUserGestureRequiredToSkipUi());
     }
 
-    /**
-     * @return true when there is exactly one available payment app which can provide all requested
-     * information including shipping address and payer's contact information whenever needed.
-     */
-    private boolean onlySingleAppCanProvideAllRequiredInformation() {
-        assert mPaymentUIsManager.getPaymentMethodsSection() != null;
-
-        if (!mRequestShipping && !mRequestPayerName && !mRequestPayerPhone && !mRequestPayerEmail) {
-            return mPaymentUIsManager.getPaymentMethodsSection().getSize() == 1
-                    && !((PaymentApp) mPaymentUIsManager.getPaymentMethodsSection().getItem(0))
-                                .isAutofillInstrument();
-        }
-
-        boolean anAppCanProvideAllInfo = false;
-        int sectionSize = mPaymentUIsManager.getPaymentMethodsSection().getSize();
-        for (int i = 0; i < sectionSize; i++) {
-            PaymentApp app = (PaymentApp) mPaymentUIsManager.getPaymentMethodsSection().getItem(i);
-            if ((!mRequestShipping || app.handlesShippingAddress())
-                    && (!mRequestPayerName || app.handlesPayerName())
-                    && (!mRequestPayerPhone || app.handlesPayerPhone())
-                    && (!mRequestPayerEmail || app.handlesPayerEmail())) {
-                // There is more than one available app that can provide all merchant requested
-                // information information.
-                if (anAppCanProvideAllInfo) return false;
-
-                anAppCanProvideAllInfo = true;
-            }
-        }
-        return anAppCanProvideAllInfo;
-    }
-
     /** @return Whether the UI was built. */
     private boolean buildUI(ChromeActivity activity) {
         // Payment methods section must be ready before building the rest of the UI. This is because
@@ -711,7 +668,7 @@
         }
 
         if (shouldShowShippingSection() && !mWaitForUpdatedDetails) {
-            createShippingSection(activity, mPaymentUIsManager.getAutofillProfiles());
+            mPaymentUIsManager.createShippingSectionForPaymentRequestUI(activity);
         }
 
         if (shouldShowContactSection()) {
@@ -748,8 +705,7 @@
 
         // Add the callback to change the label of shipping addresses depending on the focus.
         if (mRequestShipping) {
-            mPaymentUIsManager.getPaymentRequestUI().setShippingAddressSectionFocusChangedObserver(
-                    this);
+            mPaymentUIsManager.setShippingAddressSectionFocusChangedObserverForPaymentRequestUI();
         }
 
         mPaymentUIsManager.getAddressEditor().setEditorDialog(
@@ -764,73 +720,6 @@
         return true;
     }
 
-    private void createShippingSection(
-            Context context, List<AutofillProfile> unmodifiableProfiles) {
-        List<AutofillAddress> addresses = new ArrayList<>();
-
-        for (int i = 0; i < unmodifiableProfiles.size(); i++) {
-            AutofillProfile profile = unmodifiableProfiles.get(i);
-            mPaymentUIsManager.getAddressEditor().addPhoneNumberIfValid(profile.getPhoneNumber());
-
-            // Only suggest addresses that have a street address.
-            if (!TextUtils.isEmpty(profile.getStreetAddress())) {
-                addresses.add(new AutofillAddress(context, profile));
-            }
-        }
-
-        // Suggest complete addresses first.
-        Collections.sort(addresses, COMPLETENESS_COMPARATOR);
-
-        // Limit the number of suggestions.
-        addresses = addresses.subList(0, Math.min(addresses.size(), SUGGESTIONS_LIMIT));
-
-        // Load the validation rules for each unique region code.
-        Set<String> uniqueCountryCodes = new HashSet<>();
-        for (int i = 0; i < addresses.size(); ++i) {
-            String countryCode = AutofillAddress.getCountryCode(addresses.get(i).getProfile());
-            if (!uniqueCountryCodes.contains(countryCode)) {
-                uniqueCountryCodes.add(countryCode);
-                PersonalDataManager.getInstance().loadRulesForAddressNormalization(countryCode);
-            }
-        }
-
-        // Automatically select the first address if one is complete and if the merchant does
-        // not require a shipping address to calculate shipping costs.
-        boolean hasCompleteShippingAddress = !addresses.isEmpty() && addresses.get(0).isComplete();
-        int firstCompleteAddressIndex = SectionInformation.NO_SELECTION;
-        if (mPaymentUIsManager.getUiShippingOptions().getSelectedItem() != null
-                && hasCompleteShippingAddress) {
-            firstCompleteAddressIndex = 0;
-
-            // The initial label for the selected shipping address should not include the
-            // country.
-            addresses.get(firstCompleteAddressIndex).setShippingAddressLabelWithoutCountry();
-        }
-
-        // Log the number of suggested shipping addresses and whether at least one of them is
-        // complete.
-        mJourneyLogger.setNumberOfSuggestionsShown(
-                Section.SHIPPING_ADDRESS, addresses.size(), hasCompleteShippingAddress);
-
-        int missingFields = 0;
-        if (addresses.isEmpty()) {
-            // All fields are missing.
-            missingFields = AutofillAddress.CompletionStatus.INVALID_RECIPIENT
-                    | AutofillAddress.CompletionStatus.INVALID_PHONE_NUMBER
-                    | AutofillAddress.CompletionStatus.INVALID_ADDRESS;
-        } else {
-            missingFields = addresses.get(0).getMissingFieldsOfShippingProfile();
-        }
-        if (missingFields != 0) {
-            RecordHistogram.recordSparseHistogram(
-                    "PaymentRequest.MissingShippingFields", missingFields);
-        }
-
-        mPaymentUIsManager.setShippingAddressesSection(
-                new SectionInformation(PaymentRequestUI.DataType.SHIPPING_ADDRESSES,
-                        firstCompleteAddressIndex, addresses));
-    }
-
     // Implement ComponentPaymentRequestDelegate:
     /**
      * Called by the merchant website to show the payment request to the user.
@@ -1285,7 +1174,7 @@
         // Do not create shipping section When UI is not built yet. This happens when the show
         // promise gets resolved before all apps are ready.
         if (mPaymentUIsManager.getPaymentRequestUI() != null && shouldShowShippingSection()) {
-            createShippingSection(chromeActivity, mPaymentUIsManager.getAutofillProfiles());
+            mPaymentUIsManager.createShippingSectionForPaymentRequestUI(chromeActivity);
         }
 
         mWaitForUpdatedDetails = false;
@@ -1452,24 +1341,7 @@
     @Override
     public void getSectionInformation(@PaymentRequestUI.DataType final int optionType,
             final Callback<SectionInformation> callback) {
-        SectionInformation result = null;
-        switch (optionType) {
-            case PaymentRequestUI.DataType.SHIPPING_ADDRESSES:
-                result = mPaymentUIsManager.getShippingAddressesSection();
-                break;
-            case PaymentRequestUI.DataType.SHIPPING_OPTIONS:
-                result = mPaymentUIsManager.getUiShippingOptions();
-                break;
-            case PaymentRequestUI.DataType.CONTACT_DETAILS:
-                result = mPaymentUIsManager.getContactSection();
-                break;
-            case PaymentRequestUI.DataType.PAYMENT_METHODS:
-                result = mPaymentUIsManager.getPaymentMethodsSection();
-                break;
-            default:
-                assert false;
-        }
-        mHandler.post(callback.bind(result));
+        mPaymentUIsManager.getSectionInformation(optionType, callback);
     }
 
     @Override
@@ -1518,7 +1390,7 @@
                     && mPaymentUIsManager.getShippingAddressesSection() == null) {
                 ChromeActivity activity = ChromeActivity.fromWebContents(mWebContents);
                 assert activity != null;
-                createShippingSection(activity, mPaymentUIsManager.getAutofillProfiles());
+                mPaymentUIsManager.createShippingSectionForPaymentRequestUI(activity);
             }
             if (shouldShowContactSection() && mPaymentUIsManager.getContactSection() == null) {
                 ChromeActivity activity = ChromeActivity.fromWebContents(mWebContents);
@@ -1533,7 +1405,7 @@
                 AutofillPaymentInstrument card = (AutofillPaymentInstrument) paymentApp;
 
                 if (!card.isComplete()) {
-                    editCard(card);
+                    mPaymentUIsManager.editCard(card);
                     return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
                 }
             }
@@ -1551,53 +1423,14 @@
     @PaymentRequestUI.SelectionResult
     public int onSectionEditOption(@PaymentRequestUI.DataType int optionType, EditableOption option,
             Callback<PaymentInformation> callback) {
-        if (optionType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES) {
-            // Log the edit of a shipping address.
-            mJourneyLogger.incrementSelectionEdits(Section.SHIPPING_ADDRESS);
-            mPaymentUIsManager.editAddress((AutofillAddress) option);
-            mPaymentUIsManager.setPaymentInformationCallback(callback);
-
-            return PaymentRequestUI.SelectionResult.ASYNCHRONOUS_VALIDATION;
-        }
-
-        if (optionType == PaymentRequestUI.DataType.CONTACT_DETAILS) {
-            mJourneyLogger.incrementSelectionEdits(Section.CONTACT_INFO);
-            mPaymentUIsManager.editContactOnPaymentRequestUI((AutofillContact) option);
-            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
-        }
-
-        if (optionType == PaymentRequestUI.DataType.PAYMENT_METHODS) {
-            editCard((AutofillPaymentInstrument) option);
-            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
-        }
-
-        assert false;
-        return PaymentRequestUI.SelectionResult.NONE;
+        return mPaymentUIsManager.onSectionEditOption(optionType, option, callback);
     }
 
     @Override
     @PaymentRequestUI.SelectionResult
     public int onSectionAddOption(
             @PaymentRequestUI.DataType int optionType, Callback<PaymentInformation> callback) {
-        if (optionType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES) {
-            mPaymentUIsManager.editAddress(null);
-            mPaymentUIsManager.setPaymentInformationCallback(callback);
-            // Log the add of shipping address.
-            mJourneyLogger.incrementSelectionAdds(Section.SHIPPING_ADDRESS);
-            return PaymentRequestUI.SelectionResult.ASYNCHRONOUS_VALIDATION;
-        } else if (optionType == PaymentRequestUI.DataType.CONTACT_DETAILS) {
-            mPaymentUIsManager.editContactOnPaymentRequestUI(null);
-            // Log the add of contact info.
-            mJourneyLogger.incrementSelectionAdds(Section.CONTACT_INFO);
-            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
-        } else if (optionType == PaymentRequestUI.DataType.PAYMENT_METHODS) {
-            editCard(null);
-            // Log the add of credit card.
-            mJourneyLogger.incrementSelectionAdds(Section.PAYMENT_METHOD);
-            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
-        }
-
-        return PaymentRequestUI.SelectionResult.NONE;
+        return mPaymentUIsManager.onSectionAddOption(optionType, callback);
     }
 
     @Override
@@ -1610,43 +1443,6 @@
         return mPaymentUIsManager.shouldShowContactSection();
     }
 
-    private void editCard(final AutofillPaymentInstrument toEdit) {
-        if (toEdit != null) {
-            // Log the edit of a credit card.
-            mJourneyLogger.incrementSelectionEdits(Section.PAYMENT_METHOD);
-        }
-        mPaymentUIsManager.getCardEditor().edit(toEdit, new Callback<AutofillPaymentInstrument>() {
-            @Override
-            public void onResult(AutofillPaymentInstrument editedCard) {
-                if (mPaymentUIsManager.getPaymentRequestUI() == null) return;
-
-                if (editedCard != null) {
-                    // A partial or complete card came back from the editor (could have been from
-                    // adding/editing or cancelling out of the edit flow).
-                    if (!editedCard.isComplete()) {
-                        // If the card is not complete, unselect it (editor can return incomplete
-                        // information when cancelled).
-                        mPaymentUIsManager.getPaymentMethodsSection().setSelectedItemIndex(
-                                SectionInformation.NO_SELECTION);
-                    } else if (toEdit == null) {
-                        // Card is complete and we were in the "Add flow": add an item to the list.
-                        mPaymentUIsManager.getPaymentMethodsSection().addAndSelectItem(editedCard);
-                    }
-                    // If card is complete and (toEdit != null), no action needed: the card was
-                    // already selected in the UI.
-                }
-                // If |editedCard| is null, the user has cancelled out of the "Add flow". No action
-                // to take (if another card was selected prior to the add flow, it will stay
-                // selected).
-
-                mPaymentUIsManager.updateAppModifiedTotals();
-                mPaymentUIsManager.getPaymentRequestUI().updateSection(
-                        PaymentRequestUI.DataType.PAYMENT_METHODS,
-                        mPaymentUIsManager.getPaymentMethodsSection());
-            }
-        });
-    }
-
     @Override
     public void onInstrumentDetailsLoadingWithoutUI() {
         if (getClient() == null || mPaymentUIsManager.getPaymentRequestUI() == null
@@ -2232,7 +2028,7 @@
             }
         }
 
-        Collections.sort(mPendingApps, mPaymentAppComparator);
+        mPaymentUIsManager.rankPaymentAppsForPaymentRequestUI(mPendingApps);
 
         // Possibly pre-select the first app on the list.
         int selection = !mPendingApps.isEmpty() && mPendingApps.get(0).canPreselect()
@@ -2457,28 +2253,6 @@
     }
 
     @Override
-    public void onFocusChanged(@PaymentRequestUI.DataType int dataType, boolean willFocus) {
-        assert dataType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES;
-
-        if (mPaymentUIsManager.getShippingAddressesSection().getSelectedItem() == null) return;
-
-        AutofillAddress selectedAddress =
-                (AutofillAddress) mPaymentUIsManager.getShippingAddressesSection()
-                        .getSelectedItem();
-
-        // The label should only include the country if the view is focused.
-        if (willFocus) {
-            selectedAddress.setShippingAddressLabelWithCountry();
-        } else {
-            selectedAddress.setShippingAddressLabelWithoutCountry();
-        }
-
-        mPaymentUIsManager.getPaymentRequestUI().updateSection(
-                PaymentRequestUI.DataType.SHIPPING_ADDRESSES,
-                mPaymentUIsManager.getShippingAddressesSection());
-    }
-
-    @Override
     public void onAddressNormalized(AutofillProfile profile) {
         PaymentRequestClient client = getClient();
         if (client == null) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java
index cee3b3d..d0f2e1b3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java
@@ -14,7 +14,6 @@
 import org.chromium.chrome.browser.payments.AutofillAddress;
 import org.chromium.chrome.browser.payments.AutofillContact;
 import org.chromium.chrome.browser.payments.ContactEditor;
-import org.chromium.chrome.browser.payments.PaymentRequestImpl;
 import org.chromium.components.payments.JourneyLogger;
 import org.chromium.components.payments.Section;
 
@@ -138,7 +137,7 @@
             if (isNewSuggestion) uniqueContacts.add(contact);
 
             // Limit the number of suggestions.
-            if (uniqueContacts.size() == PaymentRequestImpl.SUGGESTIONS_LIMIT) break;
+            if (uniqueContacts.size() == PaymentUIsManager.SUGGESTIONS_LIMIT) break;
         }
 
         // Automatically select the first address if it is complete.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppComparator.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentAppComparator.java
similarity index 97%
rename from chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppComparator.java
rename to chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentAppComparator.java
index 740afcf..a0d2594 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentAppComparator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentAppComparator.java
@@ -2,8 +2,9 @@
 // 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.payments;
+package org.chromium.chrome.browser.payments.ui;
 
+import org.chromium.chrome.browser.payments.PaymentPreferencesUtil;
 import org.chromium.components.autofill.Completable;
 import org.chromium.components.payments.PaymentApp;
 import org.chromium.components.payments.PaymentRequestParams;
@@ -11,7 +12,7 @@
 
 import java.util.Comparator;
 
-/** A comparator that is used to rank the payment apps to be listed in the payment sheet. */
+/** A comparator that is used to rank the payment apps to be listed on the PaymentRequest UI. */
 /* package */ class PaymentAppComparator implements Comparator<PaymentApp> {
     private final PaymentRequestParams mParams;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUIsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUIsManager.java
index b827ebc1..15f69e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUIsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentUIsManager.java
@@ -4,12 +4,15 @@
 
 package org.chromium.chrome.browser.payments.ui;
 
+import android.content.Context;
 import android.os.Handler;
+import android.text.TextUtils;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
@@ -19,6 +22,7 @@
 import org.chromium.chrome.browser.payments.AutofillContact;
 import org.chromium.chrome.browser.payments.AutofillPaymentAppCreator;
 import org.chromium.chrome.browser.payments.AutofillPaymentAppFactory;
+import org.chromium.chrome.browser.payments.AutofillPaymentInstrument;
 import org.chromium.chrome.browser.payments.CardEditor;
 import org.chromium.chrome.browser.payments.ContactEditor;
 import org.chromium.chrome.browser.payments.PaymentRequestImpl;
@@ -27,14 +31,18 @@
 import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator;
 import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator.PaymentHandlerUiObserver;
 import org.chromium.chrome.browser.payments.handler.PaymentHandlerCoordinator.PaymentHandlerWebContentsObserver;
+import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.OptionSection.FocusChangedObserver;
+import org.chromium.components.autofill.Completable;
 import org.chromium.components.autofill.EditableOption;
 import org.chromium.components.payments.CurrencyFormatter;
+import org.chromium.components.payments.JourneyLogger;
 import org.chromium.components.payments.PaymentApp;
 import org.chromium.components.payments.PaymentAppType;
 import org.chromium.components.payments.PaymentFeatureList;
 import org.chromium.components.payments.PaymentOptionsUtils;
 import org.chromium.components.payments.PaymentRequestLifecycleObserver;
 import org.chromium.components.payments.PaymentRequestParams;
+import org.chromium.components.payments.Section;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.payments.mojom.PayerDetail;
 import org.chromium.payments.mojom.PaymentCurrencyAmount;
@@ -48,6 +56,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -62,8 +71,16 @@
  * should be moved into this class.
  */
 public class PaymentUIsManager implements SettingsAutofillAndPaymentsObserver.Observer,
-                                          PaymentRequestLifecycleObserver,
-                                          PaymentHandlerUiObserver {
+                                          PaymentRequestLifecycleObserver, PaymentHandlerUiObserver,
+                                          FocusChangedObserver {
+    /** Limit in the number of suggested items in a section. */
+    /* package */ static final int SUGGESTIONS_LIMIT = 4;
+
+    // Reverse order of the comparator to sort in descending order of completeness scores.
+    private static final Comparator<Completable> COMPLETENESS_COMPARATOR =
+            (a, b) -> (PaymentAppComparator.compareCompletablesByCompleteness(b, a));
+    private final Comparator<PaymentApp> mPaymentAppComparator;
+
     private final boolean mIsOffTheRecord;
     private final Handler mHandler = new Handler();
     private final Queue<Runnable> mRetryQueue = new LinkedList<>();
@@ -89,6 +106,7 @@
     private boolean mHaveRequestedAutofillData = true;
     private List<AutofillProfile> mAutofillProfiles;
     private Boolean mCanUserAddCreditCard;
+    private final JourneyLogger mJourneyLogger;
 
     /** The delegate of this class. */
     public interface Delegate {
@@ -160,9 +178,10 @@
      * @param params The parameters of the payment request specified by the merchant.
      * @param webContents The WebContents of the merchant page.
      * @param isOffTheRecord Whether merchant page is in an isOffTheRecord tab.
+     * @param journeyLogger The logger of the user journey.
      */
     public PaymentUIsManager(Delegate delegate, PaymentRequestParams params,
-            WebContents webContents, boolean isOffTheRecord) {
+            WebContents webContents, boolean isOffTheRecord, JourneyLogger journeyLogger) {
         mDelegate = delegate;
         mParams = params;
 
@@ -172,10 +191,12 @@
         // PaymentRequest card editor does not show the organization name in the dropdown with the
         // billing address labels.
         mCardEditor = new CardEditor(webContents, mAddressEditor, /*includeOrgLabel=*/false);
+        mJourneyLogger = journeyLogger;
 
         mPaymentUisShowStateReconciler = new PaymentUisShowStateReconciler();
         mCurrencyFormatterMap = new HashMap<>();
         mIsOffTheRecord = isOffTheRecord;
+        mPaymentAppComparator = new PaymentAppComparator(/*params=*/mParams);
     }
 
     /**
@@ -761,9 +782,9 @@
 
     /**
      * Edit the contact information on the PaymentRequest UI.
-     * @param toEdit The information to edit.
+     * @param toEdit The information to edit, allowed to be null.
      **/
-    public void editContactOnPaymentRequestUI(final AutofillContact toEdit) {
+    public void editContactOnPaymentRequestUI(@Nullable final AutofillContact toEdit) {
         mContactEditor.edit(toEdit, new Callback<AutofillContact>() {
             @Override
             public void onResult(AutofillContact editedContact) {
@@ -802,9 +823,9 @@
 
     /**
      * Edit the address on the PaymentRequest UI.
-     * @param toEdit The address to edit.
+     * @param toEdit The address to be updated with, allowed to be null.
      */
-    public void editAddress(final AutofillAddress toEdit) {
+    public void editAddress(@Nullable final AutofillAddress toEdit) {
         mAddressEditor.edit(toEdit, new Callback<AutofillAddress>() {
             @Override
             public void onResult(AutofillAddress editedAddress) {
@@ -854,4 +875,252 @@
             }
         });
     }
+
+    /** Create a shipping section for PaymentRequest UI. */
+    public void createShippingSectionForPaymentRequestUI(Context context) {
+        List<AutofillAddress> addresses = new ArrayList<>();
+
+        for (int i = 0; i < mAutofillProfiles.size(); i++) {
+            AutofillProfile profile = mAutofillProfiles.get(i);
+            mAddressEditor.addPhoneNumberIfValid(profile.getPhoneNumber());
+
+            // Only suggest addresses that have a street address.
+            if (!TextUtils.isEmpty(profile.getStreetAddress())) {
+                addresses.add(new AutofillAddress(context, profile));
+            }
+        }
+
+        // Suggest complete addresses first.
+        Collections.sort(addresses, COMPLETENESS_COMPARATOR);
+
+        // Limit the number of suggestions.
+        addresses = addresses.subList(0, Math.min(addresses.size(), SUGGESTIONS_LIMIT));
+
+        // Load the validation rules for each unique region code.
+        Set<String> uniqueCountryCodes = new HashSet<>();
+        for (int i = 0; i < addresses.size(); ++i) {
+            String countryCode = AutofillAddress.getCountryCode(addresses.get(i).getProfile());
+            if (!uniqueCountryCodes.contains(countryCode)) {
+                uniqueCountryCodes.add(countryCode);
+                PersonalDataManager.getInstance().loadRulesForAddressNormalization(countryCode);
+            }
+        }
+
+        // Automatically select the first address if one is complete and if the merchant does
+        // not require a shipping address to calculate shipping costs.
+        boolean hasCompleteShippingAddress = !addresses.isEmpty() && addresses.get(0).isComplete();
+        int firstCompleteAddressIndex = SectionInformation.NO_SELECTION;
+        if (mUiShippingOptions.getSelectedItem() != null && hasCompleteShippingAddress) {
+            firstCompleteAddressIndex = 0;
+
+            // The initial label for the selected shipping address should not include the
+            // country.
+            addresses.get(firstCompleteAddressIndex).setShippingAddressLabelWithoutCountry();
+        }
+
+        // Log the number of suggested shipping addresses and whether at least one of them is
+        // complete.
+        mJourneyLogger.setNumberOfSuggestionsShown(
+                Section.SHIPPING_ADDRESS, addresses.size(), hasCompleteShippingAddress);
+
+        int missingFields = 0;
+        if (addresses.isEmpty()) {
+            // All fields are missing.
+            missingFields = AutofillAddress.CompletionStatus.INVALID_RECIPIENT
+                    | AutofillAddress.CompletionStatus.INVALID_PHONE_NUMBER
+                    | AutofillAddress.CompletionStatus.INVALID_ADDRESS;
+        } else {
+            missingFields = addresses.get(0).getMissingFieldsOfShippingProfile();
+        }
+        if (missingFields != 0) {
+            RecordHistogram.recordSparseHistogram(
+                    "PaymentRequest.MissingShippingFields", missingFields);
+        }
+
+        mShippingAddressesSection = new SectionInformation(
+                PaymentRequestUI.DataType.SHIPPING_ADDRESSES, firstCompleteAddressIndex, addresses);
+    }
+
+    /**
+     * Rank the payment apps for PaymentRequest UI.
+     * @param paymentApps A list of payment apps to be ranked in place.
+     */
+    public void rankPaymentAppsForPaymentRequestUI(List<PaymentApp> paymentApps) {
+        Collections.sort(paymentApps, mPaymentAppComparator);
+    }
+
+    /**
+     * Edit the credit cards on the PaymentRequest UI.
+     * @param toEdit The AutofillPaymentInstrument whose credit card is to replace those on the UI,
+     *         allowed to be null.
+     */
+    public void editCard(@Nullable final AutofillPaymentInstrument toEdit) {
+        if (toEdit != null) {
+            // Log the edit of a credit card.
+            mJourneyLogger.incrementSelectionEdits(Section.PAYMENT_METHOD);
+        }
+        mCardEditor.edit(toEdit, new Callback<AutofillPaymentInstrument>() {
+            @Override
+            public void onResult(AutofillPaymentInstrument editedCard) {
+                if (mPaymentRequestUI == null) return;
+
+                if (editedCard != null) {
+                    // A partial or complete card came back from the editor (could have been from
+                    // adding/editing or cancelling out of the edit flow).
+                    if (!editedCard.isComplete()) {
+                        // If the card is not complete, unselect it (editor can return incomplete
+                        // information when cancelled).
+                        mPaymentMethodsSection.setSelectedItemIndex(
+                                SectionInformation.NO_SELECTION);
+                    } else if (toEdit == null) {
+                        // Card is complete and we were in the "Add flow": add an item to the list.
+                        mPaymentMethodsSection.addAndSelectItem(editedCard);
+                    }
+                    // If card is complete and (toEdit != null), no action needed: the card was
+                    // already selected in the UI.
+                }
+                // If |editedCard| is null, the user has cancelled out of the "Add flow". No action
+                // to take (if another card was selected prior to the add flow, it will stay
+                // selected).
+
+                updateAppModifiedTotals();
+                mPaymentRequestUI.updateSection(
+                        PaymentRequestUI.DataType.PAYMENT_METHODS, mPaymentMethodsSection);
+            }
+        });
+    }
+
+    /** See {@link PaymentRequestUI.getSelectionInformation}. */
+    public void getSectionInformation(@PaymentRequestUI.DataType final int optionType,
+            final Callback<SectionInformation> callback) {
+        SectionInformation result = null;
+        switch (optionType) {
+            case PaymentRequestUI.DataType.SHIPPING_ADDRESSES:
+                result = mShippingAddressesSection;
+                break;
+            case PaymentRequestUI.DataType.SHIPPING_OPTIONS:
+                result = mUiShippingOptions;
+                break;
+            case PaymentRequestUI.DataType.CONTACT_DETAILS:
+                result = mContactSection;
+                break;
+            case PaymentRequestUI.DataType.PAYMENT_METHODS:
+                result = mPaymentMethodsSection;
+                break;
+            default:
+                assert false;
+        }
+        mHandler.post(callback.bind(result));
+    }
+
+    // Implement PaymentRequestSection.FocusChangedObserver:
+    @Override
+    public void onFocusChanged(@PaymentRequestUI.DataType int dataType, boolean willFocus) {
+        assert dataType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES;
+
+        if (mShippingAddressesSection.getSelectedItem() == null) return;
+
+        AutofillAddress selectedAddress =
+                (AutofillAddress) mShippingAddressesSection.getSelectedItem();
+
+        // The label should only include the country if the view is focused.
+        if (willFocus) {
+            selectedAddress.setShippingAddressLabelWithCountry();
+        } else {
+            selectedAddress.setShippingAddressLabelWithoutCountry();
+        }
+
+        mPaymentRequestUI.updateSection(
+                PaymentRequestUI.DataType.SHIPPING_ADDRESSES, mShippingAddressesSection);
+    }
+
+    /** See {@link PaymentRequestUI.Client.onSectionAddOption}. */
+    public int onSectionAddOption(
+            @PaymentRequestUI.DataType int optionType, Callback<PaymentInformation> callback) {
+        if (optionType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES) {
+            editAddress(null);
+            mPaymentInformationCallback = callback;
+            // Log the add of shipping address.
+            mJourneyLogger.incrementSelectionAdds(Section.SHIPPING_ADDRESS);
+            return PaymentRequestUI.SelectionResult.ASYNCHRONOUS_VALIDATION;
+        } else if (optionType == PaymentRequestUI.DataType.CONTACT_DETAILS) {
+            editContactOnPaymentRequestUI(null);
+            // Log the add of contact info.
+            mJourneyLogger.incrementSelectionAdds(Section.CONTACT_INFO);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        } else if (optionType == PaymentRequestUI.DataType.PAYMENT_METHODS) {
+            editCard(null);
+            // Log the add of credit card.
+            mJourneyLogger.incrementSelectionAdds(Section.PAYMENT_METHOD);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        }
+
+        return PaymentRequestUI.SelectionResult.NONE;
+    }
+
+    @PaymentRequestUI.SelectionResult
+    public int onSectionEditOption(@PaymentRequestUI.DataType int optionType, EditableOption option,
+            Callback<PaymentInformation> callback) {
+        if (optionType == PaymentRequestUI.DataType.SHIPPING_ADDRESSES) {
+            // Log the edit of a shipping address.
+            mJourneyLogger.incrementSelectionEdits(Section.SHIPPING_ADDRESS);
+            editAddress((AutofillAddress) option);
+            mPaymentInformationCallback = callback;
+
+            return PaymentRequestUI.SelectionResult.ASYNCHRONOUS_VALIDATION;
+        }
+
+        if (optionType == PaymentRequestUI.DataType.CONTACT_DETAILS) {
+            mJourneyLogger.incrementSelectionEdits(Section.CONTACT_INFO);
+            editContactOnPaymentRequestUI((AutofillContact) option);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        }
+
+        if (optionType == PaymentRequestUI.DataType.PAYMENT_METHODS) {
+            editCard((AutofillPaymentInstrument) option);
+            return PaymentRequestUI.SelectionResult.EDITOR_LAUNCH;
+        }
+
+        assert false;
+        return PaymentRequestUI.SelectionResult.NONE;
+    }
+
+    /** Set a change observer for the shipping address section on the PaymentRequest UI. */
+    public void setShippingAddressSectionFocusChangedObserverForPaymentRequestUI() {
+        mPaymentRequestUI.setShippingAddressSectionFocusChangedObserver(this);
+    }
+
+    /**
+     * @return true when there is exactly one available payment app which can provide all requested
+     * information including shipping address and payer's contact information whenever needed.
+     */
+    public boolean onlySingleAppCanProvideAllRequiredInformation() {
+        assert mPaymentMethodsSection != null;
+
+        if (!PaymentOptionsUtils.requestAnyInformation(mParams.getPaymentOptions())) {
+            return mPaymentMethodsSection.getSize() == 1
+                    && !((PaymentApp) mPaymentMethodsSection.getItem(0)).isAutofillInstrument();
+        }
+
+        boolean anAppCanProvideAllInfo = false;
+        int sectionSize = mPaymentMethodsSection.getSize();
+        for (int i = 0; i < sectionSize; i++) {
+            PaymentApp app = (PaymentApp) mPaymentMethodsSection.getItem(i);
+            if ((!PaymentOptionsUtils.requestShipping(mParams.getPaymentOptions())
+                        || app.handlesShippingAddress())
+                    && (!PaymentOptionsUtils.requestPayerName(mParams.getPaymentOptions())
+                            || app.handlesPayerName())
+                    && (!PaymentOptionsUtils.requestPayerPhone(mParams.getPaymentOptions())
+                            || app.handlesPayerPhone())
+                    && (!PaymentOptionsUtils.requestPayerEmail(mParams.getPaymentOptions())
+                            || app.handlesPayerEmail())) {
+                // There is more than one available app that can provide all merchant requested
+                // information information.
+                if (anAppCanProvideAllInfo) return false;
+
+                anAppCanProvideAllInfo = true;
+            }
+        }
+        return anAppCanProvideAllInfo;
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SafeBrowsingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SafeBrowsingTest.java
index 1fb617cf..de77547 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/SafeBrowsingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SafeBrowsingTest.java
@@ -16,10 +16,12 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.safe_browsing.SafeBrowsingApiBridge;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
@@ -34,6 +36,7 @@
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+@Features.DisableFeatures({ChromeFeatureList.SAFE_BROWSING_DELAYED_WARNINGS})
 public final class SafeBrowsingTest {
     @Rule
     public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
index ceac214..b840207 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
@@ -318,8 +318,11 @@
      */
     @Test
     @SmallTest
-    @DisableFeatures(ChromeFeatureList.SPLIT_CACHE_BY_NETWORK_ISOLATION_KEY)
-    public void testSafeBrowsingMainResource() throws Exception {
+    @DisableFeatures({ChromeFeatureList.SPLIT_CACHE_BY_NETWORK_ISOLATION_KEY,
+            ChromeFeatureList.SAFE_BROWSING_DELAYED_WARNINGS})
+
+    public void
+    testSafeBrowsingMainResource() throws Exception {
         testSafeBrowsingMainResource(true /* afterNative */, false /* splitCacheEnabled */);
     }
 
@@ -330,6 +333,7 @@
     @Test
     @SmallTest
     @EnableFeatures(ChromeFeatureList.SPLIT_CACHE_BY_NETWORK_ISOLATION_KEY)
+    @DisableFeatures(ChromeFeatureList.SAFE_BROWSING_DELAYED_WARNINGS)
     public void testSafeBrowsingMainResourceWithSplitCache() throws Exception {
         testSafeBrowsingMainResource(true /* afterNative */, true /* splitCacheEnabled */);
     }
@@ -340,6 +344,7 @@
      */
     @Test
     @SmallTest
+    @DisableFeatures({ChromeFeatureList.SAFE_BROWSING_DELAYED_WARNINGS})
     public void testSafeBrowsingSubresource() throws Exception {
         testSafeBrowsingSubresource(true);
     }
@@ -350,8 +355,10 @@
      */
     @Test
     @SmallTest
-    @DisableFeatures(ChromeFeatureList.SPLIT_CACHE_BY_NETWORK_ISOLATION_KEY)
-    public void testSafeBrowsingMainResourceBeforeNative() throws Exception {
+    @DisableFeatures({ChromeFeatureList.SPLIT_CACHE_BY_NETWORK_ISOLATION_KEY,
+            ChromeFeatureList.SAFE_BROWSING_DELAYED_WARNINGS})
+    public void
+    testSafeBrowsingMainResourceBeforeNative() throws Exception {
         testSafeBrowsingMainResource(false /* afterNative */, false /* splitCacheEnabled */);
     }
 
@@ -361,6 +368,7 @@
      */
     @Test
     @SmallTest
+    @Features.DisableFeatures({ChromeFeatureList.SAFE_BROWSING_DELAYED_WARNINGS})
     public void testSafeBrowsingSubresourceBeforeNative() throws Exception {
         testSafeBrowsingSubresource(false);
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurfaceTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurfaceTest.java
index e5904df6..10cf8911 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurfaceTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/feed/v2/FeedStreamSurfaceTest.java
@@ -38,6 +38,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Captor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
@@ -590,12 +591,17 @@
     @SmallTest
     public void testClearAll() {
         FeedStreamSurface.startup();
+        InOrder order = Mockito.inOrder(mFeedStreamSurfaceJniMock, mProcessScope);
         mFeedStreamSurface.surfaceOpened();
-        verify(mFeedStreamSurfaceJniMock).surfaceOpened(anyLong(), any(FeedStreamSurface.class));
+        order.verify(mFeedStreamSurfaceJniMock)
+                .surfaceOpened(anyLong(), any(FeedStreamSurface.class));
 
         FeedStreamSurface.clearAll();
-        verify(mFeedStreamSurfaceJniMock).surfaceClosed(anyLong(), any(FeedStreamSurface.class));
-        verify(mProcessScope).resetAccount();
+        order.verify(mFeedStreamSurfaceJniMock)
+                .surfaceClosed(anyLong(), any(FeedStreamSurface.class));
+        order.verify(mProcessScope).resetAccount();
+        order.verify(mFeedStreamSurfaceJniMock)
+                .surfaceOpened(anyLong(), any(FeedStreamSurface.class));
     }
 
     @Test
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ea32c54..4eba640 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6060,6 +6060,9 @@
         <message name="IDS_PASSWORD_MANAGER_ACCESSORY_ALL_PASSWORDS_LINK" desc="The text of the link in the password sheet that opens the password management section.">
           Manage passwords
         </message>
+        <message name="IDS_PASSWORD_MANAGER_ACCESSORY_USE_OTHER_PASSWORD" desc="The text of the link in the password sheet that opens a bottom sheet which shows all saved passwords from any origin.">
+          Use other password
+        </message>
         <message name="IDS_PASSWORD_MANAGER_ACCESSORY_GENERATE_PASSWORD_BUTTON_TITLE" desc="Text for the button used to generate a password.">
           Suggest strong password
         </message>
diff --git a/chrome/app/generated_resources_grd/IDS_PASSWORD_MANAGER_ACCESSORY_USE_OTHER_PASSWORD.png.sha1 b/chrome/app/generated_resources_grd/IDS_PASSWORD_MANAGER_ACCESSORY_USE_OTHER_PASSWORD.png.sha1
new file mode 100644
index 0000000..8f1c92d
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_PASSWORD_MANAGER_ACCESSORY_USE_OTHER_PASSWORD.png.sha1
@@ -0,0 +1 @@
+813869837d077ccb1dc094eaf062345de9c70116
\ No newline at end of file
diff --git a/chrome/app/profiles_strings.grdp b/chrome/app/profiles_strings.grdp
index 3927896..2d1e688 100644
--- a/chrome/app/profiles_strings.grdp
+++ b/chrome/app/profiles_strings.grdp
@@ -667,6 +667,9 @@
     <message name="IDS_PROFILE_PICKER_ASK_ON_STARTUP" desc="Text for the checkbox on the profile picker main view">
       Ask on startup
     </message>
+    <message name="IDS_PROFILE_PICKER_BROWSE_AS_GUEST_BUTTON" desc="Text for the profile picker main view button that launches guest session.">
+      Browse as Guest
+    </message>
     <message name="IDS_PROFILE_PICKER_BACK_BUTTON_LABEL" desc="Label for a button that navigates user to the previous page">
       Back
     </message>
diff --git a/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_BROWSE_AS_GUEST_BUTTON.png.sha1 b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_BROWSE_AS_GUEST_BUTTON.png.sha1
new file mode 100644
index 0000000..fbd2c11
--- /dev/null
+++ b/chrome/app/profiles_strings_grdp/IDS_PROFILE_PICKER_BROWSE_AS_GUEST_BUTTON.png.sha1
@@ -0,0 +1 @@
+12998557c02a35e50d016c53c9ab9bc3a778c724
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c7ed1f0..10fff30 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2787,6 +2787,10 @@
       "password_check/android/password_check_bridge.h",
       "password_manager/android/account_chooser_dialog_android.cc",
       "password_manager/android/account_chooser_dialog_android.h",
+      "password_manager/android/all_passwords_bottom_sheet_controller.cc",
+      "password_manager/android/all_passwords_bottom_sheet_controller.h",
+      "password_manager/android/all_passwords_bottom_sheet_view.cc",
+      "password_manager/android/all_passwords_bottom_sheet_view.h",
       "password_manager/android/auto_signin_first_run_dialog_android.cc",
       "password_manager/android/auto_signin_first_run_dialog_android.h",
       "password_manager/android/auto_signin_prompt_controller.cc",
diff --git a/chrome/browser/autofill/manual_filling_controller_impl.cc b/chrome/browser/autofill/manual_filling_controller_impl.cc
index 616cb0a..977ea9c5 100644
--- a/chrome/browser/autofill/manual_filling_controller_impl.cc
+++ b/chrome/browser/autofill/manual_filling_controller_impl.cc
@@ -297,6 +297,7 @@
   switch (action) {
     case AccessoryAction::GENERATE_PASSWORD_MANUAL:
     case AccessoryAction::MANAGE_PASSWORDS:
+    case AccessoryAction::USE_OTHER_PASSWORD:
     case AccessoryAction::GENERATE_PASSWORD_AUTOMATIC:
     case AccessoryAction::TOGGLE_SAVE_PASSWORDS:
       return GetPasswordController();
diff --git a/chrome/browser/browser_switcher/browser_switcher_service_browsertest.cc b/chrome/browser/browser_switcher/browser_switcher_service_browsertest.cc
index 62a0c79..d498242 100644
--- a/chrome/browser/browser_switcher/browser_switcher_service_browsertest.cc
+++ b/chrome/browser/browser_switcher/browser_switcher_service_browsertest.cc
@@ -81,14 +81,13 @@
 
 void SetPolicy(policy::PolicyMap* policies,
                const char* key,
-               std::unique_ptr<base::Value> value) {
+               base::Value value) {
   policies->Set(key, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
                 policy::POLICY_SOURCE_PLATFORM, std::move(value), nullptr);
 }
 
 void EnableBrowserSwitcher(policy::PolicyMap* policies) {
-  SetPolicy(policies, policy::key::kBrowserSwitcherEnabled,
-            std::make_unique<base::Value>(true));
+  SetPolicy(policies, policy::key::kBrowserSwitcherEnabled, base::Value(true));
 }
 
 }  // namespace
@@ -128,7 +127,7 @@
     policy::PolicyMap policies;
     EnableBrowserSwitcher(&policies);
     SetPolicy(&policies, policy::key::kBrowserSwitcherUseIeSitelist,
-              std::make_unique<base::Value>(use_ie_sitelist));
+              base::Value(use_ie_sitelist));
     provider_.UpdateChromePolicy(policies);
     base::RunLoop().RunUntilIdle();
   }
@@ -137,7 +136,7 @@
     policy::PolicyMap policies;
     EnableBrowserSwitcher(&policies);
     SetPolicy(&policies, policy::key::kBrowserSwitcherExternalSitelistUrl,
-              std::make_unique<base::Value>(url));
+              base::Value(url));
     provider_.UpdateChromePolicy(policies);
     base::RunLoop().RunUntilIdle();
   }
@@ -368,12 +367,12 @@
                        ExternalGreylistFetchAndParseAfterStartup) {
   policy::PolicyMap policies;
   EnableBrowserSwitcher(&policies);
-  auto url_list = std::make_unique<base::ListValue>();
-  url_list->Append("*");
+  base::Value url_list(base::Value::Type::LIST);
+  url_list.Append("*");
   SetPolicy(&policies, policy::key::kBrowserSwitcherUrlList,
             std::move(url_list));
   SetPolicy(&policies, policy::key::kBrowserSwitcherExternalGreylistUrl,
-            std::make_unique<base::Value>(kAValidUrl));
+            base::Value(kAValidUrl));
   policy_provider().UpdateChromePolicy(policies);
   base::RunLoop().RunUntilIdle();
 
@@ -513,23 +512,23 @@
   policy::PolicyMap policies;
   EnableBrowserSwitcher(&policies);
   SetPolicy(&policies, policy::key::kAlternativeBrowserPath,
-            std::make_unique<base::Value>("IExplore.exe"));
-  auto alt_params = std::make_unique<base::ListValue>();
-  alt_params->Append(base::Value("--bogus-flag"));
+            base::Value("IExplore.exe"));
+  base::Value alt_params(base::Value::Type::LIST);
+  alt_params.Append("--bogus-flag");
   SetPolicy(&policies, policy::key::kAlternativeBrowserParameters,
             std::move(alt_params));
   SetPolicy(&policies, policy::key::kBrowserSwitcherChromePath,
-            std::make_unique<base::Value>("chrome.exe"));
-  auto chrome_params = std::make_unique<base::ListValue>();
-  chrome_params->Append(base::Value("--force-dark-mode"));
+            base::Value("chrome.exe"));
+  base::Value chrome_params(base::Value::Type::LIST);
+  chrome_params.Append("--force-dark-mode");
   SetPolicy(&policies, policy::key::kBrowserSwitcherChromeParameters,
             std::move(chrome_params));
-  auto url_list = std::make_unique<base::ListValue>();
-  url_list->Append(base::Value("example.com"));
+  base::Value url_list(base::Value::Type::LIST);
+  url_list.Append("example.com");
   SetPolicy(&policies, policy::key::kBrowserSwitcherUrlList,
             std::move(url_list));
-  auto greylist = std::make_unique<base::ListValue>();
-  greylist->Append(base::Value("foo.example.com"));
+  base::Value greylist(base::Value::Type::LIST);
+  greylist.Append("foo.example.com");
   SetPolicy(&policies, policy::key::kBrowserSwitcherUrlGreylist,
             std::move(greylist));
   policy_provider().UpdateChromePolicy(policies);
@@ -580,13 +579,11 @@
   policy::PolicyMap policies;
   EnableBrowserSwitcher(&policies);
   SetPolicy(&policies, policy::key::kBrowserSwitcherExternalSitelistUrl,
-            std::make_unique<base::Value>(
-                net::FilePathToFileURL(external_sitelist_path).spec()));
+            base::Value(net::FilePathToFileURL(external_sitelist_path).spec()));
   SetPolicy(&policies, policy::key::kBrowserSwitcherExternalGreylistUrl,
-            std::make_unique<base::Value>(
-                net::FilePathToFileURL(external_greylist_path).spec()));
+            base::Value(net::FilePathToFileURL(external_greylist_path).spec()));
   SetPolicy(&policies, policy::key::kBrowserSwitcherUseIeSitelist,
-            std::make_unique<base::Value>(true));
+            base::Value(true));
   policy_provider().UpdateChromePolicy(policies);
   base::RunLoop().RunUntilIdle();
   BrowserSwitcherServiceWin::SetIeemSitelistUrlForTesting(
diff --git a/chrome/browser/browsing_data/access_context_audit_service.cc b/chrome/browser/browsing_data/access_context_audit_service.cc
index 09b70a9..ced41ab 100644
--- a/chrome/browser/browsing_data/access_context_audit_service.cc
+++ b/chrome/browser/browsing_data/access_context_audit_service.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/browsing_data/access_context_audit_service.h"
 #include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
+#include "base/updateable_sequenced_task_runner.h"
 #include "chrome/browser/browsing_data/access_context_audit_database.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -28,10 +28,13 @@
 
   // Tests may have provided a task runner already.
   if (!database_task_runner_) {
-    database_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
-        {base::MayBlock(), base::WithBaseSyncPrimitives(),
-         base::TaskPriority::USER_VISIBLE,
-         base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+    // Task runner is set to block shutdown as content settings are checked on
+    // service shutdown and records which should not be persisted are removed.
+    database_task_runner_ =
+        base::ThreadPool::CreateUpdateableSequencedTaskRunner(
+            {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+             base::ThreadPolicy::PREFER_BACKGROUND,
+             base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
   }
 
   if (!database_task_runner_->PostTask(
@@ -81,10 +84,25 @@
 
 void AccessContextAuditService::GetAllAccessRecords(
     AccessContextRecordsCallback callback) {
+  if (!user_visible_tasks_in_progress++)
+    database_task_runner_->UpdatePriority(base::TaskPriority::USER_VISIBLE);
+
   database_task_runner_->PostTaskAndReplyWithResult(
       FROM_HERE,
       base::BindOnce(&AccessContextAuditDatabase::GetAllRecords, database_),
-      std::move(callback));
+      base::BindOnce(
+          &AccessContextAuditService::CompleteGetAllAccessRecordsInternal,
+          weak_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void AccessContextAuditService::CompleteGetAllAccessRecordsInternal(
+    AccessContextRecordsCallback callback,
+    std::vector<AccessContextAuditDatabase::AccessRecord> records) {
+  DCHECK_GT(user_visible_tasks_in_progress, 0);
+  if (!--user_visible_tasks_in_progress)
+    database_task_runner_->UpdatePriority(base::TaskPriority::BEST_EFFORT);
+
+  std::move(callback).Run(std::move(records));
 }
 
 void AccessContextAuditService::Shutdown() {
@@ -161,7 +179,7 @@
 }
 
 void AccessContextAuditService::SetTaskRunnerForTesting(
-    scoped_refptr<base::SequencedTaskRunner> task_runner) {
+    scoped_refptr<base::UpdateableSequencedTaskRunner> task_runner) {
   DCHECK(!database_task_runner_);
   database_task_runner_ = std::move(task_runner);
 }
diff --git a/chrome/browser/browsing_data/access_context_audit_service.h b/chrome/browser/browsing_data/access_context_audit_service.h
index ad27d644..954bd5f 100644
--- a/chrome/browser/browsing_data/access_context_audit_service.h
+++ b/chrome/browser/browsing_data/access_context_audit_service.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_BROWSING_DATA_ACCESS_CONTEXT_AUDIT_SERVICE_H_
 #define CHROME_BROWSER_BROWSING_DATA_ACCESS_CONTEXT_AUDIT_SERVICE_H_
 
+#include "base/updateable_sequenced_task_runner.h"
 #include "chrome/browser/browsing_data/access_context_audit_database.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/browsing_data/content/local_shared_objects_container.h"
@@ -46,6 +47,11 @@
   // |callback|.
   void GetAllAccessRecords(AccessContextRecordsCallback callback);
 
+  // Called on completion of GetAllAccessRecords.
+  void CompleteGetAllAccessRecordsInternal(
+      AccessContextRecordsCallback callback,
+      std::vector<AccessContextAuditDatabase::AccessRecord> records);
+
   // KeyedService:
   void Shutdown() override;
 
@@ -63,7 +69,7 @@
   // Override internal task runner with provided task runner. Must be called
   // before Init().
   void SetTaskRunnerForTesting(
-      scoped_refptr<base::SequencedTaskRunner> task_runner);
+      scoped_refptr<base::UpdateableSequencedTaskRunner> task_runner);
 
  private:
   friend class AccessContextAuditServiceTest;
@@ -73,7 +79,9 @@
   void ClearSessionOnlyRecords();
 
   scoped_refptr<AccessContextAuditDatabase> database_;
-  scoped_refptr<base::SequencedTaskRunner> database_task_runner_;
+  scoped_refptr<base::UpdateableSequencedTaskRunner> database_task_runner_;
+
+  int user_visible_tasks_in_progress = 0;
 
   base::Clock* clock_;
   Profile* profile_;
@@ -83,6 +91,7 @@
   ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
       history_observer_{this};
 
+  base::WeakPtrFactory<AccessContextAuditService> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(AccessContextAuditService);
 };
 
diff --git a/chrome/browser/browsing_data/access_context_audit_service_unittest.cc b/chrome/browser/browsing_data/access_context_audit_service_unittest.cc
index 3d1f821e..bd92371b 100644
--- a/chrome/browser/browsing_data/access_context_audit_service_unittest.cc
+++ b/chrome/browser/browsing_data/access_context_audit_service_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/files/scoped_temp_dir.h"
 #include "base/i18n/time_formatting.h"
+#include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_clock.h"
 #include "base/test/test_simple_task_runner.h"
@@ -105,8 +106,7 @@
       content::BrowserContext* context) {
     std::unique_ptr<AccessContextAuditService> service(
         new AccessContextAuditService(static_cast<Profile*>(context)));
-    service->SetTaskRunnerForTesting(
-        browser_task_environment_.GetMainThreadTaskRunner());
+    service->SetTaskRunnerForTesting(task_runner_);
     service->Init(temp_directory_.GetPath(), cookie_manager(),
                   history_service());
     return service;
@@ -116,9 +116,12 @@
     feature_list_.InitWithFeatures(
         {features::kClientStorageAccessContextAuditing}, {});
 
+    task_runner_ = base::ThreadPool::CreateUpdateableSequencedTaskRunner(
+        {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+         base::ThreadPolicy::PREFER_BACKGROUND,
+         base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+
     ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
-    task_runner_ = scoped_refptr<base::TestSimpleTaskRunner>(
-        new base::TestSimpleTaskRunner);
 
     TestingProfile::Builder builder;
     builder.AddTestingFactory(
@@ -133,18 +136,28 @@
             base::Unretained(this)));
     builder.SetPath(temp_directory_.GetPath());
     profile_ = builder.Build();
+    FlushSequencedTaskRunner();
     browser_task_environment_.RunUntilIdle();
   }
 
-  void AccessRecordCallback(
-      std::vector<AccessContextAuditDatabase::AccessRecord> records) {
-    records_ = records;
+  std::vector<AccessContextAuditDatabase::AccessRecord> GetAllAccessRecords() {
+    base::RunLoop run_loop;
+    std::vector<AccessContextAuditDatabase::AccessRecord> records_out;
+    service()->GetAllAccessRecords(base::BindLambdaForTesting(
+        [&](std::vector<AccessContextAuditDatabase::AccessRecord> records) {
+          records_out = records;
+          run_loop.QuitWhenIdle();
+        }));
+    run_loop.Run();
+    return records_out;
   }
 
-  std::vector<AccessContextAuditDatabase::AccessRecord> GetReturnedRecords() {
-    return records_;
+  void FlushSequencedTaskRunner() {
+    base::RunLoop run_loop;
+    task_runner_->PostTask(FROM_HERE, base::BindLambdaForTesting(
+                                          [&]() { run_loop.QuitWhenIdle(); }));
+    run_loop.Run();
   }
-  void ClearReturnedRecords() { records_.clear(); }
 
   TestCookieManager* cookie_manager() { return &cookie_manager_; }
   base::SimpleTestClock* clock() { return &clock_; }
@@ -163,7 +176,7 @@
   history::HistoryService* history_service_;
   base::test::ScopedFeatureList feature_list_;
 
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  scoped_refptr<base::UpdateableSequencedTaskRunner> task_runner_;
   std::vector<AccessContextAuditDatabase::AccessRecord> records_;
 };
 
@@ -191,16 +204,11 @@
                                 kTopFrameOrigin);
 
   // Ensure that the record of these accesses is correctly returned.
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(2u, GetReturnedRecords().size());
-  CheckContainsCookieRecord(test_cookie.get(), kTopFrameOrigin,
-                            GetReturnedRecords());
+  auto records = GetAllAccessRecords();
+  EXPECT_EQ(2u, records.size());
+  CheckContainsCookieRecord(test_cookie.get(), kTopFrameOrigin, records);
   CheckContainsCookieRecord(test_non_persistent_cookie.get(), kTopFrameOrigin,
-                            GetReturnedRecords());
+                            records);
 
   // Check that informing the service of non-deletion changes to the cookies
   // via the CookieChangeInterface is a no-op.
@@ -211,16 +219,11 @@
       *test_non_persistent_cookie, net::CookieAccessResult(),
       net::CookieChangeCause::OVERWRITE));
 
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(2u, GetReturnedRecords().size());
-  CheckContainsCookieRecord(test_cookie.get(), kTopFrameOrigin,
-                            GetReturnedRecords());
+  records = GetAllAccessRecords();
+  EXPECT_EQ(2u, records.size());
+  CheckContainsCookieRecord(test_cookie.get(), kTopFrameOrigin, records);
   CheckContainsCookieRecord(test_non_persistent_cookie.get(), kTopFrameOrigin,
-                            GetReturnedRecords());
+                            records);
 
   // Check that a repeated access correctly updates associated timestamp.
   base::Time repeat_cookie_access_time =
@@ -230,17 +233,11 @@
   service()->RecordCookieAccess({*test_cookie, *test_non_persistent_cookie},
                                 kTopFrameOrigin);
 
-  ClearReturnedRecords();
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(2u, GetReturnedRecords().size());
-  CheckContainsCookieRecord(test_cookie.get(), kTopFrameOrigin,
-                            GetReturnedRecords());
+  records = GetAllAccessRecords();
+  EXPECT_EQ(2u, records.size());
+  CheckContainsCookieRecord(test_cookie.get(), kTopFrameOrigin, records);
   CheckContainsCookieRecord(test_non_persistent_cookie.get(), kTopFrameOrigin,
-                            GetReturnedRecords());
+                            records);
 
   // Inform the service the cookies have been deleted and check they are no
   // longer returned.
@@ -250,13 +247,8 @@
   service()->OnCookieChange(net::CookieChangeInfo(
       *test_non_persistent_cookie, net::CookieAccessResult(),
       net::CookieChangeCause::EXPLICIT));
-  ClearReturnedRecords();
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(0u, GetReturnedRecords().size());
+  records = GetAllAccessRecords();
+  EXPECT_EQ(0u, records.size());
 }
 
 TEST_F(AccessContextAuditServiceTest, ExpiredCookies) {
@@ -269,11 +261,7 @@
   service()->RecordCookieAccess({*test_cookie_expired},
                                 url::Origin::Create(kTestURL));
 
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-  EXPECT_EQ(0u, GetReturnedRecords().size());
+  EXPECT_EQ(0u, GetAllAccessRecords().size());
 }
 
 TEST_F(AccessContextAuditServiceTest, HistoryDeletion) {
@@ -305,11 +293,7 @@
                                     kNoRemainingHistoryEntriesOrigin);
 
   // Ensure all records have been initially recorded.
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-  EXPECT_EQ(4u, GetReturnedRecords().size());
+  EXPECT_EQ(4u, GetAllAccessRecords().size());
 
   // Add history entries for all three URLs, then remove history entries for
   // URL1 and URL3. This will fire a history deletion event where the shared
@@ -331,16 +315,12 @@
 
   // Confirm that the records for the origin of URL3 have been removed, but the
   // records for the shared origin of URL1 & URL2 remain.
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-  EXPECT_EQ(2u, GetReturnedRecords().size());
+  auto records = GetAllAccessRecords();
+  EXPECT_EQ(2u, records.size());
   CheckContainsCookieRecord(test_cookie.get(), kHistoryEntriesRemainingOrigin,
-                            GetReturnedRecords());
+                            records);
   CheckContainsStorageAPIRecord(kTestStorageOrigin, kTestStorageType,
-                                kHistoryEntriesRemainingOrigin,
-                                GetReturnedRecords());
+                                kHistoryEntriesRemainingOrigin, records);
 }
 
 TEST_F(AccessContextAuditServiceTest, AllHistoryDeletion) {
@@ -376,11 +356,7 @@
       kNoHistoryEntryOrigin);
 
   // Check access has been initially recorded.
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-  EXPECT_EQ(4u, GetReturnedRecords().size());
+  EXPECT_EQ(4u, GetAllAccessRecords().size());
 
   // Expire all history and confirm that all records are removed.
   base::RunLoop run_loop;
@@ -390,11 +366,7 @@
       /*user_initiated*/ true, run_loop.QuitClosure(), &task_tracker);
   run_loop.Run();
 
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-  EXPECT_EQ(0u, GetReturnedRecords().size());
+  EXPECT_EQ(0u, GetAllAccessRecords().size());
 }
 
 TEST_F(AccessContextAuditServiceTest, TimeRangeHistoryDeletion) {
@@ -457,11 +429,7 @@
   service()->RecordStorageAPIAccess(kOrigin2, kTestStorageType1, kOrigin2);
 
   // Ensure all records have been initially recorded.
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-  EXPECT_EQ(6u, GetReturnedRecords().size());
+  EXPECT_EQ(6u, GetAllAccessRecords().size());
 
   // Expire history in target time range.
   base::RunLoop run_loop;
@@ -473,15 +441,11 @@
   run_loop.Run();
 
   // Ensure records have been removed as expected.
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-  EXPECT_EQ(2u, GetReturnedRecords().size());
+  auto records = GetAllAccessRecords();
+  EXPECT_EQ(2u, records.size());
   CheckContainsCookieRecord(cookie_accessed_outside_range.get(), kOrigin1,
-                            GetReturnedRecords());
-  CheckContainsStorageAPIRecord(kOrigin1, kTestStorageType2, kOrigin1,
-                                GetReturnedRecords());
+                            records);
+  CheckContainsStorageAPIRecord(kOrigin1, kTestStorageType2, kOrigin1, records);
 }
 
 TEST_F(AccessContextAuditServiceTest, SessionOnlyRecords) {
@@ -526,11 +490,7 @@
       kTopFrameOrigin);
 
   // Ensure all records have been initially recorded.
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-  EXPECT_EQ(5u, GetReturnedRecords().size());
+  EXPECT_EQ(5u, GetAllAccessRecords().size());
 
   // Apply Session Only exception.
   HostContentSettingsMapFactory::GetForProfile(profile())
@@ -543,18 +503,12 @@
   // correctly removed.
   service()->ClearSessionOnlyRecords();
 
-  ClearReturnedRecords();
-  service()->GetAllAccessRecords(
-      base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
-                     base::Unretained(this)));
-  browser_task_environment_.RunUntilIdle();
-
-  ASSERT_EQ(3u, GetReturnedRecords().size());
+  auto records = GetAllAccessRecords();
+  ASSERT_EQ(3u, records.size());
   CheckContainsCookieRecord(test_cookie_persistent.get(), kTopFrameOrigin,
-                            GetReturnedRecords());
+                            records);
   CheckContainsCookieRecord(test_cookie_session_only_explicit.get(),
-                            kTopFrameOrigin, GetReturnedRecords());
+                            kTopFrameOrigin, records);
   CheckContainsStorageAPIRecord(url::Origin::Create(GURL(kTestPersistentURL)),
-                                kTestStorageType, kTopFrameOrigin,
-                                GetReturnedRecords());
+                                kTestStorageType, kTopFrameOrigin, records);
 }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index fdfefcd..b399364e 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2800,7 +2800,6 @@
   deps = [
     ":chromeos",
     "//base",
-    "//dbus",
   ]
 }
 
diff --git a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc
index 9b47ba8..cbfc90f 100644
--- a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge_unittest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chromeos/arc/test/test_arc_session_manager.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
@@ -34,18 +33,14 @@
   ArcBootPhaseMonitorBridgeTest()
       : scoped_user_manager_(
             std::make_unique<chromeos::FakeChromeUserManager>()),
+        arc_service_manager_(std::make_unique<ArcServiceManager>()),
+        arc_session_manager_(
+            CreateTestArcSessionManager(std::make_unique<ArcSessionRunner>(
+                base::BindRepeating(FakeArcSession::Create)))),
+        testing_profile_(std::make_unique<TestingProfile>()),
         record_uma_counter_(0) {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
     chromeos::SessionManagerClient::InitializeFakeInMemory();
 
-    arc_service_manager_ = std::make_unique<ArcServiceManager>();
-    arc_session_manager_ = CreateTestArcSessionManager(
-      std::make_unique<ArcSessionRunner>(
-      base::BindRepeating(FakeArcSession::Create)));
-    testing_profile_ = std::make_unique<TestingProfile>();
-
     SetArcAvailableCommandLineForTesting(
         base::CommandLine::ForCurrentProcess());
 
@@ -63,11 +58,7 @@
 
   ~ArcBootPhaseMonitorBridgeTest() override {
     boot_phase_monitor_bridge_->Shutdown();
-    testing_profile_.reset();
-    arc_session_manager_.reset();
-    arc_service_manager_.reset();
     chromeos::SessionManagerClient::Shutdown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
  protected:
diff --git a/chrome/browser/chromeos/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc b/chrome/browser/chromeos/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc
index afc6ebb2..bb9d31e1 100644
--- a/chrome/browser/chromeos/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc
+++ b/chrome/browser/chromeos/arc/instance_throttle/arc_boot_phase_throttle_observer_unittest.cc
@@ -10,10 +10,8 @@
 #include "base/values.h"
 #include "chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
-#include "chrome/browser/chromeos/arc/test/test_arc_session_manager.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
@@ -29,20 +27,16 @@
  public:
   ArcBootPhaseThrottleObserverTest()
       : scoped_user_manager_(
-            std::make_unique<chromeos::FakeChromeUserManager>()) {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
-    arc_session_manager_ =
-        CreateTestArcSessionManager(std::make_unique<ArcSessionRunner>(
-            base::BindRepeating(FakeArcSession::Create)));
-    testing_profile_ = std::make_unique<TestingProfile>();
-
+            std::make_unique<chromeos::FakeChromeUserManager>()),
+        arc_session_manager_(
+            std::make_unique<ArcSessionRunner>(
+                base::Bind(FakeArcSession::Create)),
+            std::make_unique<AdbSideloadingAvailabilityDelegateImpl>()) {
     // Setup and login profile
     SetArcAvailableCommandLineForTesting(
         base::CommandLine::ForCurrentProcess());
-    const AccountId account_id(AccountId::FromUserEmailGaiaId(
-        testing_profile_->GetProfileUserName(), ""));
+    const AccountId account_id(
+        AccountId::FromUserEmailGaiaId(profile()->GetProfileUserName(), ""));
     auto* user_manager = static_cast<chromeos::FakeChromeUserManager*>(
         user_manager::UserManager::Get());
     user_manager->AddUser(account_id);
@@ -51,38 +45,32 @@
     // By default, ARC is not started for opt-in.
     arc_session_manager()->set_directly_started_for_testing(true);
 
-    ArcBootPhaseMonitorBridge::GetForBrowserContextForTesting(
-        testing_profile_.get());
+    ArcBootPhaseMonitorBridge::GetForBrowserContextForTesting(profile());
     observer()->StartObserving(
-        testing_profile_.get(),
+        profile(),
         ArcBootPhaseThrottleObserver::ObserverStateChangedCallback());
   }
 
-  void TearDown() override {
-    observer()->StopObserving();
-    testing_profile_.reset();
-    arc_session_manager_.reset();
-    chromeos::DBusThreadManager::Shutdown();
-  }
+  void TearDown() override { observer()->StopObserving(); }
 
  protected:
   sync_preferences::TestingPrefServiceSyncable* GetPrefs() {
-    return testing_profile_->GetTestingPrefService();
+    return testing_profile_.GetTestingPrefService();
   }
 
   ArcBootPhaseThrottleObserver* observer() { return &observer_; }
 
-  ArcSessionManager* arc_session_manager() {
-    return arc_session_manager_.get();
-  }
+  TestingProfile* profile() { return &testing_profile_; }
+
+  ArcSessionManager* arc_session_manager() { return &arc_session_manager_; }
 
  private:
   content::BrowserTaskEnvironment task_environment_;
   user_manager::ScopedUserManager scoped_user_manager_;
   ArcServiceManager arc_service_manager_;
-  std::unique_ptr<ArcSessionManager> arc_session_manager_;
+  ArcSessionManager arc_session_manager_;
   ArcBootPhaseThrottleObserver observer_;
-  std::unique_ptr<TestingProfile> testing_profile_;
+  TestingProfile testing_profile_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcBootPhaseThrottleObserverTest);
 };
diff --git a/chrome/browser/chromeos/arc/instance_throttle/arc_instance_throttle_unittest.cc b/chrome/browser/chromeos/arc/instance_throttle/arc_instance_throttle_unittest.cc
index 1d97a3e7..a0029e2a 100644
--- a/chrome/browser/chromeos/arc/instance_throttle/arc_instance_throttle_unittest.cc
+++ b/chrome/browser/chromeos/arc/instance_throttle/arc_instance_throttle_unittest.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/chromeos/arc/test/test_arc_session_manager.h"
 #include "chrome/browser/chromeos/throttle_observer.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
@@ -30,17 +29,13 @@
 class ArcInstanceThrottleTest : public testing::Test {
  public:
   ArcInstanceThrottleTest()
-      : disable_cpu_restriction_counter_(0),
+      : arc_service_manager_(std::make_unique<ArcServiceManager>()),
+        arc_session_manager_(
+            CreateTestArcSessionManager(std::make_unique<ArcSessionRunner>(
+                base::BindRepeating(FakeArcSession::Create)))),
+        testing_profile_(std::make_unique<TestingProfile>()),
+        disable_cpu_restriction_counter_(0),
         enable_cpu_restriction_counter_(0) {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
-    arc_service_manager_ = std::make_unique<ArcServiceManager>();
-    arc_session_manager_ =
-        CreateTestArcSessionManager(std::make_unique<ArcSessionRunner>(
-            base::BindRepeating(FakeArcSession::Create)));
-    testing_profile_ = std::make_unique<TestingProfile>();
-
     SetArcAvailableCommandLineForTesting(
         base::CommandLine::ForCurrentProcess());
 
@@ -53,13 +48,6 @@
         std::make_unique<TestDelegateImpl>(this));
   }
 
-  ~ArcInstanceThrottleTest() override {
-    testing_profile_.reset();
-    arc_session_manager_.reset();
-    arc_service_manager_.reset();
-    chromeos::DBusThreadManager::Shutdown();
-  }
-
  protected:
   sync_preferences::TestingPrefServiceSyncable* GetPrefs() {
     return testing_profile_->GetTestingPrefService();
diff --git a/chrome/browser/chromeos/arc/notification/arc_provision_notification_service_unittest.cc b/chrome/browser/chromeos/arc/notification/arc_provision_notification_service_unittest.cc
index 7353c38..b92c4cf 100644
--- a/chrome/browser/chromeos/arc/notification/arc_provision_notification_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/notification/arc_provision_notification_service_unittest.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/arc/arc_prefs.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
@@ -43,9 +42,6 @@
             std::make_unique<chromeos::FakeChromeUserManager>()) {}
 
   void SetUp() override {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
     SetArcAvailableCommandLineForTesting(
         base::CommandLine::ForCurrentProcess());
     ArcSessionManager::SetUiEnabledForTesting(false);
@@ -80,7 +76,6 @@
     BrowserWithTestWindowTest::TearDown();
     arc_session_manager_.reset();
     arc_service_manager_.reset();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
   chromeos::FakeChromeUserManager* GetFakeUserManager() {
diff --git a/chrome/browser/chromeos/arc/session/arc_play_store_enabled_preference_handler_unittest.cc b/chrome/browser/chromeos/arc/session/arc_play_store_enabled_preference_handler_unittest.cc
index f12090c..1d48d9e 100644
--- a/chrome/browser/chromeos/arc/session/arc_play_store_enabled_preference_handler_unittest.cc
+++ b/chrome/browser/chromeos/arc/session/arc_play_store_enabled_preference_handler_unittest.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
 #include "components/arc/arc_prefs.h"
@@ -55,9 +54,6 @@
             std::make_unique<chromeos::FakeChromeUserManager>()) {}
 
   void SetUp() override {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
     chromeos::SessionManagerClient::InitializeFakeInMemory();
     chromeos::UpstartClient::InitializeFake();
 
@@ -99,7 +95,6 @@
     profile_.reset();
     chromeos::UpstartClient::Shutdown();
     chromeos::SessionManagerClient::Shutdown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
   TestingProfile* profile() const { return profile_.get(); }
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.cc b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
index 30f0597..1c777ab 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
@@ -462,15 +462,11 @@
   if (chromeos::SessionManagerClient::Get())
     chromeos::SessionManagerClient::Get()->AddObserver(this);
   ResetStabilityMetrics();
-  chromeos::DBusThreadManager::Get()->GetConciergeClient()->AddVmObserver(this);
 }
 
 ArcSessionManager::~ArcSessionManager() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  chromeos::DBusThreadManager::Get()->GetConciergeClient()->RemoveVmObserver(
-      this);
-
   if (chromeos::SessionManagerClient::Get())
     chromeos::SessionManagerClient::Get()->RemoveObserver(this);
 
@@ -967,25 +963,6 @@
   return playstore_launcher_.get();
 }
 
-void ArcSessionManager::OnVmStarted(
-    const vm_tools::concierge::VmStartedSignal& vm_signal) {
-  // When an ARCVM starts, store the vm info.
-  if (vm_signal.name() == kArcVmName)
-    vm_info_ = vm_signal.vm_info();
-}
-
-void ArcSessionManager::OnVmStopped(
-    const vm_tools::concierge::VmStoppedSignal& vm_signal) {
-  // When an ARCVM stops, clear the stored vm info.
-  if (vm_signal.name() == kArcVmName)
-    vm_info_ = base::nullopt;
-}
-
-const base::Optional<vm_tools::concierge::VmInfo>&
-ArcSessionManager::GetVmInfo() const {
-  return vm_info_;
-}
-
 bool ArcSessionManager::RequestEnableImpl() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(profile_);
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.h b/chrome/browser/chromeos/arc/session/arc_session_manager.h
index ff6fbf9..1e3afe52 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.h
@@ -20,7 +20,6 @@
 #include "chrome/browser/chromeos/arc/session/adb_sideloading_availability_delegate_impl.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager_observer.h"
 #include "chrome/browser/chromeos/policy/android_management_client.h"
-#include "chromeos/dbus/concierge_client.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "components/arc/mojom/auth.mojom.h"
 #include "components/arc/session/arc_session_runner.h"
@@ -48,8 +47,7 @@
 // This class is responsible for handing stages of ARC life-cycle.
 class ArcSessionManager : public ArcSessionRunner::Observer,
                           public ArcSupportHost::ErrorDelegate,
-                          public chromeos::SessionManagerClient::Observer,
-                          public chromeos::ConciergeClient::VmObserver {
+                          public chromeos::SessionManagerClient::Observer {
  public:
   // Represents each State of ARC session.
   // NOT_INITIALIZED: represents the state that the Profile is not yet ready
@@ -284,16 +282,6 @@
     property_files_dest_dir_ = property_files_dest_dir;
   }
 
-  // chromeos::ConciergeClient::VmObserver overrides.
-  void OnVmStarted(
-      const vm_tools::concierge::VmStartedSignal& vm_signal) override;
-  void OnVmStopped(
-      const vm_tools::concierge::VmStoppedSignal& vm_signal) override;
-
-  // Getter for |vm_info_|.
-  // If ARCVM is not running, return base::nullopt.
-  const base::Optional<vm_tools::concierge::VmInfo>& GetVmInfo() const;
-
  private:
   // Reports statuses of OptIn flow to UMA.
   class ScopedOptInFlowTracker;
@@ -429,8 +417,6 @@
   base::FilePath property_files_source_dir_;
   base::FilePath property_files_dest_dir_;
 
-  base::Optional<vm_tools::concierge::VmInfo> vm_info_;
-
   // Must be the last member.
   base::WeakPtrFactory<ArcSessionManager> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc b/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc
index e5c23544..6d9d19c 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager_unittest.cc
@@ -46,7 +46,6 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/dbus/upstart/upstart_client.h"
@@ -128,9 +127,6 @@
   ArcSessionManagerInLoginScreenTest()
       : user_manager_enabler_(
             std::make_unique<chromeos::FakeChromeUserManager>()) {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
     chromeos::SessionManagerClient::InitializeFakeInMemory();
 
     ArcSessionManager::SetUiEnabledForTesting(false);
@@ -147,7 +143,6 @@
     arc_session_manager_.reset();
     arc_service_manager_.reset();
     chromeos::SessionManagerClient::Shutdown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
  protected:
@@ -207,7 +202,6 @@
   ~ArcSessionManagerTestBase() override = default;
 
   void SetUp() override {
-    chromeos::DBusThreadManager::Initialize();
     chromeos::PowerManagerClient::InitializeFake();
     chromeos::SessionManagerClient::InitializeFakeInMemory();
     chromeos::UpstartClient::InitializeFake();
@@ -241,7 +235,6 @@
     chromeos::UpstartClient::Shutdown();
     chromeos::SessionManagerClient::Shutdown();
     chromeos::PowerManagerClient::Shutdown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
   chromeos::FakeChromeUserManager* GetFakeUserManager() const {
@@ -988,60 +981,6 @@
   arc_session_manager()->Shutdown();
 }
 
-// Tests that |vm_info| is initialized with base::nullopt.
-TEST_F(ArcSessionManagerTest, GetVmInfo_InitialValue) {
-  const auto& vm_info = arc_session_manager()->GetVmInfo();
-  EXPECT_EQ(base::nullopt, vm_info);
-}
-
-// Tests that |vm_info| is updated with that from VmStartedSignal.
-TEST_F(ArcSessionManagerTest, GetVmInfo_WithVmStarted) {
-  vm_tools::concierge::VmStartedSignal vm_signal;
-  vm_signal.set_name(kArcVmName);
-  vm_signal.mutable_vm_info()->set_seneschal_server_handle(1000UL);
-  arc_session_manager()->OnVmStarted(vm_signal);
-
-  const auto& vm_info = arc_session_manager()->GetVmInfo();
-  ASSERT_NE(base::nullopt, vm_info);
-  EXPECT_EQ(1000UL, vm_info->seneschal_server_handle());
-}
-
-// Tests that |vm_info| remains as base::nullopt after VM stops.
-TEST_F(ArcSessionManagerTest, GetVmInfo_WithVmStopped) {
-  vm_tools::concierge::VmStoppedSignal vm_signal;
-  vm_signal.set_name(kArcVmName);
-  arc_session_manager()->OnVmStopped(vm_signal);
-
-  const auto& vm_info = arc_session_manager()->GetVmInfo();
-  EXPECT_EQ(base::nullopt, vm_info);
-}
-
-// Tests that |vm_info| is reset to base::nullopt after VM starts and stops.
-TEST_F(ArcSessionManagerTest, GetVmInfo_WithVmStarted_ThenStopped) {
-  vm_tools::concierge::VmStartedSignal start_signal;
-  start_signal.set_name(kArcVmName);
-  start_signal.mutable_vm_info()->set_seneschal_server_handle(1000UL);
-  arc_session_manager()->OnVmStarted(start_signal);
-
-  vm_tools::concierge::VmStoppedSignal stop_signal;
-  stop_signal.set_name(kArcVmName);
-  arc_session_manager()->OnVmStopped(stop_signal);
-
-  const auto& vm_info = arc_session_manager()->GetVmInfo();
-  EXPECT_EQ(base::nullopt, vm_info);
-}
-
-// Tests that |vm_info| is not updated with non-ARCVM VmStartedSignal.
-TEST_F(ArcSessionManagerTest, GetVmInfo_WithNonVmStarted) {
-  vm_tools::concierge::VmStartedSignal non_vm_signal;
-  non_vm_signal.set_name("non-ARCVM");
-  non_vm_signal.mutable_vm_info()->set_seneschal_server_handle(1000UL);
-  arc_session_manager()->OnVmStarted(non_vm_signal);
-
-  const auto& vm_info = arc_session_manager()->GetVmInfo();
-  EXPECT_EQ(base::nullopt, vm_info);
-}
-
 class ArcSessionManagerArcAlwaysStartTest : public ArcSessionManagerTest {
  public:
   ArcSessionManagerArcAlwaysStartTest() = default;
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
index de75853..184e7bb 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
@@ -58,6 +58,10 @@
       if (user_manager::UserManager::Get()->IsUserLoggedIn())
         return user_manager::UserManager::Get()->GetActiveUser()->IsChild();
       return IsDeviceOwnedByChild();
+    case SupervisedAction::kOnlineLogin:
+      if (!features::IsParentAccessCodeForOnlineLoginEnabled())
+        return false;
+      return IsDeviceOwnedByChild();
   }
 }
 
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h
index 50fe0c6..476165e 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h
@@ -43,7 +43,9 @@
     // the settings page (in-session) and the tray bubble (out-session).
     kUpdateClock,
     // Change timezone from the settings page.
-    kUpdateTimezone
+    kUpdateTimezone,
+    // Online login with Gaia.
+    kOnlineLogin
   };
 
   // Registers preferences.
diff --git a/chrome/browser/chromeos/guest_os/guest_os_share_path.cc b/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
index f0aafef..5358124 100644
--- a/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
+++ b/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
@@ -9,7 +9,6 @@
 #include "base/files/file_util.h"
 #include "base/optional.h"
 #include "base/task/thread_pool.h"
-#include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
@@ -24,7 +23,6 @@
 #include "chromeos/dbus/concierge/concierge_service.pb.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/seneschal_client.h"
-#include "components/arc/arc_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -331,15 +329,6 @@
     request.set_handle(
         plugin_vm::PluginVmManagerFactory::GetForProfile(profile_)
             ->seneschal_server_handle());
-  } else if (vm_name == arc::kArcVmName) {
-    const auto& vm_info = arc::ArcSessionManager::Get()->GetVmInfo();
-    if (!vm_info) {
-      LOG(WARNING) << "ARCVM not running, cannot share paths";
-      std::move(callback).Run(base::FilePath(), false,
-                              "ARCVM not running, cannot share paths");
-      return;
-    }
-    request.set_handle(vm_info->seneschal_server_handle());
   } else {
     // Restart VM if not currently running.
     auto* crostini_manager = crostini::CrostiniManager::GetForProfile(profile_);
@@ -377,14 +366,6 @@
     request.set_handle(
         plugin_vm::PluginVmManagerFactory::GetForProfile(profile_)
             ->seneschal_server_handle());
-  } else if (vm_name == arc::kArcVmName) {
-    const auto& vm_info = arc::ArcSessionManager::Get()->GetVmInfo();
-    if (!vm_info) {
-      LOG(WARNING) << "ARCVM not running, cannot unshare paths";
-      std::move(callback).Run(true, "ARCVM not running, cannot unshare paths");
-      return;
-    }
-    request.set_handle(vm_info->seneschal_server_handle());
   } else {
     auto* crostini_manager = crostini::CrostiniManager::GetForProfile(profile_);
     base::Optional<crostini::VmInfo> vm_info =
diff --git a/chrome/browser/chromeos/guest_os/guest_os_share_path_unittest.cc b/chrome/browser/chromeos/guest_os/guest_os_share_path_unittest.cc
index 0e15c174..25f276b 100644
--- a/chrome/browser/chromeos/guest_os/guest_os_share_path_unittest.cc
+++ b/chrome/browser/chromeos/guest_os/guest_os_share_path_unittest.cc
@@ -9,8 +9,6 @@
 #include "base/files/file_util.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
-#include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
-#include "chrome/browser/chromeos/arc/test/test_arc_session_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
@@ -33,9 +31,6 @@
 #include "chromeos/dbus/seneschal/seneschal_service.pb.h"
 #include "chromeos/disks/disk_mount_manager.h"
 #include "components/account_id/account_id.h"
-#include "components/arc/arc_util.h"
-#include "components/arc/session/arc_session_runner.h"
-#include "components/arc/test/fake_arc_session.h"
 #include "components/drive/drive_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
@@ -266,15 +261,9 @@
 
     g_browser_process->platform_part()
         ->InitializeSchedulerConfigurationManager();
-
-    // Create ArcSessionManager for ARCVM testing.
-    arc_session_manager_ = arc::CreateTestArcSessionManager(
-        std::make_unique<arc::ArcSessionRunner>(
-            base::BindRepeating(arc::FakeArcSession::Create)));
   }
 
   void TearDown() override {
-    arc_session_manager_.reset();
     g_browser_process->platform_part()->ShutdownSchedulerConfigurationManager();
     // Shutdown GuestOsSharePath to schedule FilePathWatchers to be destroyed,
     // then run thread bundle to ensure they are.
@@ -310,7 +299,6 @@
   base::test::ScopedFeatureList features_;
   std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
   AccountId account_id_;
-  std::unique_ptr<arc::ArcSessionManager> arc_session_manager_;
 
  private:
   std::unique_ptr<ScopedTestingLocalState> local_state_;
@@ -368,28 +356,6 @@
   run_loop()->Run();
 }
 
-// Tests that ARCVM can share path.
-TEST_F(GuestOsSharePathTest, SuccessArcvm) {
-  SetUpVolume();
-
-  // Set up VmInfo in |arc_session_manager_| to simulate a running ARCVM.
-  vm_tools::concierge::VmStartedSignal start_signal;
-  start_signal.set_name(arc::kArcVmName);
-  start_signal.mutable_vm_info()->set_seneschal_server_handle(1000UL);
-  arc_session_manager_->OnVmStarted(start_signal);
-
-  guest_os_share_path_->SharePath(
-      arc::kArcVmName, drivefs_.Append("root").Append("ArcvmTest"), PERSIST_NO,
-      base::BindOnce(&GuestOsSharePathTest::SharePathCallback,
-                     base::Unretained(this), arc::kArcVmName, Persist::NO,
-                     SeneschalClientCalled::YES,
-                     &vm_tools::seneschal::SharePathRequest::DRIVEFS_MY_DRIVE,
-                     "ArcvmTest", Success::YES, ""));
-  // Also validate the seneschal server handle.
-  EXPECT_EQ(1000UL, fake_seneschal_client_->last_share_path_request().handle());
-  run_loop()->Run();
-}
-
 TEST_F(GuestOsSharePathTest, SuccessDriveFsMyDrive) {
   SetUpVolume();
   guest_os_share_path_->SharePath(
@@ -790,30 +756,6 @@
   run_loop()->Run();
 }
 
-// Tests that it cannot unshare path when ARCVM is not running.
-TEST_F(GuestOsSharePathTest, UnsharePathArcvmNotRunning) {
-  SetUpVolume();
-  DictionaryPrefUpdate update(profile()->GetPrefs(),
-                              prefs::kGuestOSPathsSharedToVms);
-  base::DictionaryValue* shared_paths = update.Get();
-  base::Value vms(base::Value::Type::LIST);
-  vms.Append(base::Value(arc::kArcVmName));
-  shared_paths->SetKey(shared_path_.value(), std::move(vms));
-
-  // Remove VmInfo from |arc_session_manager_| to simulate a stopped ARCVM.
-  vm_tools::concierge::VmStoppedSignal stop_signal;
-  stop_signal.set_name(arc::kArcVmName);
-  arc_session_manager_->OnVmStopped(stop_signal);
-
-  guest_os_share_path_->UnsharePath(
-      arc::kArcVmName, shared_path_, true,
-      base::BindOnce(&GuestOsSharePathTest::UnsharePathCallback,
-                     base::Unretained(this), shared_path_, Persist::NO,
-                     SeneschalClientCalled::NO, "", Success::YES,
-                     "ARCVM not running, cannot unshare paths"));
-  run_loop()->Run();
-}
-
 TEST_F(GuestOsSharePathTest, UnsharePathInvalidPath) {
   SetUpVolume();
   base::FilePath invalid("invalid/path");
diff --git a/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc b/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc
index 4ab9322..54fb42a8 100644
--- a/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/app_manager_impl_unittest.cc
@@ -31,7 +31,6 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/session/arc_session.h"
 #include "content/public/test/browser_task_environment.h"
@@ -143,9 +142,6 @@
   ~LockScreenAppManagerImplTest() override = default;
 
   void SetUp() override {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
     // Initialize command line so chromeos::NoteTakingHelper thinks note taking
     // on lock screen is enabled.
     command_line_ = std::make_unique<base::test::ScopedCommandLine>();
@@ -181,11 +177,8 @@
     // destruction.
     app_manager_.reset();
 
-    lock_screen_profile_creator_.reset();
     chromeos::NoteTakingHelper::Shutdown();
-    arc_session_manager_.reset();
     extensions::ExtensionSystem::Get(profile())->Shutdown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
   void InitExtensionSystem(Profile* profile) {
diff --git a/chrome/browser/chromeos/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc b/chrome/browser/chromeos/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
index 40434dbd6..eeab6c6 100644
--- a/chrome/browser/chromeos/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/lock_screen_profile_creator_impl_unittest.cc
@@ -30,7 +30,6 @@
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/session/arc_session.h"
 #include "components/crx_file/id_util.h"
@@ -215,9 +214,6 @@
   ~LockScreenProfileCreatorImplTest() override {}
 
   void SetUp() override {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
         extensions::switches::kAllowlistedExtensionID,
         crx_file::id_util::GenerateId("test_app"));
@@ -243,11 +239,8 @@
   }
 
   void TearDown() override {
-    lock_screen_profile_creator_.reset();
-    arc_session_manager_.reset();
     chromeos::NoteTakingHelper::Shutdown();
     TestingBrowserProcess::GetGlobal()->SetProfileManager(nullptr);
-    chromeos::DBusThreadManager::Shutdown();
   }
 
   UnittestProfileManager* profile_manager() { return profile_manager_; }
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
index 802ed840..3d995c8 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
@@ -38,7 +38,6 @@
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/fake_power_manager_client.h"
 #include "chromeos/dbus/power_manager/suspend.pb.h"
 #include "components/arc/arc_service_manager.h"
@@ -384,10 +383,6 @@
   ~LockScreenAppStateTest() override = default;
 
   void SetUp() override {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
-
     command_line_ = std::make_unique<base::test::ScopedCommandLine>();
     command_line_->GetProcessCommandLine()->InitFromArgv({""});
     SetUpCommandLine(command_line_->GetProcessCommandLine());
@@ -438,19 +433,18 @@
   }
 
   void TearDown() override {
+    extensions::ExtensionSystem::Get(profile())->Shutdown();
+
     state_controller_->RemoveObserver(&observer_);
     state_controller_->Shutdown();
-    focus_cycler_delegate_.reset();
+    chromeos::NoteTakingHelper::Shutdown();
+
+    session_manager_.reset();
     app_manager_ = nullptr;
     lock_screen_profile_creator_ = nullptr;
-    extensions::ExtensionSystem::Get(profile())->Shutdown();
-    chromeos::NoteTakingHelper::Shutdown();
-    arc_session_manager_.reset();
-    session_manager_.reset();
     app_window_.reset();
     BrowserWithTestWindowTest::TearDown();
-    command_line_.reset();
-    chromeos::DBusThreadManager::Shutdown();
+    focus_cycler_delegate_.reset();
   }
 
   TestingProfile* CreateProfile() override {
diff --git a/chrome/browser/chromeos/login/eula_browsertest.cc b/chrome/browser/chromeos/login/eula_browsertest.cc
index 1d8ab896..cdb550b 100644
--- a/chrome/browser/chromeos/login/eula_browsertest.cc
+++ b/chrome/browser/chromeos/login/eula_browsertest.cc
@@ -75,14 +75,13 @@
 const test::UIPath kEulaTPMPassword = {"oobe-eula-md", "eula-password"};
 const test::UIPath kUsageStats = {"oobe-eula-md", "usageStats"};
 const test::UIPath kAdditionalTermsLink = {"oobe-eula-md", "additionalTerms"};
-const test::UIPath kAdditionalTermsDialog = {"oobe-eula-md", "additional-tos"};
+const test::UIPath kAdditionalTermsDialog = {"oobe-eula-md", "additionalToS"};
 const test::UIPath kAdditionalTermsClose = {"oobe-eula-md",
                                             "close-additional-tos"};
-const test::UIPath kInstallationSettingsLink = {"oobe-eula-md",
-                                                "installationSettings"};
-const test::UIPath kInstallationSettingsDialog = {"oobe-eula-md",
-                                                  "installationSettingsDialog"};
-const test::UIPath kLearnMoreLink = {"oobe-eula-md", "learn-more"};
+const test::UIPath kSecuritySettingsLink = {"oobe-eula-md", "securitySettings"};
+const test::UIPath kSecuritySettingsDialog = {"oobe-eula-md",
+                                              "securitySettingsDialog"};
+const test::UIPath kLearnMoreLink = {"oobe-eula-md", "learnMore"};
 
 // Helper class to wait until the WebCotnents finishes loading.
 class WebContentsLoadFinishedWaiter : public content::WebContentsObserver {
@@ -320,8 +319,8 @@
   base::HistogramTester histogram_tester;
   ShowEulaScreen();
 
-  test::OobeJS().TapLinkOnPath(kInstallationSettingsLink);
-  test::OobeJS().ExpectVisiblePath(kInstallationSettingsDialog);
+  test::OobeJS().TapLinkOnPath(kSecuritySettingsLink);
+  test::OobeJS().ExpectVisiblePath(kSecuritySettingsDialog);
 
   test::OobeJS()
       .CreateWaiter(
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
index 00308e7..04d2c9a1 100644
--- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
@@ -113,8 +113,7 @@
   if (user && user->GetType() == user_manager::UserType::USER_TYPE_SUPERVISED)
     return false;
 
-  // Enable quick unlock only if the switch is present.
-  return base::FeatureList::IsEnabled(features::kQuickUnlockPin);
+  return true;
 }
 
 // Returns fingerprint location depending on the commandline switch.
diff --git a/chrome/browser/chromeos/login/screens/eula_screen.cc b/chrome/browser/chromeos/login/screens/eula_screen.cc
index 3cac9f1..912b08d 100644
--- a/chrome/browser/chromeos/login/screens/eula_screen.cc
+++ b/chrome/browser/chromeos/login/screens/eula_screen.cc
@@ -149,7 +149,17 @@
     return;
   }
   RecordUserAction(action_id);
-  if (action_id == kUserActionAcceptButtonClicked) {
+  if (action_id == kUserActionShowStatsUsageLearnMore) {
+    ShowStatsUsageLearnMore();
+  } else if (action_id == kUserActionShowAdditionalTos) {
+    ShowAdditionalTosDialog();
+  } else if (action_id == kUserActionShowSecuritySettings) {
+    InitiatePasswordFetch();
+  } else if (action_id == kUserActionSelectStatsUsage) {
+    SetUsageStatsEnabled(true);
+  } else if (action_id == kUserActionUnselectStatsUsage) {
+    SetUsageStatsEnabled(false);
+  } else if (action_id == kUserActionAcceptButtonClicked) {
     exit_callback_.Run(g_usage_statistics_reporting_enabled
                            ? Result::ACCEPTED_WITH_USAGE_STATS_REPORTING
                            : Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING);
@@ -172,4 +182,14 @@
     view_->OnPasswordFetched(tpm_password_);
 }
 
+void EulaScreen::ShowStatsUsageLearnMore() {
+  if (view_)
+    view_->ShowStatsUsageLearnMore();
+}
+
+void EulaScreen::ShowAdditionalTosDialog() {
+  if (view_)
+    view_->ShowAdditionalTosDialog();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/eula_screen.h b/chrome/browser/chromeos/login/screens/eula_screen.h
index 449afda..d169d1f 100644
--- a/chrome/browser/chromeos/login/screens/eula_screen.h
+++ b/chrome/browser/chromeos/login/screens/eula_screen.h
@@ -81,6 +81,8 @@
 
   // TpmPasswordFetcherDelegate implementation:
   void OnPasswordFetched(const std::string& tpm_password) override;
+  void ShowStatsUsageLearnMore();
+  void ShowAdditionalTosDialog();
 
   // URL of the OEM EULA page (on disk).
   GURL oem_eula_page_;
diff --git a/chrome/browser/chromeos/login/screens/mock_eula_screen.h b/chrome/browser/chromeos/login/screens/mock_eula_screen.h
index cfc854f..30e93789 100644
--- a/chrome/browser/chromeos/login/screens/mock_eula_screen.h
+++ b/chrome/browser/chromeos/login/screens/mock_eula_screen.h
@@ -36,6 +36,8 @@
   MOCK_METHOD(void, MockBind, (EulaScreen * screen));
   MOCK_METHOD(void, MockUnbind, ());
   MOCK_METHOD(void, OnPasswordFetched, (const std::string& tpm_password));
+  MOCK_METHOD(void, ShowStatsUsageLearnMore, ());
+  MOCK_METHOD(void, ShowAdditionalTosDialog, ());
 
  private:
   EulaScreen* screen_ = nullptr;
diff --git a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
index 8693a69..5a0dadf 100644
--- a/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
+++ b/chrome/browser/chromeos/policy/lock_to_single_user_manager_unittest.cc
@@ -37,12 +37,6 @@
   ~LockToSingleUserManagerTest() override = default;
 
   void SetUp() override {
-    // This setter will initialize DBusThreadManager.
-    // This is required before ArcSessionManager's constructor calls
-    // DBusThreadManager::Get().
-    auto dbus_thread_manager_setter =
-        chromeos::DBusThreadManager::GetSetterForTesting();
-
     arc::SetArcAvailableCommandLineForTesting(
         base::CommandLine::ForCurrentProcess());
     chromeos::LoginState::Initialize();
@@ -60,19 +54,20 @@
 
     arc_service_manager_->set_browser_context(profile());
 
+    auto setter = chromeos::DBusThreadManager::GetSetterForTesting();
     fake_concierge_client_ = new chromeos::FakeConciergeClient();
-    dbus_thread_manager_setter->SetConciergeClient(
-        base::WrapUnique(fake_concierge_client_));
+    setter->SetConciergeClient(base::WrapUnique(fake_concierge_client_));
   }
 
   void TearDown() override {
+    lock_to_single_user_manager_.reset();
+
     arc_session_manager_->Shutdown();
-    arc_session_manager_.reset();
     arc_service_manager_->set_browser_context(nullptr);
-    arc_service_manager_.reset();
 
     BrowserWithTestWindowTest::TearDown();
-    lock_to_single_user_manager_.reset();
+    arc_session_manager_.reset();
+    arc_service_manager_.reset();
 
     chromeos::CryptohomeClient::Shutdown();
     chromeos::LoginState::Shutdown();
diff --git a/chrome/browser/chromeos/policy/system_proxy_manager.cc b/chrome/browser/chromeos/policy/system_proxy_manager.cc
index 1fc7c4b..0c9bcf8 100644
--- a/chrome/browser/chromeos/policy/system_proxy_manager.cc
+++ b/chrome/browser/chromeos/policy/system_proxy_manager.cc
@@ -125,8 +125,11 @@
     // daemon and tell it to exit.
     // TODO(crbug.com/1055245,acostinas): Do not send shut-down command if
     // System-proxy is inactive.
-    chromeos::SystemProxyClient::Get()->ShutDownDaemon(base::BindOnce(
-        &SystemProxyManager::OnDaemonShutDown, weak_factory_.GetWeakPtr()));
+    system_proxy::ShutDownRequest request;
+    request.set_traffic_type(system_proxy::TrafficOrigin::ALL);
+    chromeos::SystemProxyClient::Get()->ShutDownProcess(
+        request, base::BindOnce(&SystemProxyManager::OnShutDownProcess,
+                                weak_factory_.GetWeakPtr()));
     system_services_address_.clear();
     return;
   }
@@ -205,10 +208,11 @@
   }
 }
 
-void SystemProxyManager::OnDaemonShutDown(
+void SystemProxyManager::OnShutDownProcess(
     const system_proxy::ShutDownResponse& response) {
   if (response.has_error_message() && !response.error_message().empty()) {
-    NET_LOG(ERROR) << "Failed to shutdown system proxy: " << kSystemProxyService
+    NET_LOG(ERROR) << "Failed to shutdown system proxy process: "
+                   << kSystemProxyService
                    << ", error: " << response.error_message();
   }
 }
diff --git a/chrome/browser/chromeos/policy/system_proxy_manager.h b/chrome/browser/chromeos/policy/system_proxy_manager.h
index efc53ff..8ad54ec 100644
--- a/chrome/browser/chromeos/policy/system_proxy_manager.h
+++ b/chrome/browser/chromeos/policy/system_proxy_manager.h
@@ -62,7 +62,7 @@
  private:
   void OnSetAuthenticationDetails(
       const system_proxy::SetAuthenticationDetailsResponse& response);
-  void OnDaemonShutDown(const system_proxy::ShutDownResponse& response);
+  void OnShutDownProcess(const system_proxy::ShutDownResponse& response);
   void OnClearUserCredentials(
       const system_proxy::ClearUserCredentialsResponse& response);
 
diff --git a/chrome/browser/conversions/OWNERS b/chrome/browser/conversions/OWNERS
new file mode 100644
index 0000000..8b8a4832
--- /dev/null
+++ b/chrome/browser/conversions/OWNERS
@@ -0,0 +1 @@
+file://content/browser/conversions/OWNERS
diff --git a/chrome/browser/conversions/conversions_usecounter_browsertest.cc b/chrome/browser/conversions/conversions_usecounter_browsertest.cc
new file mode 100644
index 0000000..ea82270c
--- /dev/null
+++ b/chrome/browser/conversions/conversions_usecounter_browsertest.cc
@@ -0,0 +1,122 @@
+// 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 "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/default_handlers.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Tests UseCounters recorded for the Conversion Measurement API. This is tested
+// in the Chrome layer, as UseCounter recording is not used with content shell.
+class ConversionsUseCounterBrowsertest : public InProcessBrowserTest {
+ public:
+  ConversionsUseCounterBrowsertest() = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Sets up the blink runtime feature for ConversionMeasurement.
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+  }
+
+  void SetUpOnMainThread() override {
+    host_resolver()->AddRule("*", "127.0.0.1");
+    server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+    net::test_server::RegisterDefaultHandlers(&server_);
+    server_.ServeFilesFromSourceDirectory("content/test/data");
+    content::SetupCrossSiteRedirector(&server_);
+    ASSERT_TRUE(server_.Start());
+  }
+
+ protected:
+  net::EmbeddedTestServer server_{net::EmbeddedTestServer::TYPE_HTTPS};
+};
+
+IN_PROC_BROWSER_TEST_F(ConversionsUseCounterBrowsertest,
+                       ImpressionClicked_FeatureRecorded) {
+  base::HistogramTester histogram_tester;
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  page_load_metrics::PageLoadMetricsTestWaiter waiter(web_contents);
+  waiter.AddWebFeatureExpectation(blink::mojom::WebFeature::kConversionAPIAll);
+
+  EXPECT_TRUE(ui_test_utils::NavigateToURL(
+      browser(),
+      server_.GetURL("a.test",
+                     "/conversions/page_with_impression_creator.html")));
+
+  // Create an anchor tag with impression attributes which opens a link in a
+  // new.
+  GURL link_url = server_.GetURL(
+      "b.test", "/conversions/page_with_conversion_redirect.html");
+  EXPECT_TRUE(ExecJs(web_contents, content::JsReplace(R"(
+    createImpressionTagWithTarget("link" /* id */,
+                        $1 /* url */,
+                        "1" /* impression data */,
+                        "https://b.test" /* conversion_destination */, "_blank");)",
+                                                      link_url)));
+
+  // Click the impression, and wait for the new window to open. Then switch to
+  // the tab with the impression.
+  content::WebContentsAddedObserver window_observer;
+  EXPECT_TRUE(ExecJs(web_contents, "simulateClick('link');"));
+  content::WebContents* new_contents = window_observer.GetWebContents();
+  WaitForLoadStop(new_contents);
+  browser()->tab_strip_model()->ActivateTabAt(0);
+  waiter.Wait();
+
+  // Navigate to a new page to flush metrics.
+  EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank")));
+
+  histogram_tester.ExpectBucketCount(
+      "Blink.UseCounter.Features",
+      blink::mojom::WebFeature::kImpressionRegistration, 1);
+  histogram_tester.ExpectBucketCount(
+      "Blink.UseCounter.Features", blink::mojom::WebFeature::kConversionAPIAll,
+      1);
+}
+
+IN_PROC_BROWSER_TEST_F(ConversionsUseCounterBrowsertest,
+                       ConversionPing_FeatureRecorded) {
+  base::HistogramTester histogram_tester;
+
+  EXPECT_TRUE(ui_test_utils::NavigateToURL(
+      browser(),
+      server_.GetURL("a.test",
+                     "/conversions/page_with_conversion_redirect.html")));
+
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Register a conversion with the original page as the reporting origin.
+  EXPECT_TRUE(ExecJs(web_contents, "registerConversion(7)"));
+
+  // Wait for the conversion redirect to be intercepted. This is indicated by
+  // window title changing when the img element for the conversion request fires
+  // an onerror event.
+  const base::string16 kConvertTitle = base::ASCIIToUTF16("converted");
+  content::TitleWatcher watcher(web_contents, kConvertTitle);
+  EXPECT_EQ(kConvertTitle, watcher.WaitAndGetTitle());
+
+  // Navigate to a new page to flush metrics.
+  EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank")));
+
+  histogram_tester.ExpectBucketCount(
+      "Blink.UseCounter.Features",
+      blink::mojom::WebFeature::kConversionRegistration, 1);
+  histogram_tester.ExpectBucketCount(
+      "Blink.UseCounter.Features", blink::mojom::WebFeature::kConversionAPIAll,
+      1);
+}
diff --git a/chrome/browser/extensions/active_tab_apitest.cc b/chrome/browser/extensions/active_tab_apitest.cc
index 6990ac3..bbb906e 100644
--- a/chrome/browser/extensions/active_tab_apitest.cc
+++ b/chrome/browser/extensions/active_tab_apitest.cc
@@ -51,7 +51,6 @@
   }
 
  private:
-
   DISALLOW_COPY_AND_ASSIGN(ExtensionActiveTabTest);
 };
 
@@ -251,7 +250,7 @@
     // Sanity check the last committed url on the |file_iframe|.
     content::RenderFrameHost* file_iframe = content::FrameMatchingPredicate(
         browser()->tab_strip_model()->GetActiveWebContents(),
-        base::Bind(&content::FrameMatchesName, "file_iframe"));
+        base::BindRepeating(&content::FrameMatchesName, "file_iframe"));
     bool is_file_url = file_iframe->GetLastCommittedURL() == GURL("file:///");
     EXPECT_EQ(allowed, is_file_url)
         << "Unexpected committed url: "
diff --git a/chrome/browser/extensions/active_tab_permission_granter.cc b/chrome/browser/extensions/active_tab_permission_granter.cc
index 4d6c9b60..4cb86850 100644
--- a/chrome/browser/extensions/active_tab_permission_granter.cc
+++ b/chrome/browser/extensions/active_tab_permission_granter.cc
@@ -30,7 +30,7 @@
 
 namespace {
 
-using CreateMessageFunction = base::Callback<IPC::Message*(bool)>;
+using CreateMessageFunction = base::RepeatingCallback<IPC::Message*(bool)>;
 
 // Creates a new IPC message for updating tab-specific permissions.
 IPC::Message* CreateUpdateMessage(const GURL& visible_url,
@@ -177,8 +177,8 @@
       // We update all extension render views with the new tab permissions, and
       // also the tab itself.
       CreateMessageFunction update_message =
-          base::Bind(&CreateUpdateMessage, navigation_entry->GetURL(),
-                     extension->id(), new_hosts.Clone(), tab_id_);
+          base::BindRepeating(&CreateUpdateMessage, navigation_entry->GetURL(),
+                              extension->id(), new_hosts.Clone(), tab_id_);
       SendMessageToProcesses(
           process_manager->GetRenderFrameHostsForExtension(extension->id()),
           web_contents()->GetMainFrame()->GetProcess(), update_message);
@@ -253,7 +253,7 @@
   }
 
   CreateMessageFunction clear_message =
-      base::Bind(&CreateClearMessage, extension_ids, tab_id_);
+      base::BindRepeating(&CreateClearMessage, extension_ids, tab_id_);
   SendMessageToProcesses(
       frame_hosts, web_contents()->GetMainFrame()->GetProcess(), clear_message);
 
diff --git a/chrome/browser/extensions/activity_log/activity_database.cc b/chrome/browser/extensions/activity_log/activity_database.cc
index 0e87b02..01356b6 100644
--- a/chrome/browser/extensions/activity_log/activity_database.cc
+++ b/chrome/browser/extensions/activity_log/activity_database.cc
@@ -59,9 +59,8 @@
   did_init_ = true;
   DCHECK(GetActivityLogTaskRunner()->RunsTasksInCurrentSequence());
   db_.set_histogram_tag("Activity");
-  db_.set_error_callback(
-      base::Bind(&ActivityDatabase::DatabaseErrorCallback,
-                 base::Unretained(this)));
+  db_.set_error_callback(base::BindRepeating(
+      &ActivityDatabase::DatabaseErrorCallback, base::Unretained(this)));
   db_.set_page_size(4096);
   db_.set_cache_size(32);
 
diff --git a/chrome/browser/extensions/activity_log/counting_policy_unittest.cc b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
index 62adbd87..72ed45d2 100644
--- a/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
@@ -112,7 +112,7 @@
     // Set up a timeout for receiving results; if we haven't received anything
     // when the timeout triggers then assume that the test is broken.
     base::CancelableClosure timeout(
-        base::Bind(&CountingPolicyTest::TimeoutCallback));
+        base::BindRepeating(&CountingPolicyTest::TimeoutCallback));
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, timeout.callback(), TestTimeouts::action_timeout());
 
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc b/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc
index 669ffa4..36a60f8 100644
--- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc
+++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc
@@ -70,8 +70,8 @@
 IN_PROC_BROWSER_TEST_F(ActivityLogApiTest, MAYBE_TriggerEvent) {
   ActivityLog::GetInstance(profile())->SetWatchdogAppActiveForTesting(true);
 
-  embedded_test_server()->RegisterRequestHandler(
-      base::Bind(&ActivityLogApiTest::HandleRequest, base::Unretained(this)));
+  embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+      &ActivityLogApiTest::HandleRequest, base::Unretained(this)));
   ASSERT_TRUE(StartEmbeddedTestServer());
 
   const Extension* friend_extension = LoadExtensionIncognito(
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
index 10fe5961..085689e 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -200,7 +200,8 @@
 CountryEntryList GenerateCountryList(
     const autofill::PersonalDataManager& personal_data) {
   autofill::CountryComboboxModel model;
-  model.SetCountries(personal_data, base::Callback<bool(const std::string&)>(),
+  model.SetCountries(personal_data,
+                     base::RepeatingCallback<bool(const std::string&)>(),
                      g_browser_process->GetApplicationLocale());
   const std::vector<std::unique_ptr<autofill::AutofillCountry>>& countries =
       model.countries();
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index 61aa3b7..0e44728 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -408,13 +408,13 @@
     const std::vector<char>& image_data,
     api::clipboard::ImageType type,
     AdditionalDataItemList additional_items,
-    const base::Closure& success_callback,
-    const base::Callback<void(const std::string&)>& error_callback) {
+    base::OnceClosure success_callback,
+    base::OnceCallback<void(const std::string&)> error_callback) {
   if (!clipboard_extension_helper_)
     clipboard_extension_helper_ = std::make_unique<ClipboardExtensionHelper>();
   clipboard_extension_helper_->DecodeAndSaveImageData(
-      image_data, type, std::move(additional_items), success_callback,
-      error_callback);
+      image_data, type, std::move(additional_items),
+      std::move(success_callback), std::move(error_callback));
 }
 #endif
 
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chrome/browser/extensions/api/chrome_extensions_api_client.h
index 98d45c9..15fa53b 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -86,8 +86,8 @@
       const std::vector<char>& image_data,
       api::clipboard::ImageType type,
       AdditionalDataItemList additional_items,
-      const base::Closure& success_callback,
-      const base::Callback<void(const std::string&)>& error_callback) override;
+      base::OnceClosure success_callback,
+      base::OnceCallback<void(const std::string&)> error_callback) override;
 #endif
 
   AutomationInternalApiDelegate* GetAutomationInternalApiDelegate() override;
diff --git a/chrome/browser/extensions/clipboard_extension_helper_chromeos.cc b/chrome/browser/extensions/clipboard_extension_helper_chromeos.cc
index 21f05c03..f22f9723 100644
--- a/chrome/browser/extensions/clipboard_extension_helper_chromeos.cc
+++ b/chrome/browser/extensions/clipboard_extension_helper_chromeos.cc
@@ -85,8 +85,8 @@
     const std::vector<char>& data,
     clipboard::ImageType type,
     AdditionalDataItemList additional_items,
-    const base::Closure& success_callback,
-    const base::Callback<void(const std::string&)>& error_callback) {
+    base::OnceClosure success_callback,
+    base::OnceCallback<void(const std::string&)> error_callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // If there is a previous image decoding request still running, cancel it
@@ -99,8 +99,8 @@
   // Cache additonal items.
   additonal_items_ = std::move(additional_items);
 
-  image_save_success_callback_ = success_callback;
-  image_save_error_callback_ = error_callback;
+  image_save_success_callback_ = std::move(success_callback);
+  image_save_error_callback_ = std::move(error_callback);
   clipboard_image_data_decoder_->Start(data, type);
 }
 
diff --git a/chrome/browser/extensions/clipboard_extension_helper_chromeos.h b/chrome/browser/extensions/clipboard_extension_helper_chromeos.h
index a8745b8..6c6bf9b 100644
--- a/chrome/browser/extensions/clipboard_extension_helper_chromeos.h
+++ b/chrome/browser/extensions/clipboard_extension_helper_chromeos.h
@@ -28,8 +28,8 @@
       const std::vector<char>& data,
       api::clipboard::ImageType type,
       AdditionalDataItemList additional_items,
-      const base::Closure& success_callback,
-      const base::Callback<void(const std::string&)>& error_callback);
+      base::OnceClosure success_callback,
+      base::OnceCallback<void(const std::string&)> error_callback);
 
  private:
   // A class to decode PNG and JPEG file.
@@ -43,8 +43,8 @@
   void OnImageDecodeCancel();
 
   std::unique_ptr<ClipboardImageDataDecoder> clipboard_image_data_decoder_;
-  base::Closure image_save_success_callback_;
-  base::Callback<void(const std::string&)> image_save_error_callback_;
+  base::OnceClosure image_save_success_callback_;
+  base::OnceCallback<void(const std::string&)> image_save_error_callback_;
   AdditionalDataItemList additonal_items_;
 
   DISALLOW_COPY_AND_ASSIGN(ClipboardExtensionHelper);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 010c5c3..6461c6e 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -384,6 +384,7 @@
     public static final String REPORT_FEED_USER_ACTIONS = "ReportFeedUserActions";
     public static final String REVAMPED_CONTEXT_MENU = "RevampedContextMenu";
     public static final String SAFETY_CHECK_ANDROID = "SafetyCheckAndroid";
+    public static final String SAFE_BROWSING_DELAYED_WARNINGS = "SafeBrowsingDelayedWarnings";
     public static final String SAFE_BROWSING_ENHANCED_PROTECTION_ENABLED =
             "SafeBrowsingEnhancedProtection";
     public static final String SAFE_BROWSING_SECURITY_SECTION_UI =
diff --git a/chrome/browser/installable/installable_task_queue.cc b/chrome/browser/installable/installable_task_queue.cc
index 41c423a..318c01e 100644
--- a/chrome/browser/installable/installable_task_queue.cc
+++ b/chrome/browser/installable/installable_task_queue.cc
@@ -67,18 +67,20 @@
   std::deque<InstallableTask> paused_tasks = std::move(paused_tasks_);
   // Some callbacks might be already invalidated on certain resets, so we must
   // check for that.
+  // Manifest is assumed to be non-null, so we create an empty one here.
+  blink::Manifest manifest;
   for (InstallableTask& task : tasks) {
     if (task.callback) {
       std::move(task.callback)
-          .Run(InstallableData({code}, GURL(), nullptr, GURL(), nullptr, false,
-                               GURL(), nullptr, false, false));
+          .Run(InstallableData({code}, GURL(), &manifest, GURL(), nullptr,
+                               false, GURL(), nullptr, false, false));
     }
   }
   for (InstallableTask& task : paused_tasks) {
     if (task.callback) {
       std::move(task.callback)
-          .Run(InstallableData({code}, GURL(), nullptr, GURL(), nullptr, false,
-                               GURL(), nullptr, false, false));
+          .Run(InstallableData({code}, GURL(), &manifest, GURL(), nullptr,
+                               false, GURL(), nullptr, false, false));
     }
   }
 }
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc
index 77a3580..da62a2d 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc
@@ -176,14 +176,14 @@
       case UpdateDeviceRequestResult::kSuccess:
         std::move(client->update_device_requests()[0].callback)
             .Run(TestResponse());
-        return;
+        break;
       case UpdateDeviceRequestResult::kHttpFailure:
         std::move(client->update_device_requests()[0].error_callback)
             .Run(NearbyShareRequestError::kBadRequest);
-        return;
+        break;
       case UpdateDeviceRequestResult::kTimeout:
         FastForward(kTestTimeout);
-        return;
+        break;
     }
     EXPECT_EQ(num_responses + 1, responses_.size());
 
diff --git a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.cc b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.cc
new file mode 100644
index 0000000..79d0ebdf
--- /dev/null
+++ b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h"
+
+#include "chrome/browser/password_manager/android/all_passwords_bottom_sheet_view.h"
+#include "components/password_manager/core/browser/password_manager_driver.h"
+#include "components/password_manager/core/browser/password_store.h"
+
+AllPasswordsBottomSheetController::AllPasswordsBottomSheetController(
+    password_manager::PasswordManagerDriver* driver,
+    password_manager::PasswordStore* store)
+    : driver_(driver), store_(store) {
+  DCHECK(driver_);
+  DCHECK(store_);
+}
+
+AllPasswordsBottomSheetController::~AllPasswordsBottomSheetController() =
+    default;
+
+void AllPasswordsBottomSheetController::Show() {
+  store_->GetAllLoginsWithAffiliationAndBrandingInformation(this);
+  view_->Show();
+  delete view_;
+}
+
+AllPasswordsBottomSheetController* AllPasswordsBottomSheetController::Create(
+    password_manager::PasswordManagerDriver* driver,
+    password_manager::PasswordStore* store) {
+  std::unique_ptr<AllPasswordsBottomSheetController> controller =
+      std::make_unique<AllPasswordsBottomSheetController>(driver, store);
+  AllPasswordsBottomSheetController* raw_controller = controller.get();
+  raw_controller->view_ =
+      AllPasswordsBottomSheetView::Create(std::move(controller));
+  return raw_controller;
+}
+
+void AllPasswordsBottomSheetController::OnGetPasswordStoreResults(
+    std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+  // TODO(crbug.com/1104132): Implement.
+}
diff --git a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h
new file mode 100644
index 0000000..dc69f76
--- /dev/null
+++ b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.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_PASSWORD_MANAGER_ANDROID_ALL_PASSWORDS_BOTTOM_SHEET_CONTROLLER_H_
+#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ALL_PASSWORDS_BOTTOM_SHEET_CONTROLLER_H_
+
+#include "components/password_manager/core/browser/password_store_consumer.h"
+
+namespace password_manager {
+class PasswordManagerDriver;
+class PasswordStore;
+}  // namespace password_manager
+
+class AllPasswordsBottomSheetView;
+
+// This class gets credentials and creates AllPasswordsBottomSheetView.
+class AllPasswordsBottomSheetController
+    : public password_manager::PasswordStoreConsumer {
+ public:
+  AllPasswordsBottomSheetController(
+      password_manager::PasswordManagerDriver* driver,
+      password_manager::PasswordStore* store);
+  ~AllPasswordsBottomSheetController() override;
+  AllPasswordsBottomSheetController(const AllPasswordsBottomSheetController&) =
+      delete;
+  AllPasswordsBottomSheetController& operator=(
+      const AllPasswordsBottomSheetController&) = delete;
+
+  // PasswordStoreConsumer:
+  void OnGetPasswordStoreResults(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
+
+  // Initializes the view and the controller.
+  // Doesn't take ownership of |driver|.
+  // Doesn't take ownership of |store|.
+  static AllPasswordsBottomSheetController* Create(
+      password_manager::PasswordManagerDriver* driver,
+      password_manager::PasswordStore* store);
+
+  // Instructs AllPasswordsBottomSheetView to show the credentials to the user.
+  void Show();
+
+ private:
+  // The controller doesn't take |driver_| ownership.
+  password_manager::PasswordManagerDriver* driver_ = nullptr;
+
+  // The controller doesn't take |store_| ownership.
+  password_manager::PasswordStore* store_ = nullptr;
+
+  // The controller takes |view_| ownership.
+  AllPasswordsBottomSheetView* view_ = nullptr;
+};
+
+#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ALL_PASSWORDS_BOTTOM_SHEET_CONTROLLER_H_
diff --git a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_view.cc b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_view.cc
new file mode 100644
index 0000000..fbdcff7
--- /dev/null
+++ b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_view.cc
@@ -0,0 +1,28 @@
+// 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/password_manager/android/all_passwords_bottom_sheet_view.h"
+
+#include "chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h"
+#include "components/password_manager/core/browser/password_manager_driver.h"
+
+AllPasswordsBottomSheetView::AllPasswordsBottomSheetView(
+    std::unique_ptr<AllPasswordsBottomSheetController> controller)
+    : controller_(std::move(controller)) {}
+
+AllPasswordsBottomSheetView::AllPasswordsBottomSheetView(
+    AllPasswordsBottomSheetView&&) = default;
+AllPasswordsBottomSheetView& AllPasswordsBottomSheetView::operator=(
+    AllPasswordsBottomSheetView&&) = default;
+
+AllPasswordsBottomSheetView::~AllPasswordsBottomSheetView() = default;
+
+AllPasswordsBottomSheetView* AllPasswordsBottomSheetView::Create(
+    std::unique_ptr<AllPasswordsBottomSheetController> controller) {
+  return new AllPasswordsBottomSheetView(std::move(controller));
+}
+
+void AllPasswordsBottomSheetView::AllPasswordsBottomSheetView::Show() {
+  // TODO(crbug.com/1104132): Implement.
+}
diff --git a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_view.h b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_view.h
new file mode 100644
index 0000000..35de460
--- /dev/null
+++ b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_view.h
@@ -0,0 +1,37 @@
+// 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_PASSWORD_MANAGER_ANDROID_ALL_PASSWORDS_BOTTOM_SHEET_VIEW_H_
+#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ALL_PASSWORDS_BOTTOM_SHEET_VIEW_H_
+
+#include <memory>
+
+class AllPasswordsBottomSheetController;
+
+// Bridge AllPasswordsBottomSheet native and java view code by converting user
+// credentials data into java-readable formats.
+class AllPasswordsBottomSheetView {
+ public:
+  AllPasswordsBottomSheetView(
+      std::unique_ptr<AllPasswordsBottomSheetController> controller);
+  AllPasswordsBottomSheetView(const AllPasswordsBottomSheetView&) = delete;
+  AllPasswordsBottomSheetView& operator=(const AllPasswordsBottomSheetView&) =
+      delete;
+  AllPasswordsBottomSheetView(AllPasswordsBottomSheetView&&);
+  AllPasswordsBottomSheetView& operator=(AllPasswordsBottomSheetView&&);
+  ~AllPasswordsBottomSheetView();
+
+  // Create an instance of the view with passed controller.
+  // return a raw pointer for the view.
+  static AllPasswordsBottomSheetView* Create(
+      std::unique_ptr<AllPasswordsBottomSheetController> controller);
+
+  // Makes call to java bridge to show AllPasswordsBottomSheet view.
+  void Show();
+
+ private:
+  std::unique_ptr<AllPasswordsBottomSheetController> controller_ = nullptr;
+};
+
+#endif  // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_ALL_PASSWORDS_BOTTOM_SHEET_VIEW_H_
diff --git a/chrome/browser/password_manager/android/password_accessory_controller_impl.cc b/chrome/browser/password_manager/android/password_accessory_controller_impl.cc
index d224e9b..1724874c 100644
--- a/chrome/browser/password_manager/android/password_accessory_controller_impl.cc
+++ b/chrome/browser/password_manager/android/password_accessory_controller_impl.cc
@@ -17,6 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autofill/manual_filling_controller.h"
 #include "chrome/browser/autofill/manual_filling_utils.h"
+#include "chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller.h"
 #include "chrome/browser/password_manager/android/password_accessory_controller.h"
 #include "chrome/browser/password_manager/android/password_accessory_metrics_util.h"
 #include "chrome/browser/password_manager/android/password_generation_controller.h"
@@ -197,6 +198,18 @@
 
 void PasswordAccessoryControllerImpl::OnOptionSelected(
     autofill::AccessoryAction selected_action) {
+  if (selected_action == autofill::AccessoryAction::USE_OTHER_PASSWORD) {
+    password_manager::ContentPasswordManagerDriverFactory* factory =
+        password_manager::ContentPasswordManagerDriverFactory::FromWebContents(
+            web_contents_);
+    password_manager::ContentPasswordManagerDriver* driver =
+        factory->GetDriverForFrame(web_contents_->GetFocusedFrame());
+    AllPasswordsBottomSheetController* controller =
+        AllPasswordsBottomSheetController::Create(
+            driver, password_client_->GetProfilePasswordStore());
+    controller->Show();
+    return;
+  }
   if (selected_action == autofill::AccessoryAction::MANAGE_PASSWORDS) {
     password_manager_launcher::ShowPasswordSettings(
         web_contents_,
@@ -263,6 +276,15 @@
     }
   }
 
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::kFillingPasswordsFromAnyOrigin)) {
+    base::string16 use_other_password_title = l10n_util::GetStringUTF16(
+        IDS_PASSWORD_MANAGER_ACCESSORY_USE_OTHER_PASSWORD);
+    footer_commands_to_add.push_back(
+        FooterCommand(use_other_password_title,
+                      autofill::AccessoryAction::USE_OTHER_PASSWORD));
+  }
+
   if (is_password_field && is_manual_generation_available) {
     base::string16 generate_password_title = l10n_util::GetStringUTF16(
         IDS_PASSWORD_MANAGER_ACCESSORY_GENERATE_PASSWORD_BUTTON_TITLE);
diff --git a/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc b/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc
index 9511557..e94de53 100644
--- a/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc
+++ b/chrome/browser/password_manager/android/password_accessory_controller_impl_unittest.cc
@@ -142,6 +142,11 @@
   return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_EMPTY_LOGIN);
 }
 
+base::string16 show_other_passwords_str() {
+  return l10n_util::GetStringUTF16(
+      IDS_PASSWORD_MANAGER_ACCESSORY_USE_OTHER_PASSWORD);
+}
+
 base::string16 manage_passwords_str() {
   return l10n_util::GetStringUTF16(
       IDS_PASSWORD_MANAGER_ACCESSORY_ALL_PASSWORDS_LINK);
@@ -627,6 +632,41 @@
       /*is_manual_generation_available=*/false);
 }
 
+TEST_F(PasswordAccessoryControllerTest, AddsShowOtherPasswordsIfEnabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      password_manager::features::kFillingPasswordsFromAnyOrigin);
+  AccessorySheetData::Builder data_builder(AccessoryTabType::PASSWORDS,
+                                           passwords_empty_str(kExampleDomain));
+  data_builder
+      .AppendFooterCommand(show_other_passwords_str(),
+                           autofill::AccessoryAction::USE_OTHER_PASSWORD)
+      .AppendFooterCommand(manage_passwords_str(),
+                           autofill::AccessoryAction::MANAGE_PASSWORDS);
+  EXPECT_CALL(mock_manual_filling_controller_,
+              RefreshSuggestions(std::move(data_builder).Build()));
+
+  controller()->RefreshSuggestionsForField(
+      FocusedFieldType::kFillablePasswordField,
+      /*is_manual_generation_available=*/false);
+}
+
+TEST_F(PasswordAccessoryControllerTest, HidesShowOtherPasswordsIfDisabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(
+      password_manager::features::kFillingPasswordsFromAnyOrigin);
+  AccessorySheetData::Builder data_builder(AccessoryTabType::PASSWORDS,
+                                           passwords_empty_str(kExampleDomain));
+  data_builder.AppendFooterCommand(manage_passwords_str(),
+                                   autofill::AccessoryAction::MANAGE_PASSWORDS);
+  EXPECT_CALL(mock_manual_filling_controller_,
+              RefreshSuggestions(std::move(data_builder).Build()));
+
+  controller()->RefreshSuggestionsForField(
+      FocusedFieldType::kFillablePasswordField,
+      /*is_manual_generation_available=*/false);
+}
+
 TEST_F(PasswordAccessoryControllerTest,
        NoSaveToggleIfIsBlacklistedAndSavingDisabled) {
   base::test::ScopedFeatureList scoped_feature_list;
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 6bc07b6..db1db22 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <algorithm>
+#include <memory>
 #include <set>
 #include <utility>
 
@@ -154,6 +155,7 @@
 #include "third_party/blink/public/public_buildflags.h"
 #include "third_party/metrics_proto/omnibox_input_type.pb.h"
 #include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/clipboard_data_endpoint.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/emoji/emoji_panel_helper.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -771,7 +773,8 @@
   if (url.is_empty() || !url.is_valid())
     return;
 
-  ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
+  ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste,
+                                CreateDataEndpoint());
   scw.WriteText(FormatURLForClipboard(url));
 }
 
@@ -2665,6 +2668,16 @@
   }
 }
 
+std::unique_ptr<ui::ClipboardDataEndpoint>
+RenderViewContextMenu::CreateDataEndpoint() {
+  RenderFrameHost* render_frame_host = GetRenderFrameHost();
+  if (render_frame_host) {
+    return std::make_unique<ui::ClipboardDataEndpoint>(
+        render_frame_host->GetLastCommittedURL());
+  }
+  return nullptr;
+}
+
 bool RenderViewContextMenu::IsRouteMediaEnabled() const {
   if (!media_router::MediaRouterEnabled(browser_context_))
     return false;
@@ -2838,7 +2851,8 @@
 }
 
 void RenderViewContextMenu::ExecCopyLinkText() {
-  ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
+  ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste,
+                                CreateDataEndpoint());
   scw.WriteText(params_.link_text);
 }
 
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index 93b1df8..9da13ac1 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -62,6 +62,10 @@
 }
 }
 
+namespace ui {
+class ClipboardDataEndpoint;
+}
+
 class RenderViewContextMenu : public RenderViewContextMenuBase {
  public:
   RenderViewContextMenu(content::RenderFrameHost* render_frame_host,
@@ -138,7 +142,7 @@
   static base::string16 FormatURLForClipboard(const GURL& url);
 
   // Writes the specified text/url to the system clipboard.
-  static void WriteURLToClipboard(const GURL& url);
+  void WriteURLToClipboard(const GURL& url);
 
   // RenderViewContextMenuBase:
   void InitMenu() override;
@@ -195,6 +199,8 @@
   void AppendSharedClipboardItem();
   void AppendQRCodeGeneratorItem(bool for_image, bool draw_icon);
 
+  std::unique_ptr<ui::ClipboardDataEndpoint> CreateDataEndpoint();
+
   // Command enabled query functions.
   bool IsReloadEnabled() const;
   bool IsViewSourceEnabled() const;
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index 50730d12..8cfe9eb 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -216,6 +216,8 @@
 
 js_library("oobe_eula") {
   deps = [
+    ":web_view_helper",
+    "components:login_screen_behavior",
     "components:oobe_dialog",
     "components:oobe_dialog_host_behavior",
     "components:oobe_i18n_behavior",
@@ -284,3 +286,6 @@
 
 js_library("update_required_card") {
 }
+
+js_library("web_view_helper") {
+}
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js
index d3d75f0..ba40e64 100644
--- a/chrome/browser/resources/chromeos/login/oobe.js
+++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -38,7 +38,6 @@
 // <include src="oobe_screen_demo_setup.js">
 // <include src="oobe_screen_demo_preferences.js">
 // <include src="oobe_screen_enable_debugging.js">
-// <include src="oobe_screen_eula.js">
 // <include src="multi_tap_detector.js">
 // <include src="web_view_helper.js">
 
@@ -50,7 +49,6 @@
      */
     initialize() {
       cr.ui.login.DisplayManager.initialize();
-      login.EulaScreen.register();
       login.AutoEnrollmentCheckScreen.register();
       login.EnableDebuggingScreen.register();
       login.AutolaunchScreen.register();
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.css b/chrome/browser/resources/chromeos/login/oobe_eula.css
index 0bc36a67..3642ae4 100644
--- a/chrome/browser/resources/chromeos/login/oobe_eula.css
+++ b/chrome/browser/resources/chromeos/login/oobe_eula.css
@@ -17,7 +17,7 @@
   height: 300px;
 }
 
-#installationSettings,
+#securitySettings,
 #logging {
   font-size: 13px;
   min-height: unset;
@@ -28,7 +28,7 @@
 }
 
 #additionalTerms,
-#installationSettings,
+#securitySettings,
 #logging {
   margin-top: 16px;
 }
@@ -65,6 +65,6 @@
   user-select: text;
 }
 
-.installation-settings-spinner {
+.security-settings-spinner {
   margin-inline-end: 5px;
 }
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.html b/chrome/browser/resources/chromeos/login/oobe_eula.html
index 788ee54..89633e79 100644
--- a/chrome/browser/resources/chromeos/login/oobe_eula.html
+++ b/chrome/browser/resources/chromeos/login/oobe_eula.html
@@ -40,10 +40,10 @@
               class="oobe-local-link">
             [[i18nDynamic(locale, 'oobeEulaAditionalTerms')]]
           </a>
-          <a id="installationSettings" href="#"
+          <a id="securitySettings" href="#"
               class="oobe-local-link"
-              on-tap="onInstallationSettingsClicked_">
-            [[i18nDynamic(locale, 'eulaSystemInstallationSettings')]]
+              on-tap="onSecuritySettingsClicked_">
+            [[i18nDynamic(locale, 'eulaSystemSecuritySettings')]]
           </a>
           <div id="logging" class="layout horizontal">
             <cr-checkbox id="usageStats" class="layout start self-center"
@@ -53,7 +53,7 @@
                 <span id="usageStatsLabel">
                   [[i18nDynamic(locale, 'checkboxLogging')]]
                 </span>
-                <a id="learn-more" href="#"
+                <a id="learnMore" href="#"
                     on-tap="onUsageStatsHelpLinkClicked_"
                     class="oobe-local-link">
                   [[i18nDynamic(locale, 'learnMore')]]
@@ -75,9 +75,9 @@
         </oobe-text-button>
       </div>
     </oobe-dialog>
-    <oobe-dialog id="installationSettingsDialog" role="dialog" has-buttons
-      title-key="eulaSystemInstallationSettings" hidden
-      aria-label$="[[i18nDynamic(locale, 'eulaSystemInstallationSettings')]]">
+    <oobe-dialog id="securitySettingsDialog" role="dialog" has-buttons
+      title-key="eulaSystemSecuritySettings" hidden
+      aria-label$="[[i18nDynamic(locale, 'eulaSystemSecuritySettings')]]">
       <hd-iron-icon slot="oobe-icon"
           icon1x="oobe-32:googleg" icon2x="oobe-64:googleg">
       </hd-iron-icon>
@@ -95,7 +95,7 @@
           </div>
           <div class="layout horizontal"
               hidden="[[!isWaitingForPassword_(password)]]">
-            <div class="installation-settings-spinner throbber"></div>
+            <div class="security-settings-spinner throbber"></div>
             <div>
               [[i18nDynamic(locale, 'eulaTpmBusy')]]
             </div>
@@ -111,11 +111,11 @@
         <div class="flex"></div>
         <oobe-text-button id="settings-close-button" inverse
             class="focus-on-show"
-            text-key="eulaSystemInstallationSettingsOkButton"
-            on-tap="onInstallationSettingsCloseClicked_"></oobe-text-button>
+            text-key="eulaSystemSecuritySettingsOkButton"
+            on-tap="onSecuritySettingsCloseClicked_"></oobe-text-button>
       </div>
     </oobe-dialog>
-    <cr-dialog id="additional-tos" ignore-popstate
+    <cr-dialog id="additionalToS" ignore-popstate
         on-close="focusAdditionalTermsLink_"
         on-cancel="focusAdditionalTermsLink_">
       <div slot="title">
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.js b/chrome/browser/resources/chromeos/login/oobe_eula.js
index 04990de..646bc477 100644
--- a/chrome/browser/resources/chromeos/login/oobe_eula.js
+++ b/chrome/browser/resources/chromeos/login/oobe_eula.js
@@ -2,6 +2,231 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+(function() {
+const CLEAR_ANCHORS_CONTENT_SCRIPT = {
+  code: 'A=Array.from(document.getElementsByTagName("a"));' +
+      'for(var i = 0; i < A.length; ++i) {' +
+      '  const el = A[i];' +
+      '  let e = document.createElement("span");' +
+      '  if (el.textContent.trim().length > 0) {' +
+      '    e.textContent=el.textContent + "(" + el.href + ")";' +
+      '  }' +
+      '  el.parentNode.replaceChild(e,el);' +
+      '}'
+};
+
+const EULA_FONTS_CSS = {
+  code: `body * {
+        font-family: Roboto, sans-serif !important;
+        font-size: 13px !important;
+        background-color: transparent !important;
+        line-height: 20px !important;}
+       body {
+        background-color: transparent !important;
+       }
+       body h2 {
+         font-size: 15px !important;
+         line-height: 22px !important;}`
+};
+
+/**
+ * Timeout to load online Eula.
+ * @type {number}
+ */
+const ONLINE_EULA_LOAD_TIMEOUT_IN_MS = 7000;
+
+/**
+ * Timeout between consequent loads of online Eula.
+ * @type {number}
+ */
+const ONLINE_EULA_RETRY_BACKOFF_TIMEOUT_IN_MS = 1000;
+
+/**
+ * URL to use when online page is not available.
+ * @type {string}
+ */
+const TERMS_URL = 'chrome://terms';
+
+// EulaLoader assists on the process of loading an URL into a webview.
+// It listens for events from the webRequest API for the given URL and
+// loads an offline version of the EULA in case of failure. Calling
+// setURL() multiple times with the same URL while requests are being made
+// won't affect current requests. Instead, it will mark the flag
+// 'reloadRequested' for the given URL. The reload will be performed only
+// if the current requests fail. This prevents webview-loadAbort events
+// from being fired and unnecessary reloads.
+class EulaLoader {
+  /**
+   * @suppress {missingProperties} as WebView type has no addContentScripts
+   */
+  constructor(webview, timeout, load_offline_callback, clear_anchors) {
+    assert(webview.tagName === 'WEBVIEW');
+
+    // Do not create multiple loaders.
+    if (EulaLoader.instances[webview.id]) {
+      return EulaLoader.instances[webview.id];
+    }
+
+    this.webview_ = webview;
+    this.timeout_ = timeout;
+    this.isPerformingRequests_ = false;
+    this.reloadRequested_ = false;
+    this.loadOfflineCallback_ = load_offline_callback;
+    this.loadTimer_ = 0;
+    this.backOffTimer_ = 0;
+    this.url_ = '';
+
+    if (clear_anchors) {
+      // Add the CLEAR_ANCHORS_CONTENT_SCRIPT that will clear <a><\a>
+      // (anchors) in order to prevent any navigation in the webview itself.
+      webview.addContentScripts([{
+        name: 'clearAnchors',
+        matches: ['<all_urls>'],
+        js: CLEAR_ANCHORS_CONTENT_SCRIPT,
+      }]);
+      webview.addEventListener('contentload', () => {
+        webview.executeScript(CLEAR_ANCHORS_CONTENT_SCRIPT);
+      });
+    }
+    webview.addEventListener('contentload', () => {
+      webview.insertCSS(EULA_FONTS_CSS);
+    });
+
+    // Monitor webRequests API events
+    this.webview_.request.onCompleted.addListener(
+        this.onCompleted_.bind(this),
+        {urls: ['<all_urls>'], types: ['main_frame']});
+    this.webview_.request.onErrorOccurred.addListener(
+        this.onErrorOccurred_.bind(this),
+        {urls: ['<all_urls>'], types: ['main_frame']});
+
+    // The only instance of the EulaLoader.
+    EulaLoader.instances[webview.id] = this;
+  }
+
+  // Clears the internal state of the EULA loader. Stops the timeout timer
+  // and prevents events from being handled.
+  clearInternalState() {
+    window.clearTimeout(this.loadTimer_);
+    window.clearTimeout(this.backOffTimer_);
+    this.isPerformingRequests_ = false;
+    this.reloadRequested_ = false;
+  }
+
+  // Sets an URL to be loaded in the webview. If the URL is different from the
+  // previous one, it will be immediately loaded. If the URL is the same as
+  // the previous one, it will be reloaded. If requests are under way, the
+  // reload will be performed once the current requests are finished.
+  setUrl(url) {
+    assert(/^https?:\/\//.test(url));
+
+    if (url != this.url_) {
+      // Clear the internal state and start with a new URL.
+      this.clearInternalState();
+      this.url_ = url;
+      this.loadWithFallbackTimer();
+    } else {
+      // Same URL was requested again. Reload later if a request is under way.
+      if (this.isPerformingRequests_)
+        this.reloadRequested_ = true;
+      else
+        this.loadWithFallbackTimer();
+    }
+  }
+
+  // This method only gets invoked if the webview webRequest API does not
+  // fire either 'onErrorOccurred' or 'onCompleted' before the timer runs out.
+  // See: https://developer.chrome.com/extensions/webRequest
+  onTimeoutError_() {
+    // Return if we are no longer monitoring requests. Sanity check.
+    if (!this.isPerformingRequests_)
+      return;
+
+    if (this.reloadRequested_)
+      this.loadWithFallbackTimer();
+    else
+      this.tryLoadOffline();
+  }
+
+  // Loads the offline version of the EULA.
+  tryLoadOffline() {
+    this.clearInternalState();
+    if (this.loadOfflineCallback_)
+      this.loadOfflineCallback_();
+  }
+
+  /**
+   * Only process events for the current URL and when performing requests.
+   * @param {!Object} details
+   */
+  shouldProcessEvent(details) {
+    return this.isPerformingRequests_ && (details.url === this.url_);
+  }
+
+  /**
+   * webRequest API Event Handler for 'onErrorOccurred'
+   * @param {!Object} details
+   */
+  onErrorOccurred_(details) {
+    if (!this.shouldProcessEvent(details))
+      return;
+
+    if (this.reloadRequested_)
+      this.loadWithFallbackTimer();
+    else
+      this.loadAfterBackoff();
+  }
+
+  /**
+   * webRequest API Event Handler for 'onCompleted'
+   * @suppress {missingProperties} no statusCode for details
+   * @param {!Object} details
+   */
+  onCompleted_(details) {
+    if (!this.shouldProcessEvent(details))
+      return;
+
+    // Http errors such as 4xx, 5xx hit here instead of 'onErrorOccurred'.
+    if (details.statusCode != 200) {
+      // Not a successful request. Perform a reload if requested.
+      if (this.reloadRequested_)
+        this.loadWithFallbackTimer();
+      else
+        this.loadAfterBackoff();
+    } else {
+      // Success!
+      this.clearInternalState();
+    }
+  }
+
+  // Loads the URL into the webview and starts a timer.
+  loadWithFallbackTimer() {
+    // Clear previous timer and perform a load.
+    window.clearTimeout(this.loadTimer_);
+    this.loadTimer_ =
+        window.setTimeout(this.onTimeoutError_.bind(this), this.timeout_);
+    this.tryLoadOnline();
+  }
+
+  loadAfterBackoff() {
+    window.clearTimeout(this.backOffTimer_);
+    this.backOffTimer_ = window.setTimeout(
+        this.tryLoadOnline.bind(this), ONLINE_EULA_RETRY_BACKOFF_TIMEOUT_IN_MS);
+  }
+
+  tryLoadOnline() {
+    this.reloadRequested_ = false;
+    // A request is being made
+    this.isPerformingRequests_ = true;
+    if (this.webview_.src === this.url_)
+      this.webview_.reload();
+    else
+      this.webview_.src = this.url_;
+  }
+}
+
+EulaLoader.instances = {};
+
 /**
  * @fileoverview Polymer element for displaying material design Terms Of Service
  * screen.
@@ -10,7 +235,14 @@
 Polymer({
   is: 'oobe-eula-md',
 
-  behaviors: [OobeI18nBehavior, OobeDialogHostBehavior],
+  behaviors: [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior],
+
+  EXTERNAL_API: [
+    'setTpmPassword',
+    'setUsageStats',
+    'showAdditionalTosDialog',
+    'showSecuritySettingsDialog',
+  ],
 
   properties: {
     /**
@@ -38,23 +270,12 @@
     },
 
     /**
-     * The TPM password shown on the installation settings page.
+     * The TPM password shown on the security settings page.
      */
     password: {
       type: String,
       value: null,
     },
-
-    /**
-     * Reference to OOBE screen object.
-     * @type {!{
-     *     loadEulaToWebview_: function(Element, string, boolean),
-     *     onUsageStatsClicked_: function(boolean),
-     * }}
-     */
-    screen: {
-      type: Object,
-    },
   },
 
   /**
@@ -65,15 +286,22 @@
 
   focus() {
     if (this.eulaLoadingScreenShown) {
-      this.$.eulaLoadingDialog.show();
+      this.$.eulaLoadingDialog.focus();
     } else {
-      this.$.eulaDialog.show();
+      this.$.crosEulaFrame.focus();
     }
   },
 
-  /** Called when dialog is shown */
+  /** Called just before the dialog is shown */
   onBeforeShow() {
     window.setTimeout(this.initializeScreen_.bind(this), 0);
+    this.updateLocalizedContent();
+  },
+
+  ready() {
+    this.initializeLoginScreen('EulaScreen', {
+      resetAllowed: true,
+    });
   },
 
   /**
@@ -115,19 +343,48 @@
   },
 
   /**
+   * Load Eula into the given webview. Online version is attempted first with
+   * a timeout. If it fails to load, fallback to chrome://terms. The loaded
+   * terms contents is then set to the webview via data url. Webview is
+   * used as a sandbox for both online and local contents. Data url is
+   * used for chrome://terms so that webview never needs to have the
+   * privileged webui bindings.
+   *
+   * @param {!Object} webview Webview element to host the terms.
+   * @param {!string} onlineEulaUrl
+   * @param {boolean} clear_anchors if true the script will clear anchors
+   *                                from the loaded page.
+   */
+  loadEulaToWebview_(webview, onlineEulaUrl, clear_anchors) {
+    assert(webview.tagName === 'WEBVIEW');
+
+    var loadBundledEula = function() {
+      WebViewHelper.loadUrlContentToWebView(
+          webview, TERMS_URL, WebViewHelper.ContentType.HTML);
+    };
+
+    // Load online Eula with a timeout to fallback to the offline version.
+    // This won't construct multiple EulaLoaders. Single instance.
+    var eulaLoader = new EulaLoader(
+        webview, ONLINE_EULA_LOAD_TIMEOUT_IN_MS, loadBundledEula,
+        clear_anchors);
+    eulaLoader.setUrl(onlineEulaUrl);
+  },
+
+  /**
    * This is called when strings are updated.
    */
-  updateLocalizedContent(event) {
+  updateLocalizedContent() {
     // This forces frame to reload.
     const onlineEulaUrl = loadTimeData.getString('eulaOnlineUrl');
 
     this.eulaLoadingScreenShown = true;
-    this.screen.loadEulaToWebview_(
+    this.loadEulaToWebview_(
         this.$.crosEulaFrame, onlineEulaUrl, false /* clear_anchors */);
 
     const additionalToSUrl =
         loadTimeData.getString('eulaAdditionalToSOnlineUrl');
-    this.screen.loadEulaToWebview_(
+    this.loadEulaToWebview_(
         this.$.additionalChromeToSFrame, additionalToSUrl,
         true /* clear_anchors */);
     this.i18nUpdateLocale();
@@ -139,7 +396,7 @@
    * @private
    */
   eulaAccepted_() {
-    chrome.send('login.EulaScreen.userActed', ['accept-button']);
+    this.userActed('accept-button');
   },
 
   /**
@@ -148,21 +405,26 @@
    * @private
    */
   onUsageChanged_() {
-    if (this.$.usageStats.checked) {
-      chrome.send('login.EulaScreen.userActed', ['select-stats-usage']);
+    if (this.usageStatsChecked) {
+      this.userActed('select-stats-usage');
     } else {
-      chrome.send('login.EulaScreen.userActed', ['unselect-stats-usage']);
+      this.userActed('unselect-stats-usage');
     }
-    this.screen.onUsageStatsClicked_(this.$.usageStats.checked);
   },
 
   /**
    * @private
    */
   onAdditionalTermsClicked_() {
-    chrome.send('login.EulaScreen.userActed', ['show-additional-tos']);
-    this.$['additional-tos'].showModal();
-    this.$['close-additional-tos'].focus();
+    this.userActed('show-additional-tos');
+  },
+
+  /**
+   * Shows additional terms of service dialog.
+   */
+  showAdditionalTosDialog() {
+    this.$.additionalToS.showModal();
+    this.$.additionalToS.focus();
   },
 
   /**
@@ -171,7 +433,7 @@
    * @private
    */
   hideToSDialog_() {
-    this.$['additional-tos'].close();
+    this.$.additionalToS.close();
   },
 
   /**
@@ -182,28 +444,33 @@
   },
 
   /**
-   * On-tap event handler for installationSettings.
+   * On-tap event handler for securitySettings.
    *
    * @private
    */
-  onInstallationSettingsClicked_() {
-    chrome.send('login.EulaScreen.userActed', ['show-security-settings']);
-    chrome.send('eulaOnInstallationSettingsPopupOpened');
-    this.$.eulaDialog.hidden = true;
-    this.$.installationSettingsDialog.hidden = false;
-    this.$.installationSettingsDialog.show();
+  onSecuritySettingsClicked_() {
+    this.userActed('show-security-settings');
   },
 
   /**
-   * On-tap event handler for the close button on installation settings page.
+   * Shows system security settings dialog.
+   */
+  showSecuritySettingsDialog() {
+    this.$.eulaDialog.hidden = true;
+    this.$.securitySettingsDialog.hidden = false;
+    this.$.securitySettingsDialog.show();
+  },
+
+  /**
+   * On-tap event handler for the close button on security settings page.
    *
    * @private
    */
-  onInstallationSettingsCloseClicked_() {
-    this.$.installationSettingsDialog.hidden = true;
+  onSecuritySettingsCloseClicked_() {
+    this.$.securitySettingsDialog.hidden = true;
     this.$.eulaDialog.hidden = false;
     this.$.eulaDialog.show();
-    this.$.installationSettings.focus();
+    this.$.securitySettings.focus();
   },
 
   /**
@@ -212,9 +479,8 @@
    * @private
    */
   onUsageStatsHelpLinkClicked_(e) {
-    chrome.send('login.EulaScreen.userActed', ['show-stats-usage-learn-more']);
-    this.$['learn-more'].focus();
-    chrome.send('eulaOnLearnMore');
+    this.userActed('show-stats-usage-learn-more');
+    this.$.learnMore.focus();
     e.stopPropagation();
   },
 
@@ -224,7 +490,7 @@
    * @private
    */
   onEulaBackButtonPressed_() {
-    chrome.send('login.EulaScreen.userActed', ['back-button']);
+    this.userActed('back-button');
   },
 
   /**
@@ -244,4 +510,28 @@
   isPasswordEmpty_(password) {
     return password != null && password.length == 0;
   },
+
+  /**
+   * Sets TPM password.
+   * @param {string} password TPM password to be shown.
+   */
+  setTpmPassword(password) {
+    this.password = password;
+  },
+
+  /**
+   * Sets usage statistics checkbox.
+   * @param {boolean} checked Is the checkbox checked?
+   */
+  setUsageStats(checked) {
+    this.usageStatsChecked = checked;
+  },
+
+  /**
+   * Called when focus is returned.
+   */
+  onFocusReturned() {
+    this.focus();
+  },
 });
+})();
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_eula.html b/chrome/browser/resources/chromeos/login/oobe_screen_eula.html
deleted file mode 100644
index d4794f3..0000000
--- a/chrome/browser/resources/chromeos/login/oobe_screen_eula.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<div class="step hidden" id="eula" role="group"
-     i18n-values="aria-label:eulaScreenAccessibleTitle" hidden>
-  <oobe-eula-md id="oobe-eula-md"></oobe-eula-md>
-</div>
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_eula.js b/chrome/browser/resources/chromeos/login/oobe_screen_eula.js
deleted file mode 100644
index 1fbbad8a..0000000
--- a/chrome/browser/resources/chromeos/login/oobe_screen_eula.js
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview Oobe eula screen implementation.
- */
-
-login.createScreen('EulaScreen', 'eula', function() {
-  const CLEAR_ANCHORS_CONTENT_SCRIPT = {
-    code: 'A=Array.from(document.getElementsByTagName("a"));' +
-        'for(var i = 0; i < A.length; ++i) {' +
-        '  const el = A[i];' +
-        '  let e = document.createElement("span");' +
-        '  if (el.textContent.trim().length > 0) {' +
-        '    e.textContent=el.textContent + "(" + el.href + ")";' +
-        '  }' +
-        '  el.parentNode.replaceChild(e,el);' +
-        '}'
-  };
-
-  const EULA_FONTS_CSS = {
-    code: `body * {
-          font-family: Roboto, sans-serif !important;
-          font-size: 13px !important;
-          background-color: transparent !important;
-          line-height: 20px !important;}
-         body {
-          background-color: transparent !important;
-         }
-         body h2 {
-           font-size: 15px !important;
-           line-height: 22px !important;}`
-  };
-
-  /**
-   * Timeout to load online Eula.
-   * @type {number}
-   */
-  const ONLINE_EULA_LOAD_TIMEOUT_IN_MS = 7000;
-
-  /**
-   * Timeout between consequent loads of online Eula.
-   * @type {number}
-   */
-  const ONLINE_EULA_RETRY_BACKOFF_TIMEOUT_IN_MS = 1000;
-
-  /**
-   * URL to use when online page is not available.
-   * @type {string}
-   */
-  const TERMS_URL = 'chrome://terms';
-
-  // EulaLoader assists on the process of loading an URL into a webview.
-  // It listens for events from the webRequest API for the given URL and
-  // loads an offline version of the EULA in case of failure. Calling
-  // setURL() multiple times with the same URL while requests are being made
-  // won't affect current requests. Instead, it will mark the flag
-  // 'reloadRequested' for the given URL. The reload will be performed only
-  // if the current requests fail. This prevents webview-loadAbort events
-  // from being fired and unnecessary reloads.
-  class EulaLoader {
-    constructor(webview, timeout, load_offline_callback, clear_anchors) {
-      assert(webview.tagName === 'WEBVIEW');
-
-      // Do not create multiple loaders.
-      if (EulaLoader.instances[webview.id]) {
-        return EulaLoader.instances[webview.id];
-      }
-
-      this.webview_ = webview;
-      this.timeout_ = timeout;
-      this.isPerformingRequests_ = false;
-      this.reloadRequested_ = false;
-      this.loadOfflineCallback_ = load_offline_callback;
-      this.loadTimer_ = 0;
-      this.backOffTimer_ = 0;
-
-      if (clear_anchors) {
-        // Add the CLEAR_ANCHORS_CONTENT_SCRIPT that will clear <a><\a>
-        // (anchors) in order to prevent any navigation in the webview itself.
-        webview.addContentScripts([{
-          name: 'clearAnchors',
-          matches: ['<all_urls>'],
-          js: CLEAR_ANCHORS_CONTENT_SCRIPT,
-        }]);
-        webview.addEventListener('contentload', () => {
-          webview.executeScript(CLEAR_ANCHORS_CONTENT_SCRIPT);
-        });
-      }
-      webview.addEventListener('contentload', () => {
-        webview.insertCSS(EULA_FONTS_CSS);
-      });
-
-      // Monitor webRequests API events
-      this.webview_.request.onCompleted.addListener(
-          this.onCompleted_.bind(this),
-          {urls: ['<all_urls>'], types: ['main_frame']});
-      this.webview_.request.onErrorOccurred.addListener(
-          this.onErrorOccurred_.bind(this),
-          {urls: ['<all_urls>'], types: ['main_frame']});
-
-      // The only instance of the EulaLoader.
-      EulaLoader.instances[webview.id] = this;
-    }
-
-    // Clears the internal state of the EULA loader. Stops the timeout timer
-    // and prevents events from being handled.
-    clearInternalState() {
-      window.clearTimeout(this.loadTimer_);
-      window.clearTimeout(this.backOffTimer_);
-      this.isPerformingRequests_ = false;
-      this.reloadRequested_ = false;
-    }
-
-    // Sets an URL to be loaded in the webview. If the URL is different from the
-    // previous one, it will be immediately loaded. If the URL is the same as
-    // the previous one, it will be reloaded. If requests are under way, the
-    // reload will be performed once the current requests are finished.
-    setUrl(url) {
-      assert(/^https?:\/\//.test(url));
-
-      if (url != this.url_) {
-        // Clear the internal state and start with a new URL.
-        this.clearInternalState();
-        this.url_ = url;
-        this.loadWithFallbackTimer();
-      } else {
-        // Same URL was requested again. Reload later if a request is under way.
-        if (this.isPerformingRequests_)
-          this.reloadRequested_ = true;
-        else
-          this.loadWithFallbackTimer();
-      }
-    }
-
-    // This method only gets invoked if the webview webRequest API does not
-    // fire either 'onErrorOccurred' or 'onCompleted' before the timer runs out.
-    // See: https://developer.chrome.com/extensions/webRequest
-    onTimeoutError_() {
-      // Return if we are no longer monitoring requests. Sanity check.
-      if (!this.isPerformingRequests_)
-        return;
-
-      if (this.reloadRequested_)
-        this.loadWithFallbackTimer();
-      else
-        this.tryLoadOffline();
-    }
-
-    // Loads the offline version of the EULA.
-    tryLoadOffline() {
-      this.clearInternalState();
-      if (this.loadOfflineCallback_)
-        this.loadOfflineCallback_();
-    }
-
-    // Only process events for the current URL and when performing requests.
-    shouldProcessEvent(details) {
-      return this.isPerformingRequests_ && (details.url === this.url_);
-    }
-
-    // webRequest API Event Handler for 'onErrorOccurred'
-    onErrorOccurred_(details) {
-      if (!this.shouldProcessEvent(details))
-        return;
-
-      if (this.reloadRequested_)
-        this.loadWithFallbackTimer();
-      else
-        this.loadAfterBackoff();
-    }
-
-    // webRequest API Event Handler for 'onCompleted'
-    onCompleted_(details) {
-      if (!this.shouldProcessEvent(details))
-        return;
-
-      // Http errors such as 4xx, 5xx hit here instead of 'onErrorOccurred'.
-      if (details.statusCode != 200) {
-        // Not a successful request. Perform a reload if requested.
-        if (this.reloadRequested_)
-          this.loadWithFallbackTimer();
-        else
-          this.loadAfterBackoff();
-      } else {
-        // Success!
-        this.clearInternalState();
-      }
-    }
-
-    // Loads the URL into the webview and starts a timer.
-    loadWithFallbackTimer() {
-      // Clear previous timer and perform a load.
-      window.clearTimeout(this.loadTimer_);
-      this.loadTimer_ =
-          window.setTimeout(this.onTimeoutError_.bind(this), this.timeout_);
-      this.tryLoadOnline();
-    }
-
-    loadAfterBackoff() {
-      window.clearTimeout(this.backOffTimer_);
-      this.backOffTimer_ = window.setTimeout(
-          this.tryLoadOnline.bind(this),
-          ONLINE_EULA_RETRY_BACKOFF_TIMEOUT_IN_MS);
-    }
-
-    tryLoadOnline() {
-      this.reloadRequested_ = false;
-      // A request is being made
-      this.isPerformingRequests_ = true;
-      if (this.webview_.src === this.url_)
-        this.webview_.reload();
-      else
-        this.webview_.src = this.url_;
-    }
-  }
-  EulaLoader.instances = {};
-
-  return {
-    EXTERNAL_API: [
-      'setTpmPassword',
-      'setUsageStats',
-    ],
-
-    /** @override */
-    decorate() {
-      $('oobe-eula-md').screen = this;
-    },
-
-    /**
-     * Called from $('oobe-eula-md') onUsageChanged handler.
-     * @param {boolean} value $('usage-stats').checked value.
-     */
-    onUsageStatsClicked_(value) {
-      chrome.send('EulaScreen.usageStatsEnabled', [value]);
-    },
-
-    /**
-     * Event handler that is invoked just before the screen is shown.
-     * @param {object} data Screen init payload.
-     */
-    onBeforeShow() {
-      this.updateLocalizedContent();
-    },
-
-    /**
-     * Returns a control which should receive an initial focus.
-     */
-    get defaultControl() {
-      return $('oobe-eula-md');
-    },
-
-    enableKeyboardFlow() {},
-
-    /**
-     * Updates localized content of the screen that is not updated via template.
-     */
-    updateLocalizedContent() {
-      // Reload the terms contents.
-      $('oobe-eula-md').updateLocalizedContent();
-    },
-
-    /**
-     * Sets TPM password.
-     * @param {text} password TPM password to be shown.
-     */
-    setTpmPassword(password) {
-      $('oobe-eula-md').password = password;
-    },
-
-    /**
-     * Sets usage statistics checkbox.
-     * @param {boolean} checked Is the checkbox checked?
-     */
-    setUsageStats(checked) {
-      $('oobe-eula-md').usageStatsChecked = checked;
-    },
-
-    /**
-     * Load Eula into the given webview. Online version is attempted first with
-     * a timeout. If it fails to load, fallback to chrome://terms. The loaded
-     * terms contents is then set to the webview via data url. Webview is
-     * used as a sandbox for both online and local contents. Data url is
-     * used for chrome://terms so that webview never needs to have the
-     * privileged webui bindings.
-     *
-     * @param {!WebView} webview Webview element to host the terms.
-     * @param {!string} onlineEulaUrl
-     * @param {boolean} clear_anchors if true the script will clear anchors
-     *                                from the loaded page.
-     */
-    loadEulaToWebview_(webview, onlineEulaUrl, clear_anchors) {
-      assert(webview.tagName === 'WEBVIEW');
-
-      var loadBundledEula = function() {
-        WebViewHelper.loadUrlContentToWebView(
-            webview, TERMS_URL, WebViewHelper.ContentType.HTML);
-      };
-
-      // Load online Eula with a timeout to fallback to the offline version.
-      // This won't construct multiple EulaLoaders. Single instance.
-      var eulaLoader = new EulaLoader(
-          webview, ONLINE_EULA_LOAD_TIMEOUT_IN_MS, loadBundledEula,
-          clear_anchors);
-      eulaLoader.setUrl(onlineEulaUrl);
-    },
-
-    /**
-     * Called when focus is returned.
-     */
-    onFocusReturned() {
-      $('oobe-eula-md').focus();
-    },
-  };
-});
diff --git a/chrome/browser/resources/chromeos/login/structure/screens_oobe.html b/chrome/browser/resources/chromeos/login/structure/screens_oobe.html
index 8a3be0f9..d7899dc 100644
--- a/chrome/browser/resources/chromeos/login/structure/screens_oobe.html
+++ b/chrome/browser/resources/chromeos/login/structure/screens_oobe.html
@@ -13,7 +13,7 @@
 <include src="../oobe_screen_demo_setup.html">
 <oobe-network id="network-selection" class="step hidden" hidden>
 </oobe-network>
-<include src="../oobe_screen_eula.html">
+<oobe-eula-md id="oobe-eula-md" class="step hidden" hidden></oobe-eula-md>
 <oobe-update id="oobe-update" class="step hidden" hidden>
 </oobe-update>
 <include src="../oobe_screen_auto_enrollment_check.html">
diff --git a/chrome/browser/resources/chromeos/login/web_view_helper.js b/chrome/browser/resources/chromeos/login/web_view_helper.js
index 47336de..edda6338 100644
--- a/chrome/browser/resources/chromeos/login/web_view_helper.js
+++ b/chrome/browser/resources/chromeos/login/web_view_helper.js
@@ -13,9 +13,10 @@
    * The content is loaded via XHR and is sent to web view via data url so that
    * it is properly sandboxed.
    *
-   * @param {!WebView} webView web view element to host the content.
+   * @param {!Object} webView is a WebView element to host the content.
    * @param {string} url URL to load the content from.
-   * @param {!ContentType} contentType type of the content to load.
+   * @param {!WebViewHelper.ContentType} contentType type of the content to
+   *     load.
    */
   static loadUrlContentToWebView(webView, url, contentType) {
     assert(webView.tagName === 'WEBVIEW');
@@ -59,7 +60,8 @@
         onError();
         return;
       }
-      setContents(xhr.response);
+      let contents = /** @type {string} */ (xhr.response);
+      setContents(contents);
     };
 
     try {
@@ -79,4 +81,4 @@
   HTML: 'text/html',
   /** Base64 encoded application/pdf content type. */
   PDF: 'application/pdf',
-};
\ No newline at end of file
+};
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.html b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.html
index 6dd8bcf..37d953470 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.html
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.html
@@ -195,14 +195,18 @@
 
 <cr-action-menu force-dark-mode>
   <button id="single-page-view-button"
-      class="dropdown-item" on-click="onSinglePageViewClick_">
+      class="dropdown-item" on-click="onSinglePageViewClick_"
+      role="radio"
+      aria-checked="[[getSinglePageAriaChecked_(twoUpViewEnabled_)]]">
     <span class="check-container">
       <iron-icon icon="pdf:check" hidden="[[twoUpViewEnabled_]]"></iron-icon>
     </span>
     $i18n{twoUpViewDisable}
   </button>
   <button id="two-page-view-button"
-      class="dropdown-item" on-click="onTwoPageViewClick_">
+      class="dropdown-item" on-click="onTwoPageViewClick_"
+      role="radio"
+      aria-checked="[[getTwoPageViewAriaChecked_(twoUpViewEnabled_)]]">
     <span class="check-container">
       <iron-icon icon="pdf:check" hidden="[[!twoUpViewEnabled_]]"></iron-icon>
     </span>
@@ -210,7 +214,9 @@
   </button>
 
   <button id="show-annotations-button"
-      class="dropdown-item" on-click="toggleDisplayAnnotations_">
+      class="dropdown-item" on-click="toggleDisplayAnnotations_"
+      role="checkbox"
+      aria-checked="[[getShowAnnotationsAriaChecked_(displayAnnotations_)]]">
     <span class="check-container">
       <iron-icon icon="pdf:check" hidden="[[!displayAnnotations_]]"></iron-icon>
     </span>
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js
index e33c4e4..dc958c8 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar-new.js
@@ -181,6 +181,30 @@
     // </if>
   }
 
+  /**
+   * @param {boolean} checked
+   * @return {string}
+   */
+  getSinglePageAriaChecked_(checked) {
+    return checked ? 'false' : 'true';
+  }
+
+  /**
+   * @param {boolean} checked
+   * @return {string}
+   */
+  getTwoPageViewAriaChecked_(checked) {
+    return checked ? 'true' : 'false';
+  }
+
+  /**
+   * @param {boolean} checked
+   * @return {string}
+   */
+  getShowAnnotationsAriaChecked_(checked) {
+    return checked ? 'true' : 'false';
+  }
+
   /** @private */
   onSinglePageViewClick_() {
     this.twoUpViewEnabled_ = false;
diff --git a/chrome/browser/resources/signin/profile_picker/icons.js b/chrome/browser/resources/signin/profile_picker/icons.js
index 81d509c..3231955 100644
--- a/chrome/browser/resources/signin/profile_picker/icons.js
+++ b/chrome/browser/resources/signin/profile_picker/icons.js
@@ -1,8 +1,11 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
 import 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
 
 const element = document.createElement('iron-iconset-svg');
 element.name = 'profiles';
-element.size = 74;
 element.innerHTML = `
 <svg>
   <defs>
@@ -10,6 +13,10 @@
       <circle cx="37" cy="37" r="37" stroke="none"/>
       <path d="M36.9999 46.4349C36.1315 46.4349 35.4274 45.7309 35.4274 44.8624V38.5724H29.1374C28.269 38.5724 27.5649 37.8684 27.5649 36.9999C27.5649 36.1315 28.269 35.4274 29.1374 35.4274H35.4274V29.1374C35.4274 28.269 36.1315 27.5649 36.9999 27.5649C37.8684 27.5649 38.5724 28.269 38.5724 29.1374V35.4274H44.8624C45.7309 35.4274 46.4349 36.1315 46.4349 36.9999C46.4349 37.8684 45.7309 38.5724 44.8624 38.5724H38.5724V44.8624C38.5724 45.7309 37.8684 46.4349 36.9999 46.4349Z" fill="var(--iron-icon-stroke-color)"/>
     </g>
+
+    <g id="account-circle" viewBox="0 0 24 24" fill="var(--footer-text-color)" width="18px" height="18px">
+      <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/>
+    </g>
   </defs>
 </svg>`;
 document.head.appendChild(element);
diff --git a/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js b/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
index ad46615..9ae932f 100644
--- a/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
+++ b/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
@@ -37,6 +37,9 @@
    */
   launchSelectedProfile(profilePath) {}
 
+  /** Launches Guest profile. */
+  launchGuestProfile() {}
+
   /**
    * Inform native the user's choice on whether to show the profile picker
    * on startup or not.
@@ -68,6 +71,11 @@
   }
 
   /** @override */
+  launchGuestProfile() {
+    chrome.send('launchGuestProfile');
+  }
+
+  /** @override */
   askOnStartupChanged(shouldShow) {
     chrome.send('askOnStartupChanged', [shouldShow]);
   }
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
index 9ba2ea1..4b6134d 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
@@ -89,14 +89,6 @@
     --cr-icon-button-stroke-color: var(--google-grey-refresh-700);
   }
 
-  @media (prefers-color-scheme: dark) {
-    /* TODO(msalama): Dark mode mocks not ready yet.*/
-    cr-checkbox {
-      --cr-checkbox-label-color: var(--google-grey-refresh-500);
-      background-color: rgba(var(--md-background-color), .8);
-    }
-  }
-
   .footer {
     bottom: 0;
     display: flex;
@@ -105,14 +97,36 @@
     width: 100%;
   }
 
+  .footer > * {
+    background-color: rgba(255, 255, 255, .8);
+  }
+
+  #browseAsGuestButton {
+    margin-inline-start: 40px;
+  }
+
+  #browseAsGuestButton > iron-icon {
+    margin-inline-end: 8px;
+  }
+
   cr-checkbox {
     --cr-checkbox-label-color:  var(--google-grey-refresh-700);
     --cr-checkbox-label-padding-start: 8px;
-    background-color: rgba(255, 255, 255, .8);
     justify-content: flex-end;
     margin-inline-end: 40px;
     margin-inline-start: auto;
   }
+
+  @media (prefers-color-scheme: dark) {
+    /* TODO(msalama): Dark mode mocks not ready yet.*/
+    .footer > * {
+      background-color: rgba(0, 0, 0, .5);
+    }
+
+    cr-checkbox {
+      --cr-checkbox-label-color: var(--google-grey-refresh-500);
+    }
+  }
 </style>
 
 <div id="leftBanner" class="banner"></div>
@@ -139,6 +153,10 @@
 <div id="rightBanner" class="banner"></div>
 
 <div class="footer">
+  <cr-button id="browseAsGuestButton" on-click="onLaunchGuestProfileClick_">
+    <iron-icon icon="profiles:account-circle"></iron-icon>
+    <div>$i18n{browseAsGuestButton}</div>
+  </cr-button>
   <cr-checkbox checked="{{askOnStartup_}}"
       on-change="onAskOnStartupChangedByUser_">
     $i18n{askOnStartupCheckboxText}
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js
index a4e819f..4b2facb 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.js
@@ -92,4 +92,9 @@
   onAddProfileClick_() {
     navigateTo(Routes.NEW_PROFILE);
   },
+
+  /** @private */
+  onLaunchGuestProfileClick_() {
+    this.manageProfilesBrowserProxy_.launchGuestProfile();
+  },
 });
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 0fafb9b3..153db81e 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -6278,8 +6278,7 @@
   policy::PolicyMap policies;
   policies.Set(policy::key::kInsecureFormsWarningsEnabled,
                policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
-               policy::POLICY_SOURCE_CLOUD,
-               std::make_unique<base::Value>(false), nullptr);
+               policy::POLICY_SOURCE_CLOUD, base::Value(false), nullptr);
   UpdateProviderPolicy(policies);
   // Pref should now be set to false.
   EXPECT_FALSE(browser()->profile()->GetPrefs()->GetBoolean(
diff --git a/chrome/browser/ui/README.md b/chrome/browser/ui/README.md
index 2137f44..3cdb130 100644
--- a/chrome/browser/ui/README.md
+++ b/chrome/browser/ui/README.md
@@ -2,10 +2,13 @@
 of this directory is toolkit- and platform-independent. There are subdirectories
 with implementations for specific toolkits and OSes. Code in the root of this
 directory should *not* be aware of platform-specific implementation details or
-reach into the platform implementation subdirectories.
+reach into the platform implementation subdirectories. This directory also
+should not contain browser-process-scoped items that are not UI-specific, such
+as parts of the startup logic; these sorts of things belong elsewhere in
+chrome/browser/.
 
-This directory is often referred to in conversation as "cbui", pronounced "sea
-bee you eye".
+This directory is often referred to in conversation as "cbui" or "c/b/ui",
+pronounced "sea bee you eye".
 
 Important subdirectories:
 * views - the Views implementation of the UI, used on Windows, Mac, Linux, and
@@ -35,3 +38,8 @@
 
 //chrome/browser/ui/android/my_dialog_android.cc:  
     void ShowMyDialog(...) { ... }
+
+Because "Chromium UI" is such a large surface area, do not add new files
+directly to this directory; instead, add subdirectories with more specific
+OWNERS and place new features and files in them. Cleanup of existing scattered
+files is also welcome.
diff --git a/chrome/browser/ui/ash/assistant/assistant_state_client_unittest.cc b/chrome/browser/ui/ash/assistant/assistant_state_client_unittest.cc
index df81f80ae..9097a3e 100644
--- a/chrome/browser/ui/ash/assistant/assistant_state_client_unittest.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_state_client_unittest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/test/base/chrome_ash_test_base.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/test/fake_arc_session.h"
 #include "components/language/core/browser/pref_names.h"
@@ -30,9 +29,6 @@
   ~AssistantStateClientTest() override = default;
 
   void SetUp() override {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
     ChromeAshTestBase::SetUp();
 
     // Setup test profile.
@@ -61,7 +57,6 @@
     arc_session_manager_->Shutdown();
     arc_session_manager_.reset();
     ChromeAshTestBase::TearDown();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
   AssistantStateClient* assistant_state_client() {
diff --git a/chrome/browser/ui/ash/login_screen_client.cc b/chrome/browser/ui/ash/login_screen_client.cc
index 06892501..4629b2f 100644
--- a/chrome/browser/ui/ash/login_screen_client.cc
+++ b/chrome/browser/ui/ash/login_screen_client.cc
@@ -157,9 +157,19 @@
 }
 
 void LoginScreenClient::ShowGaiaSignin(const AccountId& prefilled_account) {
-  if (chromeos::LoginDisplayHost::default_host()) {
-    chromeos::LoginDisplayHost::default_host()->ShowGaiaDialog(
-        prefilled_account);
+  if (chromeos::parent_access::ParentAccessService::Get().IsApprovalRequired(
+          chromeos::parent_access::ParentAccessService::SupervisedAction::
+              kOnlineLogin)) {
+    // Show the client native parent access widget and processed to GAIA signin
+    // flow in |OnParentAccessValidation| when validation success.
+    ash::LoginScreen::Get()->ShowParentAccessWidget(
+        prefilled_account,
+        base::BindOnce(&LoginScreenClient::OnParentAccessValidation,
+                       weak_ptr_factory_.GetWeakPtr(), prefilled_account),
+        ash::ParentAccessRequestReason::kOnlineLogin, false /* extra_dimmer */,
+        base::Time::Now());
+  } else {
+    ShowGaiaSigninInternal(prefilled_account);
   }
 }
 
@@ -288,3 +298,18 @@
         ->ResetAutoLoginTimer();
   }
 }
+
+void LoginScreenClient::OnParentAccessValidation(
+    const AccountId& prefilled_account,
+    bool success) {
+  if (success)
+    ShowGaiaSigninInternal(prefilled_account);
+}
+
+void LoginScreenClient::ShowGaiaSigninInternal(
+    const AccountId& prefilled_account) {
+  if (chromeos::LoginDisplayHost::default_host()) {
+    chromeos::LoginDisplayHost::default_host()->ShowGaiaDialog(
+        prefilled_account);
+  }
+}
diff --git a/chrome/browser/ui/ash/login_screen_client.h b/chrome/browser/ui/ash/login_screen_client.h
index 7cd853d..8ead2a3 100644
--- a/chrome/browser/ui/ash/login_screen_client.h
+++ b/chrome/browser/ui/ash/login_screen_client.h
@@ -121,6 +121,13 @@
       const std::string& locale,
       std::unique_ptr<base::ListValue> keyboard_layouts);
 
+  void ShowGaiaSigninInternal(const AccountId& prefilled_account);
+
+  // Called when the parent access code was validated with result equals
+  // |success|.
+  void OnParentAccessValidation(const AccountId& prefilled_account,
+                                bool success);
+
   Delegate* delegate_ = nullptr;
 
   // Captures authentication related user metrics for login screen.
diff --git a/chrome/browser/ui/blocked_content/tab_under_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/tab_under_blocker_browsertest.cc
index 00df4ea..c0a65c94 100644
--- a/chrome/browser/ui/blocked_content/tab_under_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/tab_under_blocker_browsertest.cc
@@ -65,8 +65,7 @@
     policy::PolicyMap policy;
     policy.Set(policy::key::kDefaultPopupsSetting,
                policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
-               policy::POLICY_SOURCE_CLOUD,
-               std::make_unique<base::Value>(popup_setting),
+               policy::POLICY_SOURCE_CLOUD, base::Value(popup_setting),
                nullptr /* external_data_fetcher */);
     provider_.UpdateChromePolicy(policy);
   }
diff --git a/chrome/browser/ui/managed_ui_browsertest.cc b/chrome/browser/ui/managed_ui_browsertest.cc
index 0982201..5b2a80b5 100644
--- a/chrome/browser/ui/managed_ui_browsertest.cc
+++ b/chrome/browser/ui/managed_ui_browsertest.cc
@@ -43,7 +43,7 @@
   policy::PolicyMap policy_map;
   policy_map.Set("test-policy", policy::POLICY_LEVEL_MANDATORY,
                  policy::POLICY_SCOPE_MACHINE, policy::POLICY_SOURCE_PLATFORM,
-                 std::make_unique<base::Value>("hello world"), nullptr);
+                 base::Value("hello world"), nullptr);
   provider()->UpdateChromePolicy(policy_map);
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index e1623447..73eb5ccc 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -887,7 +887,7 @@
   policy::PolicyMap policies;
   policies.Set("DefaultSearchProviderEnabled", policy::POLICY_LEVEL_MANDATORY,
                policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_PLATFORM,
-               std::make_unique<base::Value>(false), nullptr);
+               base::Value(false), nullptr);
   policy_provider()->UpdateChromePolicy(policies);
   base::RunLoop().RunUntilIdle();
 
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index d09a67a..4e9553003 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -1528,9 +1528,8 @@
   policy_map_.Set(policy::key::kRestoreOnStartup,
                   policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_MACHINE,
                   policy::POLICY_SOURCE_CLOUD, base::Value(4), nullptr);
-  auto url_list = std::make_unique<base::Value>(base::Value::Type::LIST);
-  url_list->Append(
-      base::Value(embedded_test_server()->GetURL("/title1.html").spec()));
+  base::Value url_list(base::Value::Type::LIST);
+  url_list.Append(embedded_test_server()->GetURL("/title1.html").spec());
   policy_map_.Set(policy::key::kRestoreOnStartupURLs,
                   policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_MACHINE,
                   policy::POLICY_SOURCE_CLOUD, std::move(url_list), nullptr);
diff --git a/chrome/browser/ui/startup/startup_browser_policy_unittest.cc b/chrome/browser/ui/startup/startup_browser_policy_unittest.cc
index e5d3393..7540cfd9 100644
--- a/chrome/browser/ui/startup/startup_browser_policy_unittest.cc
+++ b/chrome/browser/ui/startup/startup_browser_policy_unittest.cc
@@ -99,7 +99,7 @@
                  Args... args) {
     policy_map.Set(policy, policy::POLICY_LEVEL_MANDATORY,
                    policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
-                   std::make_unique<base::Value>(args...), nullptr);
+                   base::Value(args...), nullptr);
   }
 
   template <typename... Args>
diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc
index e3b52d5..6623827 100644
--- a/chrome/browser/ui/views/collected_cookies_views.cc
+++ b/chrome/browser/ui/views/collected_cookies_views.cc
@@ -280,20 +280,6 @@
   return l10n_util::GetStringUTF16(IDS_COLLECTED_COOKIES_DIALOG_TITLE);
 }
 
-bool CollectedCookiesViews::Accept() {
-  // If the user closes our parent tab while we're still open, this method will
-  // (eventually) be called in response to a WebContentsDestroyed() call from
-  // the WebContentsImpl to its observers.  But since the InfoBarService is also
-  // torn down in response to WebContentsDestroyed(), it may already be null.
-  // Since the tab is going away anyway, we can just omit showing an infobar,
-  // which prevents any attempt to access a null InfoBarService.
-  if (status_changed_ && !web_contents_->IsBeingDestroyed()) {
-    CollectedCookiesInfoBarDelegate::Create(
-        InfoBarService::FromWebContents(web_contents_));
-  }
-  return true;
-}
-
 ui::ModalType CollectedCookiesViews::GetModalType() const {
   return ui::MODAL_TYPE_CHILD;
 }
@@ -367,6 +353,11 @@
       SetLayoutManager(std::make_unique<views::GridLayout>());
   ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
 
+  SetAcceptCallback(base::BindOnce(&CollectedCookiesViews::OnDialogClosed,
+                                   base::Unretained(this)));
+  SetCloseCallback(base::BindOnce(&CollectedCookiesViews::OnDialogClosed,
+                                  base::Unretained(this)));
+
   // Add margin above the content. The left, right, and bottom margins are added
   // by the content itself.
   SetBorder(views::CreateEmptyBorder(
@@ -414,6 +405,19 @@
   ShowCookieInfo();
 }
 
+void CollectedCookiesViews::OnDialogClosed() {
+  // If the user closes our parent tab while we're still open, this method will
+  // (eventually) be called in response to a WebContentsDestroyed() call from
+  // the WebContentsImpl to its observers.  But since the InfoBarService is also
+  // torn down in response to WebContentsDestroyed(), it may already be null.
+  // Since the tab is going away anyway, we can just omit showing an infobar,
+  // which prevents any attempt to access a null InfoBarService.
+  if (status_changed_ && !web_contents_->IsBeingDestroyed()) {
+    CollectedCookiesInfoBarDelegate::Create(
+        InfoBarService::FromWebContents(web_contents_));
+  }
+}
+
 std::unique_ptr<views::View> CollectedCookiesViews::CreateAllowedPane() {
   // This captures a snapshot of the allowed cookies of the current page so we
   // are fine using WebContents::GetMainFrame() here
diff --git a/chrome/browser/ui/views/collected_cookies_views.h b/chrome/browser/ui/views/collected_cookies_views.h
index 5ade35b..0c22ac141 100644
--- a/chrome/browser/ui/views/collected_cookies_views.h
+++ b/chrome/browser/ui/views/collected_cookies_views.h
@@ -51,7 +51,6 @@
 
   // views::DialogDelegate:
   base::string16 GetWindowTitle() const override;
-  bool Accept() override;
   ui::ModalType GetModalType() const override;
   bool ShouldShowCloseButton() const override;
   void DeleteDelegate() override;
@@ -74,8 +73,9 @@
 
   explicit CollectedCookiesViews(content::WebContents* web_contents);
 
-  std::unique_ptr<views::View> CreateAllowedPane();
+  void OnDialogClosed();
 
+  std::unique_ptr<views::View> CreateAllowedPane();
   std::unique_ptr<views::View> CreateBlockedPane();
 
   // Creates and returns the "buttons pane", which is the view in the
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 8085a8ca..fbfda14 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -268,7 +268,10 @@
     return;
   }
 
-  if (old_selection.line != OmniboxPopupModel::kNoMatch) {
+  // Do not invalidate the same line twice, in order to avoid redundant
+  // accessibility events.
+  if (old_selection.line != OmniboxPopupModel::kNoMatch &&
+      old_selection.line != new_selection.line) {
     InvalidateLine(old_selection.line);
   }
 
@@ -465,10 +468,15 @@
 
 void OmniboxPopupContentsView::FireAXEventsForNewActiveDescendant(
     View* descendant_view) {
-  if (descendant_view)
+  if (descendant_view) {
     descendant_view->NotifyAccessibilityEvent(ax::mojom::Event::kSelection,
                                               true);
-  NotifyAccessibilityEvent(ax::mojom::Event::kActiveDescendantChanged, true);
+  }
+  // Selected children changed is fired on the popup.
+  NotifyAccessibilityEvent(ax::mojom::Event::kSelectedChildrenChanged, true);
+  // Active descendant changed is fired on the focused text field.
+  omnibox_view_->NotifyAccessibilityEvent(
+      ax::mojom::Event::kActiveDescendantChanged, true);
 }
 
 void OmniboxPopupContentsView::OnWidgetBoundsChanged(
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc
index 6fc7098..4161111 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view_browsertest.cc
@@ -40,6 +40,10 @@
 
 namespace {
 
+bool contains(std::string str, std::string substr) {
+  return str.find(substr) != std::string::npos;
+}
+
 // A View that positions itself over another View to intercept clicks.
 class ClickTrackingOverlayView : public views::View {
  public:
@@ -98,13 +102,27 @@
       return;
     ui::AXNodeData node_data;
     view->GetAccessibleNodeData(&node_data);
+    ax::mojom::Role role = node_data.role;
     if (event_type == ax::mojom::Event::kTextChanged &&
-        node_data.role == ax::mojom::Role::kListBoxOption)
+        role == ax::mojom::Role::kListBoxOption) {
       text_changed_on_listboxoption_count_++;
-    else if (event_type == ax::mojom::Event::kSelectedChildrenChanged)
+    } else if (event_type == ax::mojom::Event::kSelectedChildrenChanged &&
+               role == ax::mojom::Role::kListBox) {
       selected_children_changed_count_++;
-    else if (event_type == ax::mojom::Event::kActiveDescendantChanged)
+    } else if (event_type == ax::mojom::Event::kSelection &&
+               role == ax::mojom::Role::kListBoxOption) {
+      selection_changed_count_++;
+      selected_option_name_ =
+          node_data.GetStringAttribute(ax::mojom::StringAttribute::kName);
+    } else if (event_type == ax::mojom::Event::kValueChanged &&
+               role == ax::mojom::Role::kTextField) {
+      value_changed_count_++;
+      omnibox_value_ =
+          node_data.GetStringAttribute(ax::mojom::StringAttribute::kValue);
+    } else if (event_type == ax::mojom::Event::kActiveDescendantChanged &&
+               role == ax::mojom::Role::kTextField) {
       active_descendant_changed_count_++;
+    }
   }
 
   int text_changed_on_listboxoption_count() {
@@ -113,14 +131,23 @@
   int selected_children_changed_count() {
     return selected_children_changed_count_;
   }
+  int selection_changed_count() { return selection_changed_count_; }
+  int value_changed_count() { return value_changed_count_; }
   int active_descendant_changed_count() {
     return active_descendant_changed_count_;
   }
 
+  std::string omnibox_value() { return omnibox_value_; }
+  std::string selected_option_name() { return selected_option_name_; }
+
  private:
   int text_changed_on_listboxoption_count_ = 0;
   int selected_children_changed_count_ = 0;
+  int selection_changed_count_ = 0;
+  int value_changed_count_ = 0;
   int active_descendant_changed_count_ = 0;
+  std::string omnibox_value_;
+  std::string selected_option_name_;
 
   DISALLOW_COPY_AND_ASSIGN(TestAXEventObserver);
 };
@@ -365,8 +392,7 @@
   EXPECT_EQ(color_before_focus, omnibox_view()->GetBackgroundColor());
 }
 
-IN_PROC_BROWSER_TEST_F(OmniboxPopupContentsViewTest,
-                       EmitTextChangedAccessibilityEvent) {
+IN_PROC_BROWSER_TEST_F(OmniboxPopupContentsViewTest, EmitAccessibilityEvents) {
   // Creation and population of the popup should not result in a text/name
   // change accessibility event.
   TestAXEventObserver observer;
@@ -376,8 +402,10 @@
                           AutocompleteMatchType::HISTORY_TITLE);
   AutocompleteController* controller = popup_model()->autocomplete_controller();
   match.contents = base::ASCIIToUTF16("https://foobar.com");
+  match.description = base::ASCIIToUTF16("FooBarCom");
   matches.push_back(match);
   match.contents = base::ASCIIToUTF16("https://foobarbaz.com");
+  match.description = base::ASCIIToUTF16("FooBarBazCom");
   matches.push_back(match);
   controller->result_.AppendMatches(controller->input_, matches);
   popup_view()->UpdatePopupAppearance();
@@ -389,15 +417,96 @@
   edit_model()->StartAutocomplete(false, false);
   popup_view()->UpdatePopupAppearance();
   EXPECT_EQ(observer.text_changed_on_listboxoption_count(), 0);
+  EXPECT_EQ(observer.selected_children_changed_count(), 1);
+  EXPECT_EQ(observer.selection_changed_count(), 1);
+  EXPECT_EQ(observer.active_descendant_changed_count(), 1);
+  EXPECT_EQ(observer.value_changed_count(), 2);
 
   // Each time the selection changes, we should have a text/name change event.
   // This makes it possible for screen readers to have the updated match content
   // when they are notified the selection changed.
   popup_view()->model()->SetSelection(OmniboxPopupModel::Selection(1));
   EXPECT_EQ(observer.text_changed_on_listboxoption_count(), 1);
+  EXPECT_EQ(observer.selected_children_changed_count(), 2);
+  EXPECT_EQ(observer.selection_changed_count(), 2);
+  EXPECT_EQ(observer.active_descendant_changed_count(), 2);
+  EXPECT_EQ(observer.value_changed_count(), 3);
+  EXPECT_TRUE(contains(observer.omnibox_value(), "2 of 3"));
+  EXPECT_FALSE(contains(observer.selected_option_name(), "2 of 3"));
+  EXPECT_TRUE(contains(observer.selected_option_name(), "foobar.com"));
+  EXPECT_TRUE(contains(observer.omnibox_value(), "FooBarCom"));
+  EXPECT_TRUE(contains(observer.selected_option_name(), "FooBarCom"));
+  EXPECT_TRUE(contains(observer.omnibox_value(), "location from history"));
+  EXPECT_TRUE(
+      contains(observer.selected_option_name(), "location from history"));
 
   popup_view()->model()->SetSelection(OmniboxPopupModel::Selection(2));
   EXPECT_EQ(observer.text_changed_on_listboxoption_count(), 2);
+  EXPECT_EQ(observer.selected_children_changed_count(), 3);
+  EXPECT_EQ(observer.selection_changed_count(), 3);
+  EXPECT_EQ(observer.active_descendant_changed_count(), 3);
+  EXPECT_EQ(observer.value_changed_count(), 4);
+  EXPECT_TRUE(contains(observer.omnibox_value(), "3 of 3"));
+  EXPECT_FALSE(contains(observer.selected_option_name(), "3 of 3"));
+  EXPECT_TRUE(contains(observer.selected_option_name(), "foobarbaz.com"));
+  EXPECT_TRUE(contains(observer.omnibox_value(), "FooBarBazCom"));
+  EXPECT_TRUE(contains(observer.selected_option_name(), "FooBarBazCom"));
+}
+
+IN_PROC_BROWSER_TEST_F(OmniboxPopupContentsViewTest,
+                       EmitAccessibilityEventsOnButtonFocusHint) {
+  TestAXEventObserver observer;
+  CreatePopupForTestQuery();
+  ACMatches matches;
+  AutocompleteMatch match(nullptr, 500, false,
+                          AutocompleteMatchType::HISTORY_TITLE);
+  AutocompleteController* controller = popup_model()->autocomplete_controller();
+  match.contents = base::ASCIIToUTF16("https://foobar.com");
+  match.description = base::ASCIIToUTF16("The Foo Of All Bars");
+  match.has_tab_match = true;
+  matches.push_back(match);
+  controller->result_.AppendMatches(controller->input_, matches);
+  popup_view()->UpdatePopupAppearance();
+
+  popup_view()->model()->SetSelection(OmniboxPopupModel::Selection(1));
+  EXPECT_EQ(observer.selected_children_changed_count(), 2);
+  EXPECT_EQ(observer.selection_changed_count(), 2);
+  EXPECT_EQ(observer.active_descendant_changed_count(), 2);
+  EXPECT_EQ(observer.value_changed_count(), 2);
+  EXPECT_TRUE(contains(observer.omnibox_value(), "The Foo Of All Bars"));
+  EXPECT_TRUE(contains(observer.selected_option_name(), "foobar.com"));
+  EXPECT_TRUE(contains(observer.omnibox_value(), "press Tab then Enter"));
+  EXPECT_TRUE(contains(observer.omnibox_value(), "2 of 2"));
+  EXPECT_TRUE(
+      contains(observer.selected_option_name(), "press Tab then Enter"));
+  EXPECT_FALSE(contains(observer.selected_option_name(), "2 of 2"));
+
+  popup_view()->model()->SetSelection(OmniboxPopupModel::Selection(
+      1, OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH));
+  EXPECT_TRUE(contains(observer.omnibox_value(), "The Foo Of All Bars"));
+  EXPECT_EQ(observer.selected_children_changed_count(), 3);
+  EXPECT_EQ(observer.selection_changed_count(), 3);
+  EXPECT_EQ(observer.active_descendant_changed_count(), 3);
+  EXPECT_EQ(observer.value_changed_count(), 3);
+  EXPECT_TRUE(contains(observer.omnibox_value(), "press Enter to switch"));
+  EXPECT_FALSE(contains(observer.omnibox_value(), "2 of 2"));
+  EXPECT_TRUE(
+      contains(observer.selected_option_name(), "press Enter to switch"));
+  EXPECT_FALSE(contains(observer.selected_option_name(), "2 of 2"));
+
+  popup_view()->model()->SetSelection(
+      OmniboxPopupModel::Selection(1, OmniboxPopupModel::NORMAL));
+  EXPECT_TRUE(contains(observer.omnibox_value(), "The Foo Of All Bars"));
+  EXPECT_TRUE(contains(observer.selected_option_name(), "foobar.com"));
+  EXPECT_EQ(observer.selected_children_changed_count(), 4);
+  EXPECT_EQ(observer.selection_changed_count(), 4);
+  EXPECT_EQ(observer.active_descendant_changed_count(), 4);
+  EXPECT_EQ(observer.value_changed_count(), 4);
+  EXPECT_TRUE(contains(observer.omnibox_value(), "press Tab then Enter"));
+  EXPECT_TRUE(contains(observer.omnibox_value(), "2 of 2"));
+  EXPECT_TRUE(
+      contains(observer.selected_option_name(), "press Tab then Enter"));
+  EXPECT_FALSE(contains(observer.selected_option_name(), "2 of 2"));
 }
 
 IN_PROC_BROWSER_TEST_F(OmniboxPopupContentsViewTest,
@@ -434,16 +543,22 @@
   // Lets check that arrowing up and down emits the event.
   TestAXEventObserver observer;
   EXPECT_EQ(observer.selected_children_changed_count(), 0);
+  EXPECT_EQ(observer.selection_changed_count(), 0);
+  EXPECT_EQ(observer.value_changed_count(), 0);
   EXPECT_EQ(observer.active_descendant_changed_count(), 0);
 
   // This is equiverlent of the user arrowing down in the omnibox.
   popup_view()->model()->SetSelection(OmniboxPopupModel::Selection(1));
   EXPECT_EQ(observer.selected_children_changed_count(), 1);
+  EXPECT_EQ(observer.selection_changed_count(), 1);
+  EXPECT_EQ(observer.value_changed_count(), 1);
   EXPECT_EQ(observer.active_descendant_changed_count(), 1);
 
   // This is equivalent of the user arrowing up in the omnibox.
   popup_view()->model()->SetSelection(OmniboxPopupModel::Selection(0));
   EXPECT_EQ(observer.selected_children_changed_count(), 2);
+  EXPECT_EQ(observer.selection_changed_count(), 2);
+  EXPECT_EQ(observer.value_changed_count(), 2);
   EXPECT_EQ(observer.active_descendant_changed_count(), 2);
 
   // TODO(accessibility) Test that closing the popup fires an activedescendant
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index ccf243a..546ff0d0 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -230,18 +230,23 @@
     // any cached values get updated prior to the selection change.
     EmitTextChangedAccessiblityEvent();
 
-    // Send accessibility event on the popup box that its selection has changed.
-    EmitSelectedChildrenChangedAccessibilityEvent();
+    auto selection_state = popup_contents_view_->model()->selection().state;
 
     // The text is also accessible via text/value change events in the omnibox
     // but this selection event allows the screen reader to get more details
     // about the list and the user's position within it.
-    popup_contents_view_->FireAXEventsForNewActiveDescendant(this);
+    // Limit which selection states fire the events, in order to avoid duplicate
+    // events. Specifically, OmniboxPopupContentsView::ProvideButtonFocusHint()
+    // already fires the correct events when the user tabs to an attached button
+    // in the current row.
+    if (selection_state == OmniboxPopupModel::FOCUSED_BUTTON_HEADER ||
+        selection_state == OmniboxPopupModel::NORMAL) {
+      popup_contents_view_->FireAXEventsForNewActiveDescendant(this);
+    }
 
     // TODO(orinj): Eventually the deep digging in this class should get
     //  replaced with a single local point of access to all selection state.
-    ShowKeyword(popup_contents_view_->model()->selection().state ==
-                OmniboxPopupModel::KEYWORD_MODE);
+    ShowKeyword(selection_state == OmniboxPopupModel::KEYWORD_MODE);
   } else {
     ShowKeyword(false);
   }
@@ -442,21 +447,27 @@
   // TODO(tommycli): We re-fetch the original match from the popup model,
   // because |match_| already has its contents and description swapped by this
   // class, and we don't want that for the bubble. We should improve this.
-  if (model_index_ < popup_contents_view_->model()->result().size()) {
-    AutocompleteMatch raw_match =
-        popup_contents_view_->model()->result().match_at(model_index_);
-    node_data->SetName(AutocompleteMatchType::ToAccessibilityLabel(
-        raw_match, raw_match.contents));
+  bool is_selected = IsMatchSelected();
+  OmniboxPopupModel* model = popup_contents_view_->model();
+  if (model_index_ < model->result().size()) {
+    AutocompleteMatch raw_match = model->result().match_at(model_index_);
+    // The selected match can have a special name, e.g. when is one or more
+    // buttons that can be tabbed to.
+    base::string16 label =
+        is_selected ? model->GetAccessibilityLabelForCurrentSelection(
+                          raw_match.contents, false)
+                    : AutocompleteMatchType::ToAccessibilityLabel(
+                          raw_match, raw_match.contents);
+    node_data->SetName(label);
   }
 
   node_data->role = ax::mojom::Role::kListBoxOption;
   node_data->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet,
                              model_index_ + 1);
   node_data->AddIntAttribute(ax::mojom::IntAttribute::kSetSize,
-                             popup_contents_view_->model()->result().size());
+                             model->result().size());
 
-  node_data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
-                              IsMatchSelected());
+  node_data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected, is_selected);
   if (IsMouseHovered())
     node_data->AddState(ax::mojom::State::kHovered);
 }
@@ -489,19 +500,16 @@
   // The omnibox results list reuses the same items, but the text displayed for
   // these items is updated as the value of omnibox changes. The displayed text
   // for a given item is exposed to screen readers as the item's name/label.
+  ui::AXNodeData node_data;
+  GetAccessibleNodeData(&node_data);
   base::string16 current_name =
-      AutocompleteMatchType::ToAccessibilityLabel(match_, match_.contents);
+      node_data.GetString16Attribute(ax::mojom::StringAttribute::kName);
   if (accessible_name_ != current_name) {
     NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
     accessible_name_ = current_name;
   }
 }
 
-void OmniboxResultView::EmitSelectedChildrenChangedAccessibilityEvent() {
-  popup_contents_view_->NotifyAccessibilityEvent(
-      ax::mojom::Event::kSelectedChildrenChanged, true);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // OmniboxResultView, private:
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.h b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
index 5458d56..7f3dad4 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
@@ -92,7 +92,6 @@
 
   // Helper to emit accessibility events (may only emit if conditions are met).
   void EmitTextChangedAccessiblityEvent();
-  void EmitSelectedChildrenChangedAccessibilityEvent();
 
   // views::View:
   void Layout() override;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc
index 99ed55ab..e628a3c 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc
@@ -29,10 +29,21 @@
 class OmniboxSuggestionRowButton : public views::MdTextButton {
  public:
   OmniboxSuggestionRowButton(views::ButtonListener* listener,
-                             const base::string16& text)
-      : MdTextButton(listener, CONTEXT_OMNIBOX_PRIMARY) {
+                             const base::string16& text,
+                             const gfx::VectorIcon& icon,
+                             const views::FocusRing::ViewPredicate& predicate)
+      : MdTextButton(listener, CONTEXT_OMNIBOX_PRIMARY), icon_(icon) {
     SetText(text);
+    views::InstallPillHighlightPathGenerator(this);
+    SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
+        DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
+    SetCustomPadding(ChromeLayoutProvider::Get()->GetInsetsMetric(
+        INSETS_OMNIBOX_PILL_BUTTON));
+    SetCornerRadius(GetInsets().height() +
+                    GetLayoutConstant(LOCATION_BAR_ICON_SIZE));
+
     set_ink_drop_highlight_opacity(CalculateInkDropHighlightOpacity());
+    focus_ring()->SetHasFocusPredicate(predicate);
   }
 
   OmniboxSuggestionRowButton(const OmniboxSuggestionRowButton&) = delete;
@@ -45,6 +56,8 @@
     return color_utils::GetColorWithMaxContrast(background()->get_color());
   }
 
+  void OnStyleRefresh() { focus_ring()->SchedulePaint(); }
+
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override {
     // MdTextButton uses custom colors when creating ink drop highlight.
@@ -53,7 +66,19 @@
     return views::InkDropHostView::CreateInkDropHighlight();
   }
 
+  void OnThemeChanged() override {
+    MdTextButton::OnThemeChanged();
+    SkColor color =
+        GetOmniboxColor(GetThemeProvider(), OmniboxPart::RESULTS_ICON,
+                        OmniboxPartState::NORMAL);
+    SetImage(views::Button::STATE_NORMAL,
+             gfx::CreateVectorIcon(
+                 icon_, GetLayoutConstant(LOCATION_BAR_ICON_SIZE), color));
+  }
+
  private:
+  const gfx::VectorIcon& icon_;
+
   float CalculateInkDropHighlightOpacity() {
     // Ink drop highlight opacity is result of mixing a layer with hovered
     // opacity and a layer with selected opacity. OmniboxPartState::SELECTED
@@ -70,19 +95,13 @@
 
 OmniboxSuggestionRowButton* CreatePillButton(
     OmniboxSuggestionButtonRowView* button_row,
-    const char* message) {
+    const char* message,
+    const gfx::VectorIcon& icon,
+    const views::FocusRing::ViewPredicate& predicate) {
   OmniboxSuggestionRowButton* button =
       button_row->AddChildView(std::make_unique<OmniboxSuggestionRowButton>(
-          button_row, base::ASCIIToUTF16(message)));
+          button_row, base::ASCIIToUTF16(message), icon, predicate));
   button->SetVisible(false);
-  button->SetImageLabelSpacing(ChromeLayoutProvider::Get()->GetDistanceMetric(
-      DISTANCE_RELATED_LABEL_HORIZONTAL_LIST));
-  button->SetCustomPadding(
-      ChromeLayoutProvider::Get()->GetInsetsMetric(INSETS_OMNIBOX_PILL_BUTTON));
-  button->SetCornerRadius(button->GetInsets().height() +
-                          GetLayoutConstant(LOCATION_BAR_ICON_SIZE));
-  views::HighlightPathGenerator::Install(
-      button, std::make_unique<views::PillHighlightPathGenerator>());
   return button;
 }
 
@@ -105,11 +124,6 @@
           gfx::Insets(0, ChromeLayoutProvider::Get()->GetDistanceMetric(
                              views::DISTANCE_RELATED_BUTTON_HORIZONTAL)));
 
-  // TODO(orinj): Use the real translated string table values here instead.
-  keyword_button_ = CreatePillButton(this, "Keyword search");
-  pedal_button_ = CreatePillButton(this, "Pedal");
-  tab_switch_button_ = CreatePillButton(this, "Switch to this tab");
-
   const auto make_predicate = [=](auto state) {
     return [=](View* view) {
       return view->GetVisible() &&
@@ -117,14 +131,16 @@
                  OmniboxPopupModel::Selection(model_index_, state);
     };
   };
-  keyword_button_focus_ring_ = views::FocusRing::Install(keyword_button_);
-  keyword_button_focus_ring_->SetHasFocusPredicate(
+
+  // TODO(orinj): Use the real translated string table values here instead.
+  keyword_button_ = CreatePillButton(
+      this, "Keyword search", vector_icons::kSearchIcon,
       make_predicate(OmniboxPopupModel::FOCUSED_BUTTON_KEYWORD));
-  pedal_button_focus_ring_ = views::FocusRing::Install(pedal_button_);
-  pedal_button_focus_ring_->SetHasFocusPredicate(
-      make_predicate(OmniboxPopupModel::FOCUSED_BUTTON_PEDAL));
-  tab_switch_button_focus_ring_ = views::FocusRing::Install(tab_switch_button_);
-  tab_switch_button_focus_ring_->SetHasFocusPredicate(
+  pedal_button_ =
+      CreatePillButton(this, "Pedal", omnibox::kProductIcon,
+                       make_predicate(OmniboxPopupModel::FOCUSED_BUTTON_PEDAL));
+  tab_switch_button_ = CreatePillButton(
+      this, "Switch to this tab", omnibox::kSwitchIcon,
       make_predicate(OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH));
 }
 
@@ -163,26 +179,9 @@
 }
 
 void OmniboxSuggestionButtonRowView::OnStyleRefresh() {
-  keyword_button_focus_ring_->SchedulePaint();
-  pedal_button_focus_ring_->SchedulePaint();
-  tab_switch_button_focus_ring_->SchedulePaint();
-}
-
-void OmniboxSuggestionButtonRowView::OnThemeChanged() {
-  View::OnThemeChanged();
-  SkColor color = GetOmniboxColor(GetThemeProvider(), OmniboxPart::RESULTS_ICON,
-                                  OmniboxPartState::NORMAL);
-  const int icon_size = GetLayoutConstant(LOCATION_BAR_ICON_SIZE);
-
-  keyword_button_->SetImage(
-      views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(vector_icons::kSearchIcon, icon_size, color));
-  pedal_button_->SetImage(
-      views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(omnibox::kProductIcon, icon_size, color));
-  tab_switch_button_->SetImage(
-      views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(omnibox::kSwitchIcon, icon_size, color));
+  keyword_button_->OnStyleRefresh();
+  pedal_button_->OnStyleRefresh();
+  tab_switch_button_->OnStyleRefresh();
 }
 
 void OmniboxSuggestionButtonRowView::ButtonPressed(views::Button* button,
@@ -229,7 +228,7 @@
 }
 
 void OmniboxSuggestionButtonRowView::SetPillButtonVisibility(
-    views::MdTextButton* button,
+    OmniboxSuggestionRowButton* button,
     OmniboxPopupModel::LineState state) {
   button->SetVisible(model()->IsControlPresentOnMatch(
       OmniboxPopupModel::Selection(model_index_, state)));
diff --git a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.h b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.h
index 7cf4c5d..0604377 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.h
@@ -32,9 +32,6 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
-  // views::View:
-  void OnThemeChanged() override;
-
  private:
   // Get the popup model from the view.
   const OmniboxPopupModel* model() const;
@@ -42,7 +39,7 @@
   // Digs into the model with index to get the match for owning result view.
   const AutocompleteMatch& match() const;
 
-  void SetPillButtonVisibility(views::MdTextButton* button,
+  void SetPillButtonVisibility(OmniboxSuggestionRowButton* button,
                                OmniboxPopupModel::LineState state);
 
   OmniboxPopupContentsView* const popup_contents_view_;
@@ -51,9 +48,6 @@
   OmniboxSuggestionRowButton* keyword_button_ = nullptr;
   OmniboxSuggestionRowButton* pedal_button_ = nullptr;
   OmniboxSuggestionRowButton* tab_switch_button_ = nullptr;
-  views::FocusRing* keyword_button_focus_ring_ = nullptr;
-  views::FocusRing* pedal_button_focus_ring_ = nullptr;
-  views::FocusRing* tab_switch_button_focus_ring_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(OmniboxSuggestionButtonRowView);
 };
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 0deb0d7d..b675d14 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -10,6 +10,7 @@
 #include "base/check_op.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
+#include "base/i18n/rtl.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "base/task/post_task.h"
@@ -225,11 +226,20 @@
   elide_to_rect_.set_y(elide_from_rect_.y());
   elide_to_rect_.set_height(elide_from_rect_.height());
 
+  // There is nothing to animate in this case, so return without starting.
+  if (elide_from_rect_ == elide_to_rect_ && starting_color_ == ending_color_)
+    return;
+
   starting_display_offset_ = render_text_->GetUpdatedDisplayOffset().x();
   // Shift the text to where |elide_to_bounds| starts, relative to the current
   // display rect.
-  ending_display_offset_ =
-      starting_display_offset_ - (elide_to_rect_.x() - elide_from_rect_.x());
+  if (base::i18n::IsRTL()) {
+    ending_display_offset_ = starting_display_offset_ +
+                             elide_from_rect_.right() - elide_to_rect_.right();
+  } else {
+    ending_display_offset_ =
+        starting_display_offset_ - (elide_to_rect_.x() - elide_from_rect_.x());
+  }
 
   animation_->Start();
 }
@@ -278,8 +288,10 @@
       animation->GetCurrentValue(), elide_from_rect_, elide_to_rect_);
   DCHECK_EQ(bounds.y(), old_bounds.y());
   DCHECK_EQ(bounds.height(), old_bounds.height());
-  gfx::Rect shifted_bounds(old_bounds.x(), old_bounds.y(), bounds.width(),
-                           old_bounds.height());
+  gfx::Rect shifted_bounds(base::i18n::IsRTL()
+                               ? old_bounds.right() - bounds.width()
+                               : old_bounds.x(),
+                           old_bounds.y(), bounds.width(), old_bounds.height());
   render_text_->SetDisplayRect(shifted_bounds);
   current_offset_ = gfx::Tween::IntValueBetween(animation->GetCurrentValue(),
                                                 starting_display_offset_,
@@ -290,6 +302,13 @@
     view_->ApplyColor(GetCurrentColor(), range);
   }
 
+  // TODO(crbug.com/1101472): The smoothing gradient mask is not yet implemented
+  // correctly for RTL UI.
+  if (base::i18n::IsRTL()) {
+    view_->SchedulePaint();
+    return;
+  }
+
   // The gradient mask should be a fixed width, except if that width would
   // cause it to mask the unelided section. In that case we set it to the
   // maximum width possible that won't cover the unelided section.
@@ -916,7 +935,11 @@
     bool notify_text_changed) {
   if (save_original_selection)
     saved_temporary_selection_ = GetRenderText()->GetAllSelections();
-  SetAccessibilityLabel(display_text, match);
+
+  // SetWindowTextAndCaretPos will fire the acesssibility notification,
+  // so do not also generate redundant notification here.
+  SetAccessibilityLabel(display_text, match, false);
+
   SetWindowTextAndCaretPos(display_text, display_text.length(), false,
                            notify_text_changed);
   SetAdditionalText(match.fill_into_edit_additional_text);
@@ -951,16 +974,14 @@
 
 void OmniboxViewViews::OnRevertTemporaryText(const base::string16& display_text,
                                              const AutocompleteMatch& match) {
-  SetAccessibilityLabel(display_text, match);
-  SetSelectedRanges(saved_temporary_selection_);
-
   // We got here because the user hit the Escape key. We explicitly don't call
   // TextChanged(), since OmniboxPopupModel::ResetToDefaultMatch() has already
   // been called by now, and it would've called TextChanged() if it was
   // warranted.
   // However, it's important to notify accessibility that the value has changed,
   // otherwise the screen reader will use the old accessibility label text.
-  NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
+  SetAccessibilityLabel(display_text, match, true);
+  SetSelectedRanges(saved_temporary_selection_);
 }
 
 void OmniboxViewViews::ClearAccessibilityLabel() {
@@ -972,7 +993,8 @@
 }
 
 void OmniboxViewViews::SetAccessibilityLabel(const base::string16& display_text,
-                                             const AutocompleteMatch& match) {
+                                             const AutocompleteMatch& match,
+                                             bool notify_text_changed) {
   if (model()->popup_model()->selected_line() == OmniboxPopupModel::kNoMatch) {
     // If nothing is selected in the popup, we are in the no-default-match edge
     // case, and |match| is a synthetically generated match. In that case,
@@ -983,9 +1005,12 @@
   } else {
     friendly_suggestion_text_ =
         model()->popup_model()->GetAccessibilityLabelForCurrentSelection(
-            display_text, &friendly_suggestion_text_prefix_length_);
+            display_text, true, &friendly_suggestion_text_prefix_length_);
   }
 
+  if (notify_text_changed)
+    NotifyAccessibilityEvent(ax::mojom::Event::kValueChanged, true);
+
 #if defined(OS_MAC)
   // On macOS, the only way to get VoiceOver to speak the friendly suggestion
   // text (for example, "how to open a pdf, search suggestion, 4 of 8") is
@@ -2477,22 +2502,37 @@
   }
 
   // |simplified_domain_rect| gives us the current bounds of the simplified
-  // domain substring. We shift it to the leftmost edge of the omnibox (as
-  // determined by the x position of the current display rect), and then scroll
-  // to where the simplified domain begins, so that the simplified domain
-  // appears at the leftmost edge.
+  // domain substring. We shift it to the leftmost (rightmost if UI is RTL) edge
+  // of the omnibox (as determined by the x position of the current display
+  // rect), and then scroll to where the simplified domain begins, so that the
+  // simplified domain appears at the leftmost/rightmost edge.
   gfx::Rect old_bounds = GetRenderText()->display_rect();
+  int shifted_simplified_domain_x_pos;
+  // The x position of the elided domain will depend on whether the UI is LTR or
+  // RTL.
+  if (base::i18n::IsRTL()) {
+    shifted_simplified_domain_x_pos =
+        old_bounds.right() - simplified_domain_rect.width();
+  } else {
+    shifted_simplified_domain_x_pos = old_bounds.x();
+  }
   // Use |old_bounds| for y and height values because the URL should never shift
   // vertically while eliding to/from simplified domain.
-  gfx::Rect shifted_simplified_domain_rect(old_bounds.x(), old_bounds.y(),
-                                           simplified_domain_rect.width(),
-                                           old_bounds.height());
+  gfx::Rect shifted_simplified_domain_rect(
+      shifted_simplified_domain_x_pos, old_bounds.y(),
+      simplified_domain_rect.width(), old_bounds.height());
   GetRenderText()->SetDisplayRect(shifted_simplified_domain_rect);
   // Scroll the text to where the simplified domain begins, relative to the
-  // leftmost edge of the current display rect.
-  GetRenderText()->SetDisplayOffset(
-      GetRenderText()->GetUpdatedDisplayOffset().x() -
-      (simplified_domain_rect.x() - old_bounds.x()));
+  // leftmost (rightmost if UI is RTL) edge of the current display rect.
+  if (base::i18n::IsRTL()) {
+    GetRenderText()->SetDisplayOffset(
+        GetRenderText()->GetUpdatedDisplayOffset().x() + old_bounds.right() -
+        simplified_domain_rect.right());
+  } else {
+    GetRenderText()->SetDisplayOffset(
+        GetRenderText()->GetUpdatedDisplayOffset().x() -
+        (simplified_domain_rect.x() - old_bounds.x()));
+  }
 
   // GetSubstringBounds() rounds outward internally, so there may be small
   // portions of text still showing. Set the ranges surrounding the simplified
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
index 1fa2082..729d9c8 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -219,6 +219,8 @@
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, CloseOmniboxPopupOnTextDrag);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, FriendlyAccessibleLabel);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, DoNotNavigateOnDrop);
+  FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest,
+                           ElideAnimationDoesntStartIfNoVisibleChange);
 
   // Animates the URL to a given range of text, which could be a substring or
   // superstring of what's currently displayed. An elision animation hides the
@@ -348,7 +350,8 @@
   void ClearAccessibilityLabel();
 
   void SetAccessibilityLabel(const base::string16& display_text,
-                             const AutocompleteMatch& match) override;
+                             const AutocompleteMatch& match,
+                             bool notify_text_changed) override;
 
   // Returns true if the user text was updated with the full URL (without
   // steady-state elisions).  |gesture| is the user gesture causing unelision.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index c5c771f..46799fe9 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/i18n/rtl.h"
 #include "base/macros.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_tick_clock.h"
@@ -229,6 +230,13 @@
   DISALLOW_COPY_AND_ASSIGN(TestingOmniboxEditController);
 };
 
+// TODO(crbug.com/1112536): With RTL UI, the URL is sometimes off by one pixel
+// of the right edge. Investigate if this is expected, otherwise replace this
+// with equality checks in tests that use it. Checks |a| is within 1 of |b|.
+void CheckEqualsWithMarginOne(int a, int b) {
+  EXPECT_LE(std::abs(a - b), 1);
+}
+
 }  // namespace
 
 // OmniboxViewViewsTest -------------------------------------------------------
@@ -236,10 +244,11 @@
 // Base class that ensures ScopedFeatureList is initialized first.
 class OmniboxViewViewsTestBase : public ChromeViewsTestBase {
  public:
-  OmniboxViewViewsTestBase(
-      const std::vector<base::Feature>& enabled_features,
-      const std::vector<base::Feature>& disabled_features) {
+  OmniboxViewViewsTestBase(const std::vector<base::Feature>& enabled_features,
+                           const std::vector<base::Feature>& disabled_features,
+                           bool is_rtl_ui_test = false) {
     scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
+    base::i18n::SetRTLForTesting(is_rtl_ui_test);
   }
 
  protected:
@@ -263,7 +272,8 @@
 class OmniboxViewViewsTest : public OmniboxViewViewsTestBase {
  public:
   OmniboxViewViewsTest(const std::vector<base::Feature>& enabled_features,
-                       const std::vector<base::Feature>& disabled_features);
+                       const std::vector<base::Feature>& disabled_features,
+                       bool is_rtl_ui_test = false);
 
   OmniboxViewViewsTest()
       : OmniboxViewViewsTest(std::vector<base::Feature>(),
@@ -342,8 +352,11 @@
 
 OmniboxViewViewsTest::OmniboxViewViewsTest(
     const std::vector<base::Feature>& enabled_features,
-    const std::vector<base::Feature>& disabled_features)
-    : OmniboxViewViewsTestBase(enabled_features, disabled_features),
+    const std::vector<base::Feature>& disabled_features,
+    bool is_rtl_ui_test)
+    : OmniboxViewViewsTestBase(enabled_features,
+                               disabled_features,
+                               is_rtl_ui_test),
       command_updater_(nullptr),
       omnibox_edit_controller_(&command_updater_, &location_bar_model_) {}
 
@@ -831,6 +844,30 @@
   EXPECT_FALSE(omnibox_view()->IsSelectAll());
 }
 
+TEST_F(OmniboxViewViewsTest, ElideAnimationDoesntStartIfNoVisibleChange) {
+  SetUpSimplifiedDomainTest();
+  gfx::RenderText* render_text = omnibox_view()->GetRenderText();
+  OmniboxViewViews::ElideAnimation elide_animation(omnibox_view(), render_text);
+  // Before any animation runs, the elide from rectangle is considered to be
+  // render_text's DisplayRect, so set it manually to be the current URL length.
+  gfx::Rect full_url_bounds;
+  for (auto rect : render_text->GetSubstringBounds(
+           gfx::Range(0, omnibox_view()->GetOmniboxTextLength()))) {
+    full_url_bounds.Union(rect);
+  }
+  render_text->SetDisplayRect(full_url_bounds);
+  // Start the animation, and have it animate to the current state.
+  elide_animation.Start(
+      gfx::Range(0,
+                 omnibox_view()->GetOmniboxTextLength()), /* elide_to_bounds */
+      0,                                                  /* delay_ms */
+      {gfx::Range(0, 0)}, /* ranges_surrounding_simplified_domain */
+      SK_ColorBLACK,      /* starting_color */
+      SK_ColorBLACK);     /* ending_color */
+  // Animation shouldn't have been started.
+  EXPECT_FALSE(elide_animation.IsAnimating());
+}
+
 class OmniboxViewViewsClipboardTest
     : public OmniboxViewViewsTest,
       public ::testing::WithParamInterface<ui::TextEditCommand> {
@@ -1451,8 +1488,15 @@
     // is because GetSubstringBounds() rounds outward, so the width of
     // |subdomain_and_scheme_rect| could slightly overlap
     // |registrable_domain_rect|.
-    EXPECT_EQ(registrable_domain_rect.x() - subdomain_and_scheme_rect.x(),
-              -1 * render_text->GetUpdatedDisplayOffset().x());
+    // In the RTL UI case, the offset instead has to push the path offscreen to
+    // the right, so we check offset equals the width of the path rectangle.
+    if (base::i18n::IsRTL()) {
+      CheckEqualsWithMarginOne(path_rect.width(),
+                               render_text->GetUpdatedDisplayOffset().x());
+    } else {
+      EXPECT_EQ(registrable_domain_rect.x() - subdomain_and_scheme_rect.x(),
+                -1 * render_text->GetUpdatedDisplayOffset().x());
+    }
     // The scheme and subdomain should be transparent.
     EXPECT_EQ(SK_ColorTRANSPARENT, view->GetLatestColorForRange(gfx::Range(
                                        0, scheme.size() + subdomain.size())));
@@ -1470,8 +1514,15 @@
     // text starts at the subdomain. As above, it's important to compute the
     // expected offset with x() values instead of width()s, since the width()s
     // of different adjacent substring bounds could overlap.
-    EXPECT_EQ(hostname_rect.x() - subdomain_and_scheme_rect.x(),
-              -1 * render_text->GetUpdatedDisplayOffset().x());
+    // In the RTL UI case, the offset instead has to push the path offscreen to
+    // the right, so we check offset equals the width of the path rectangle.
+    if (base::i18n::IsRTL()) {
+      CheckEqualsWithMarginOne(path_rect.width(),
+                               render_text->GetUpdatedDisplayOffset().x());
+    } else {
+      EXPECT_EQ(hostname_rect.x() - subdomain_and_scheme_rect.x(),
+                -1 * render_text->GetUpdatedDisplayOffset().x());
+    }
     // The scheme should be transparent.
     EXPECT_EQ(SK_ColorTRANSPARENT,
               view->GetLatestColorForRange(gfx::Range(0, scheme.size())));
@@ -1493,8 +1544,14 @@
   }
   EXPECT_TRUE(render_text->display_rect().Contains(unelided_rect));
   // |display_url| should be at the leading edge of |render_text|'s display
-  // rect.
-  EXPECT_EQ(unelided_rect.x(), render_text->display_rect().x());
+  // rect for LTR UI, or at the rightmost side of the omnibox for RTL UI.
+  if (base::i18n::IsRTL()) {
+    CheckEqualsWithMarginOne(
+        unelided_rect.x(),
+        render_text->display_rect().right() - unelided_rect.width());
+  } else {
+    EXPECT_EQ(unelided_rect.x(), render_text->display_rect().x());
+  }
 }
 
 // Returns true if |render_text|'s current display rect and offset display at
@@ -1548,17 +1605,18 @@
 
 class OmniboxViewViewsRevealOnHoverTest
     : public OmniboxViewViewsTest,
-      public ::testing::WithParamInterface<bool> {
+      public ::testing::WithParamInterface<std::pair<bool, bool>> {
  public:
   OmniboxViewViewsRevealOnHoverTest()
       : OmniboxViewViewsTest(
-            GetParam()
+            GetParam().first
                 ? std::vector<base::Feature>(
                       {omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
                        omnibox::kElideToRegistrableDomain})
                 : std::vector<base::Feature>(
                       {omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover}),
-            {}) {}
+            {},
+            GetParam().second) {}
 
   OmniboxViewViewsRevealOnHoverTest(const OmniboxViewViewsRevealOnHoverTest&) =
       delete;
@@ -1566,12 +1624,15 @@
       const OmniboxViewViewsRevealOnHoverTest&) = delete;
 
  protected:
-  bool ShouldElideToRegistrableDomain() { return GetParam(); }
+  bool ShouldElideToRegistrableDomain() { return GetParam().first; }
 };
 
 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsRevealOnHoverTest,
                          OmniboxViewViewsRevealOnHoverTest,
-                         ::testing::Values(true, false));
+                         ::testing::ValuesIn({std::make_pair(true, false),
+                                              std::make_pair(false, false),
+                                              std::make_pair(true, true),
+                                              std::make_pair(false, true)}));
 
 // Tests the field trial variation that shows a simplified domain by default and
 // reveals the unsimplified URL on hover.
@@ -1644,11 +1705,11 @@
 
 class OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest
     : public OmniboxViewViewsTest,
-      public ::testing::WithParamInterface<bool> {
+      public ::testing::WithParamInterface<std::pair<bool, bool>> {
  public:
   OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest()
       : OmniboxViewViewsTest(
-            GetParam()
+            GetParam().first
                 ? std::vector<base::Feature>(
                       {omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
                        omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction,
@@ -1657,7 +1718,8 @@
                       {omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
                        omnibox::
                            kHideSteadyStateUrlPathQueryAndRefOnInteraction}),
-            {}) {}
+            {},
+            GetParam().second) {}
 
   OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest(
       const OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest&) = delete;
@@ -1665,12 +1727,15 @@
       const OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest&) = delete;
 
  protected:
-  bool ShouldElideToRegistrableDomain() { return GetParam(); }
+  bool ShouldElideToRegistrableDomain() { return GetParam().first; }
 };
 
 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
                          OmniboxViewViewsHideOnInteractionAndRevealOnHoverTest,
-                         ::testing::Values(true, false));
+                         ::testing::ValuesIn({std::make_pair(true, false),
+                                              std::make_pair(false, false),
+                                              std::make_pair(true, true),
+                                              std::make_pair(false, true)}));
 
 // Tests the field trial variation that shows the simplified domain when the
 // user interacts with the page and brings back the URL when the user hovers
@@ -1959,30 +2024,34 @@
 
 class OmniboxViewViewsHideOnInteractionTest
     : public OmniboxViewViewsTest,
-      public ::testing::WithParamInterface<bool> {
+      public ::testing::WithParamInterface<std::pair<bool, bool>> {
  public:
   OmniboxViewViewsHideOnInteractionTest()
       : OmniboxViewViewsTest(
-            GetParam()
+            GetParam().first
                 ? std::vector<base::Feature>(
                       {omnibox::kHideSteadyStateUrlPathQueryAndRefOnInteraction,
                        omnibox::kElideToRegistrableDomain})
                 : std::vector<base::Feature>(
                       {omnibox::
                            kHideSteadyStateUrlPathQueryAndRefOnInteraction}),
-            {}) {}
+            {},
+            GetParam().second) {}
   OmniboxViewViewsHideOnInteractionTest(
       const OmniboxViewViewsHideOnInteractionTest&) = delete;
   OmniboxViewViewsHideOnInteractionTest& operator=(
       const OmniboxViewViewsHideOnInteractionTest&) = delete;
 
  protected:
-  bool ShouldElideToRegistrableDomain() { return GetParam(); }
+  bool ShouldElideToRegistrableDomain() { return GetParam().first; }
 };
 
 INSTANTIATE_TEST_SUITE_P(OmniboxViewViewsHideOnInteractionTest,
                          OmniboxViewViewsHideOnInteractionTest,
-                         ::testing::Values(true, false));
+                         ::testing::ValuesIn({std::make_pair(true, false),
+                                              std::make_pair(false, false),
+                                              std::make_pair(true, true),
+                                              std::make_pair(false, true)}));
 
 // Tests the the "Always Show Full URLs" option works with the field trial
 // variation that shows a simplified domain when the user interacts with the
@@ -2042,11 +2111,11 @@
 // and the hide-on-interaction variation when the parameter is true.
 class OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest
     : public OmniboxViewViewsTest,
-      public ::testing::WithParamInterface<bool> {
+      public ::testing::WithParamInterface<std::pair<bool, bool>> {
  public:
   OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest()
       : OmniboxViewViewsTest(
-            GetParam()
+            GetParam().first
                 ? std::vector<base::Feature>(
                       {omnibox::kOmniboxContextMenuShowFullUrls,
                        omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover,
@@ -2055,7 +2124,8 @@
                 : std::vector<base::Feature>(
                       {omnibox::kOmniboxContextMenuShowFullUrls,
                        omnibox::kRevealSteadyStateUrlPathQueryAndRefOnHover}),
-            {omnibox::kElideToRegistrableDomain}) {}
+            {omnibox::kElideToRegistrableDomain},
+            GetParam().second) {}
 
   OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest(
       const OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest&) =
@@ -2065,13 +2135,16 @@
       delete;
 
  protected:
-  bool IsHideOnInteractionEnabled() { return GetParam(); }
+  bool IsHideOnInteractionEnabled() { return GetParam().first; }
 };
 
 INSTANTIATE_TEST_SUITE_P(
     OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,
     OmniboxViewViewsRevealOnHoverAndMaybeHideOnInteractionTest,
-    ::testing::Values(true, false));
+    ::testing::ValuesIn({std::make_pair(true, false),
+                         std::make_pair(false, false),
+                         std::make_pair(true, true),
+                         std::make_pair(false, true)}));
 
 // Tests that unsetting the "Always show full URLs" option begins showing/hiding
 // the full URL appropriately when simplified domain field trials are enabled.
@@ -2141,6 +2214,11 @@
       omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
   ASSERT_TRUE(elide_animation);
   EXPECT_TRUE(elide_animation->IsAnimating());
+  // Advance the animation, so the visible URL changes.
+  gfx::AnimationContainerElement* elide_as_element =
+      elide_animation->GetAnimationForTesting();
+  elide_as_element->SetStartTime(base::TimeTicks());
+  elide_as_element->Step(base::TimeTicks() + base::TimeDelta::FromSeconds(1));
   omnibox_view()->OnMouseExited(CreateMouseEvent(ui::ET_MOUSE_MOVED, {0, 0}));
   elide_animation = omnibox_view()->GetHoverElideOrUnelideAnimationForTesting();
   ASSERT_TRUE(elide_animation);
@@ -2463,6 +2541,11 @@
 
 // Tests that gradient mask is set correctly.
 TEST_P(OmniboxViewViewsHideOnInteractionTest, GradientMask) {
+  if (base::i18n::IsRTL()) {
+    // TODO(crbug.com/1101472): Re-enable this test once gradient mask is
+    // implemented for RTL UI.
+    return;
+  }
   SetUpSimplifiedDomainTest();
   gfx::RenderText* render_text = omnibox_view()->GetRenderText();
 
@@ -2493,7 +2576,7 @@
   }
   // If we are eliding from the left, the other side gradient should also be
   // full size at this point, otherwise it should be 0.
-  if (GetParam()) {
+  if (ShouldElideToRegistrableDomain()) {
     EXPECT_EQ(omnibox_view()->elide_animation_smoothing_rect_left_.width(),
               max_gradient_width);
   } else {
diff --git a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
index 0d20e4a..2b75bda 100644
--- a/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_info/safety_tip_page_info_bubble_view_browsertest.cc
@@ -429,7 +429,8 @@
     All,
     SafetyTipPageInfoBubbleViewBrowserTest,
     ::testing::Values(UIStatus::kDisabled,
-                      UIStatus::kEnabledWithDefaultFeatures,
+                      // Disabled for flakiness. https://crbug.com/1113105.
+                      // UIStatus::kEnabledWithDefaultFeatures,
                       UIStatus::kEnabledWithSuspiciousSites,
                       UIStatus::kEnabledWithAllFeatures));
 
diff --git a/chrome/browser/ui/views/sharing/click_to_call_browsertest.cc b/chrome/browser/ui/views/sharing/click_to_call_browsertest.cc
index 8c98940..2f060a1 100644
--- a/chrome/browser/ui/views/sharing/click_to_call_browsertest.cc
+++ b/chrome/browser/ui/views/sharing/click_to_call_browsertest.cc
@@ -509,7 +509,7 @@
       policies.Set(policy::key::kClickToCallEnabled,
                    policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
                    policy::POLICY_SOURCE_ENTERPRISE_DEFAULT,
-                   std::make_unique<base::Value>(policy_bool), nullptr);
+                   base::Value(policy_bool), nullptr);
     }
 
     provider_.UpdateChromePolicy(policies);
diff --git a/chrome/browser/ui/webauthn/transport_utils.cc b/chrome/browser/ui/webauthn/transport_utils.cc
index 4701295..46f979a 100644
--- a/chrome/browser/ui/webauthn/transport_utils.cc
+++ b/chrome/browser/ui/webauthn/transport_utils.cc
@@ -28,6 +28,8 @@
       return IDS_WEBAUTHN_TRANSPORT_INTERNAL;
     case AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy:
       return IDS_WEBAUTHN_TRANSPORT_CABLE;
+    case AuthenticatorTransport::kAndroidAccessory:
+      return IDS_WEBAUTHN_TRANSPORT_USB;
   }
   NOTREACHED();
   return 0;
@@ -48,6 +50,8 @@
       return IDS_WEBAUTHN_TRANSPORT_POPUP_INTERNAL;
     case AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy:
       return IDS_WEBAUTHN_TRANSPORT_POPUP_CABLE;
+    case AuthenticatorTransport::kAndroidAccessory:
+      return IDS_WEBAUTHN_TRANSPORT_POPUP_USB;
   }
   NOTREACHED();
   return 0;
@@ -81,6 +85,8 @@
       return &kFingerprintIcon;
     case AuthenticatorTransport::kCloudAssistedBluetoothLowEnergy:
       return &kSmartphoneIcon;
+    case AuthenticatorTransport::kAndroidAccessory:
+      return &kSmartphoneIcon;
   }
   NOTREACHED();
   return &kFingerprintIcon;
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
index 3040f27e..3f17f0c 100644
--- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
@@ -89,8 +89,7 @@
   builder->Add("back", IDS_EULA_BACK_BUTTON);
   builder->Add("next", IDS_EULA_NEXT_BUTTON);
   builder->Add("acceptAgreement", IDS_EULA_ACCEPT_AND_CONTINUE_BUTTON);
-  builder->Add("eulaSystemInstallationSettings",
-               IDS_EULA_SYSTEM_SECURITY_SETTING);
+  builder->Add("eulaSystemSecuritySettings", IDS_EULA_SYSTEM_SECURITY_SETTING);
 
   builder->Add("eulaTpmDesc", IDS_EULA_SECURE_MODULE_DESCRIPTION);
   builder->Add("eulaTpmKeyDesc", IDS_EULA_SECURE_MODULE_KEY_DESCRIPTION);
@@ -100,7 +99,7 @@
   ::login::GetSecureModuleUsed(base::BindOnce(
       &EulaScreenHandler::UpdateLocalizedValues, weak_factory_.GetWeakPtr()));
 
-  builder->Add("eulaSystemInstallationSettingsOkButton", IDS_OK);
+  builder->Add("eulaSystemSecuritySettingsOkButton", IDS_OK);
   builder->Add("termsOfServiceLoading", IDS_TERMS_OF_SERVICE_SCREEN_LOADING);
 #if BUILDFLAG(ENABLE_RLZ)
   builder->AddF("eulaRlzDesc",
@@ -124,14 +123,6 @@
                IDS_OOBE_EULA_ACCEPT_AND_CONTINUE_BUTTON_TEXT);
 }
 
-void EulaScreenHandler::DeclareJSCallbacks() {
-  AddCallback("eulaOnLearnMore", &EulaScreenHandler::HandleOnLearnMore);
-  AddCallback("eulaOnInstallationSettingsPopupOpened",
-              &EulaScreenHandler::HandleOnInstallationSettingsPopupOpened);
-  AddCallback("EulaScreen.usageStatsEnabled",
-              &EulaScreenHandler::HandleUsageStatsEnabled);
-}
-
 void EulaScreenHandler::GetAdditionalParameters(base::DictionaryValue* dict) {
 #if BUILDFLAG(ENABLE_RLZ)
   dict->SetString("rlzEnabled", "enabled");
@@ -154,23 +145,18 @@
 
 void EulaScreenHandler::OnPasswordFetched(const std::string& tpm_password) {
   CallJS("login.EulaScreen.setTpmPassword", tpm_password);
+  CallJS("login.EulaScreen.showSecuritySettingsDialog");
 }
 
-void EulaScreenHandler::HandleOnLearnMore() {
+void EulaScreenHandler::ShowStatsUsageLearnMore() {
   if (!help_app_.get())
     help_app_ = new HelpAppLauncher(
         LoginDisplayHost::default_host()->GetNativeWindow());
   help_app_->ShowHelpTopic(HelpAppLauncher::HELP_STATS_USAGE);
 }
 
-void EulaScreenHandler::HandleOnInstallationSettingsPopupOpened() {
-  if (screen_)
-    screen_->InitiatePasswordFetch();
-}
-
-void EulaScreenHandler::HandleUsageStatsEnabled(bool enabled) {
-  if (screen_)
-    screen_->SetUsageStatsEnabled(enabled);
+void EulaScreenHandler::ShowAdditionalTosDialog() {
+  CallJS("login.EulaScreen.showAdditionalTosDialog");
 }
 
 void EulaScreenHandler::UpdateLocalizedValues(
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
index e4dcb38..4d74615 100644
--- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
@@ -26,7 +26,7 @@
 // dtor.
 class EulaView {
  public:
-  constexpr static StaticOobeScreenId kScreenId{"eula"};
+  constexpr static StaticOobeScreenId kScreenId{"oobe-eula-md"};
 
   virtual ~EulaView() {}
 
@@ -35,6 +35,8 @@
   virtual void Bind(EulaScreen* screen) = 0;
   virtual void Unbind() = 0;
   virtual void OnPasswordFetched(const std::string& tpm_password) = 0;
+  virtual void ShowStatsUsageLearnMore() = 0;
+  virtual void ShowAdditionalTosDialog() = 0;
 };
 
 // WebUI implementation of EulaScreenView. It is used to interact
@@ -53,20 +55,16 @@
   void Bind(EulaScreen* screen) override;
   void Unbind() override;
   void OnPasswordFetched(const std::string& tpm_password) override;
+  void ShowStatsUsageLearnMore() override;
+  void ShowAdditionalTosDialog() override;
 
   // BaseScreenHandler implementation:
   void DeclareLocalizedValues(
       ::login::LocalizedValuesBuilder* builder) override;
-  void DeclareJSCallbacks() override;
   void GetAdditionalParameters(base::DictionaryValue* dict) override;
   void Initialize() override;
 
  private:
-  // JS messages handlers.
-  void HandleOnLearnMore();
-  void HandleOnInstallationSettingsPopupOpened();
-  void HandleUsageStatsEnabled(bool enabled);
-
   // Determines the online URL to use.
   std::string GetEulaOnlineUrl();
   std::string GetAdditionalToSUrl();
@@ -76,12 +74,12 @@
   EulaScreen* screen_ = nullptr;
   CoreOobeView* core_oobe_view_ = nullptr;
 
-  // Help application used for help dialogs.
-  scoped_refptr<HelpAppLauncher> help_app_;
-
   // Keeps whether screen should be shown right after initialization.
   bool show_on_init_ = false;
 
+  // Help application used for help dialogs.
+  scoped_refptr<HelpAppLauncher> help_app_;
+
   base::WeakPtrFactory<EulaScreenHandler> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(EulaScreenHandler);
diff --git a/chrome/browser/ui/webui/managed_ui_handler_unittest.cc b/chrome/browser/ui/webui/managed_ui_handler_unittest.cc
index c165d33a..cc1126a 100644
--- a/chrome/browser/ui/webui/managed_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/managed_ui_handler_unittest.cc
@@ -104,7 +104,7 @@
   policy::PolicyMap non_empty_map;
   non_empty_map.Set("FakePolicyName", policy::POLICY_LEVEL_MANDATORY,
                     policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
-                    std::make_unique<base::Value>("fake"), nullptr);
+                    base::Value("fake"), nullptr);
   policy_provider()->UpdateChromePolicy(non_empty_map);
 
   // Source should auto-update.
diff --git a/chrome/browser/ui/webui/management_ui_browsertest.cc b/chrome/browser/ui/webui/management_ui_browsertest.cc
index 961468b..806e9c1 100644
--- a/chrome/browser/ui/webui/management_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/management_ui_browsertest.cc
@@ -92,7 +92,7 @@
   policy::PolicyMap policy_map;
   policy_map.Set("test-policy", policy::POLICY_LEVEL_MANDATORY,
                  policy::POLICY_SCOPE_MACHINE, policy::POLICY_SOURCE_PLATFORM,
-                 std::make_unique<base::Value>("hello world"), nullptr);
+                 base::Value("hello world"), nullptr);
   provider()->UpdateExtensionPolicy(policy_map,
                                     kOnPremReportingExtensionBetaId);
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc b/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc
index d301f7a91..36aee62 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_power_handler_browsertest.cc
@@ -176,7 +176,7 @@
   // Sets a policy update which will cause power pref managed change.
   void SetPolicyForPolicyKey(policy::PolicyMap* policy_map,
                              const std::string& policy_key,
-                             std::unique_ptr<base::Value> value) {
+                             base::Value value) {
     policy_map->Set(policy_key, policy::POLICY_LEVEL_MANDATORY,
                     policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
                     std::move(value), nullptr);
@@ -224,21 +224,20 @@
   // Making an arbitrary AC delay pref managed should result in the AC idle
   // setting being reported as managed.
   SetPolicyForPolicyKey(&policy_map, policy::key::kScreenDimDelayAC,
-                        std::make_unique<base::Value>(10000));
+                        base::Value(10000));
   DevicePowerSettings settings;
   settings.ac_idle_managed = true;
   EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage());
 
   // Ditto for battery delay pref managed.
   SetPolicyForPolicyKey(&policy_map, policy::key::kScreenDimDelayBattery,
-                        std::make_unique<base::Value>(10000));
+                        base::Value(10000));
   settings.battery_idle_managed = true;
   EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage());
 
   // Ditto for making the lid action pref managed.
-  SetPolicyForPolicyKey(
-      &policy_map, policy::key::kLidCloseAction,
-      std::make_unique<base::Value>(PowerPolicyController::ACTION_SUSPEND));
+  SetPolicyForPolicyKey(&policy_map, policy::key::kLidCloseAction,
+                        base::Value(PowerPolicyController::ACTION_SUSPEND));
   settings.lid_closed_controlled = true;
   EXPECT_EQ(ToString(settings), GetLastSettingsChangedMessage());
 }
@@ -288,9 +287,9 @@
   // Set Enterpise policy that forces AC idle action to suspend. Only possible
   // AC idle option visible to the user should be DISPLAY_OFF_SLEEP and the
   // current should also be set to same.
-  SetPolicyForPolicyKey(&policy_map, policy::key::kIdleActionAC,
-                        std::make_unique<base::Value>(
-                            chromeos::PowerPolicyController::ACTION_SUSPEND));
+  SetPolicyForPolicyKey(
+      &policy_map, policy::key::kIdleActionAC,
+      base::Value(chromeos::PowerPolicyController::ACTION_SUSPEND));
   DevicePowerSettings settings;
   std::set<PowerHandler::IdleBehavior> behaviors;
   behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_OFF_SLEEP);
@@ -301,9 +300,9 @@
   // Set Enterpise policy that forces battery idle action to Shutdown. Only
   // possible battery idle option visible to the user then should be OTHER and
   // the default should also be set to same.
-  SetPolicyForPolicyKey(&policy_map, policy::key::kIdleActionBattery,
-                        std::make_unique<base::Value>(
-                            chromeos::PowerPolicyController::ACTION_SHUT_DOWN));
+  SetPolicyForPolicyKey(
+      &policy_map, policy::key::kIdleActionBattery,
+      base::Value(chromeos::PowerPolicyController::ACTION_SHUT_DOWN));
   behaviors.clear();
   behaviors.insert(PowerHandler::IdleBehavior::OTHER);
   settings.possible_battery_behaviors = behaviors;
@@ -317,8 +316,7 @@
   // should not see DISPLAY_OFF_SLEEP in available options.
   SetPolicyForPolicyKey(
       &policy_map, policy::key::kIdleActionBattery,
-      std::make_unique<base::Value>(
-          chromeos::PowerPolicyController::ACTION_DO_NOTHING));
+      base::Value(chromeos::PowerPolicyController::ACTION_DO_NOTHING));
   behaviors.clear();
   behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_OFF);
   behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_ON);
@@ -330,7 +328,7 @@
   // action. The user should see only see DISPLAY_OFF as the possible battery
   // idle action.
   SetPolicyForPolicyKey(&policy_map, policy::key::kScreenOffDelayBattery,
-                        std::make_unique<base::Value>(10000));
+                        base::Value(10000));
   behaviors.clear();
   behaviors.insert(PowerHandler::IdleBehavior::DISPLAY_OFF);
   settings.possible_battery_behaviors = behaviors;
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_storage_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/device_storage_handler_unittest.cc
index b05bf1b..92df43e 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_storage_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_storage_handler_unittest.cc
@@ -23,7 +23,6 @@
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/test/fake_arc_session.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -59,9 +58,6 @@
   ~StorageHandlerTest() override = default;
 
   void SetUp() override {
-    // Need to initialize DBusThreadManager before ArcSessionManager's
-    // constructor calls DBusThreadManager::Get().
-    chromeos::DBusThreadManager::Initialize();
     // The storage handler requires an instance of DiskMountManager,
     // ArcServiceManager and ArcSessionManager.
     chromeos::disks::DiskMountManager::InitializeForTesting(
@@ -123,11 +119,8 @@
     apps_size_test_api_.reset();
     crostini_size_test_api_.reset();
     other_users_size_test_api_.reset();
-    arc_session_manager_.reset();
-    arc_service_manager_.reset();
     chromeos::disks::DiskMountManager::Shutdown();
     storage::ExternalMountPoints::GetSystemInstance()->RevokeAllFileSystems();
-    chromeos::DBusThreadManager::Shutdown();
   }
 
  protected:
diff --git a/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc b/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
index 81aa102..378b66e 100644
--- a/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
@@ -174,7 +174,7 @@
   // Sets a policy update which will cause power pref managed change.
   void SetPolicyForPolicyKey(policy::PolicyMap* policy_map,
                              const std::string& policy_key,
-                             std::unique_ptr<base::Value> value) {
+                             base::Value value) {
     policy_map->Set(policy_key, policy::POLICY_LEVEL_MANDATORY,
                     policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
                     std::move(value), nullptr);
@@ -225,9 +225,8 @@
 
 IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsPolicy) {
   policy::PolicyMap policy_map;
-  SetPolicyForPolicyKey(
-      &policy_map, policy::key::kDnsOverHttpsMode,
-      std::make_unique<base::Value>(SecureDnsConfig::kModeAutomatic));
+  SetPolicyForPolicyKey(&policy_map, policy::key::kDnsOverHttpsMode,
+                        base::Value(SecureDnsConfig::kModeAutomatic));
 
   PrefService* local_state = g_browser_process->local_state();
   local_state->SetString(prefs::kDnsOverHttpsMode,
@@ -245,9 +244,8 @@
 
 IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, SecureDnsPolicyChange) {
   policy::PolicyMap policy_map;
-  SetPolicyForPolicyKey(
-      &policy_map, policy::key::kDnsOverHttpsMode,
-      std::make_unique<base::Value>(SecureDnsConfig::kModeAutomatic));
+  SetPolicyForPolicyKey(&policy_map, policy::key::kDnsOverHttpsMode,
+                        base::Value(SecureDnsConfig::kModeAutomatic));
 
   std::string secure_dns_mode;
   std::vector<std::string> secure_dns_templates;
@@ -258,9 +256,8 @@
   EXPECT_EQ(static_cast<int>(SecureDnsConfig::ManagementMode::kNoOverride),
             management_mode);
 
-  SetPolicyForPolicyKey(
-      &policy_map, policy::key::kDnsOverHttpsMode,
-      std::make_unique<base::Value>(SecureDnsConfig::kModeOff));
+  SetPolicyForPolicyKey(&policy_map, policy::key::kDnsOverHttpsMode,
+                        base::Value(SecureDnsConfig::kModeOff));
   EXPECT_TRUE(GetLastSettingsChangedMessage(
       &secure_dns_mode, &secure_dns_templates, &management_mode));
   EXPECT_EQ(SecureDnsConfig::kModeOff, secure_dns_mode);
@@ -274,7 +271,7 @@
 IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, OtherPoliciesSet) {
   policy::PolicyMap policy_map;
   SetPolicyForPolicyKey(&policy_map, policy::key::kIncognitoModeAvailability,
-                        std::make_unique<base::Value>(1));
+                        base::Value(1));
 
   PrefService* local_state = g_browser_process->local_state();
   local_state->SetString(prefs::kDnsOverHttpsMode,
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
index b74f0bfa..c5c9c685 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -43,6 +43,10 @@
       base::BindRepeating(&ProfilePickerHandler::HandleLaunchSelectedProfile,
                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
+      "launchGuestProfile",
+      base::BindRepeating(&ProfilePickerHandler::HandleLaunchGuestProfile,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "askOnStartupChanged",
       base::BindRepeating(&ProfilePickerHandler::HandleAskOnStartupChanged,
                           base::Unretained(this)));
@@ -107,6 +111,15 @@
                  weak_factory_.GetWeakPtr()));
 }
 
+void ProfilePickerHandler::HandleLaunchGuestProfile(
+    const base::ListValue* args) {
+  // TODO(crbug.com/1063856): Add check |IsGuestModeEnabled| once policy
+  // checking has been added to the UI.
+  profiles::SwitchToGuestProfile(
+      base::Bind(&ProfilePickerHandler::OnSwitchToProfileComplete,
+                 weak_factory_.GetWeakPtr()));
+}
+
 void ProfilePickerHandler::HandleAskOnStartupChanged(
     const base::ListValue* args) {
   bool show_on_startup;
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.h b/chrome/browser/ui/webui/signin/profile_picker_handler.h
index 8d98c0f..6b2269d 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.h
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.h
@@ -26,6 +26,7 @@
  private:
   void HandleMainViewInitialize(const base::ListValue* args);
   void HandleLaunchSelectedProfile(const base::ListValue* args);
+  void HandleLaunchGuestProfile(const base::ListValue* args);
   void HandleAskOnStartupChanged(const base::ListValue* args);
   void HandleGetNewProfileSuggestedThemeInfo(const base::ListValue* args);
   void HandleLoadSignInProfileCreationFlow(const base::ListValue* args);
diff --git a/chrome/browser/ui/webui/signin/profile_picker_ui.cc b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
index 176336c..2ff67fd9 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
@@ -25,6 +25,7 @@
       {"mainViewTitle", IDS_PROFILE_PICKER_MAIN_VIEW_TITLE},
       {"mainViewSubtitle", IDS_PROFILE_PICKER_MAIN_VIEW_SUBTITLE},
       {"askOnStartupCheckboxText", IDS_PROFILE_PICKER_ASK_ON_STARTUP},
+      {"browseAsGuestButton", IDS_PROFILE_PICKER_BROWSE_AS_GUEST_BUTTON},
       {"backButtonLabel", IDS_PROFILE_PICKER_BACK_BUTTON_LABEL},
       {"profileTypeChoiceTitle",
        IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_PROFILE_TYPE_CHOICE_TITLE},
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index 6463013d..d6d293f 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -28,6 +28,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/device_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "device/fido/features.h"
@@ -323,6 +324,11 @@
     auto paired_phones = GetCablePairings();
     have_paired_phones = !paired_phones.empty();
     pairings.insert(pairings.end(), paired_phones.begin(), paired_phones.end());
+
+    mojo::Remote<device::mojom::UsbDeviceManager> usb_device_manager;
+    content::GetDeviceService().BindUsbDeviceManager(
+        usb_device_manager.BindNewPipeAndPassReceiver());
+    discovery_factory()->set_usb_device_manager(std::move(usb_device_manager));
   }
 
   if (pairings.empty() && !qr_generator_key) {
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 0d3a936..63f80ca5 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1596610622-a993b1ede4201f1709aeb65ee161df429dedf1b5.profdata
+chrome-win32-master-1596628771-e32af535197a262fe54680b0a1a803a0983bdd0a.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index de8d250..3dd22efc 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1596606694-35c6f8535b14ce15b4839555c5550c892d549ecc.profdata
+chrome-win64-master-1596628771-86348d2a61736525bb253851ce1433e67dea13ba.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index a7fc300..f1869d3 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -536,6 +536,11 @@
 const base::Feature kParentAccessCode{"ParentAccessCode",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables usage of Parent Access Code in the login flow for reauth and add
+// user. Requires |kParentAccessCode| to be enabled.
+const base::Feature kParentAccessCodeForOnlineLogin{
+    "ParentAccessCodeForOnlineLogin", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables usage of Parent Access Code to authorize change of time actions on
 // child user device. Requires |kParentAccessCode| to be enabled.
 const base::Feature kParentAccessCodeForTimeChange{
@@ -693,11 +698,6 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-// Enables or disables pin quick unlock.
-// TODO(https://crbug.com/935613): Remove this & the backing code.
-const base::Feature kQuickUnlockPin{"QuickUnlockPin",
-                                    base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Controls whether the PIN auto submit feature is enabled.
 const base::Feature kQuickUnlockPinAutosubmit{
     "QuickUnlockPinAutosubmit", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -806,4 +806,11 @@
                                    base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(OS_CHROMEOS)
+bool IsParentAccessCodeForOnlineLoginEnabled() {
+  return base::FeatureList::IsEnabled(kParentAccessCode) &&
+         base::FeatureList::IsEnabled(kParentAccessCodeForOnlineLogin);
+}
+#endif  // defined(OS_CHROMEOS)
+
 }  // namespace features
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index a982924..c5bce98 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -342,6 +342,9 @@
 extern const base::Feature kParentAccessCode;
 
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kParentAccessCodeForOnlineLogin;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kParentAccessCodeForTimeChange;
 
 COMPONENT_EXPORT(CHROME_FEATURES)
@@ -455,8 +458,6 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kQuickUnlockPin;
-
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kQuickUnlockPinAutosubmit;
 
@@ -521,6 +522,11 @@
 extern const base::Feature kWebTimeLimits;
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+bool IsParentAccessCodeForOnlineLoginEnabled();
+#endif  // defined(OS_CHROMEOS)
+
 bool PrefServiceEnabled();
 
 // DON'T ADD RANDOM STUFF HERE. Put it in the main section above in
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b880fa362..cfedcfe 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -884,6 +884,7 @@
       "../browser/component_updater/component_patcher_operation_browsertest.cc",
       "../browser/content_index/content_index_browsertest.cc",
       "../browser/content_settings/content_settings_browsertest.cc",
+      "../browser/conversions/conversions_usecounter_browsertest.cc",
       "../browser/crash_recovery_browsertest.cc",
       "../browser/custom_handlers/protocol_handler_registry_browsertest.cc",
       "../browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc",
diff --git a/chrome/test/data/pdf/viewer_pdf_toolbar_new_test.js b/chrome/test/data/pdf/viewer_pdf_toolbar_new_test.js
index 0c026c0..b260cea 100644
--- a/chrome/test/data/pdf/viewer_pdf_toolbar_new_test.js
+++ b/chrome/test/data/pdf/viewer_pdf_toolbar_new_test.js
@@ -156,8 +156,12 @@
 
     toolbar.addEventListener('two-up-view-changed', function(e) {
       chrome.test.assertEq(false, e.detail);
+      chrome.test.assertEq(
+          'true', singlePageViewButton.getAttribute('aria-checked'));
       chrome.test.assertFalse(
           singlePageViewButton.querySelector('iron-icon').hidden);
+      chrome.test.assertEq(
+          'false', twoPageViewButton.getAttribute('aria-checked'));
       chrome.test.assertTrue(
           twoPageViewButton.querySelector('iron-icon').hidden);
       chrome.test.succeed();
@@ -174,8 +178,12 @@
 
     toolbar.addEventListener('two-up-view-changed', function(e) {
       chrome.test.assertEq(true, e.detail);
+      chrome.test.assertEq(
+          'true', twoPageViewButton.getAttribute('aria-checked'));
       chrome.test.assertFalse(
           twoPageViewButton.querySelector('iron-icon').hidden);
+      chrome.test.assertEq(
+          'false', singlePageViewButton.getAttribute('aria-checked'));
       chrome.test.assertTrue(
           singlePageViewButton.querySelector('iron-icon').hidden);
       chrome.test.succeed();
@@ -188,11 +196,15 @@
 
     const showAnnotationsButton =
         toolbar.shadowRoot.querySelector('#show-annotations-button');
+    chrome.test.assertEq(
+        'true', showAnnotationsButton.getAttribute('aria-checked'));
     chrome.test.assertFalse(
         showAnnotationsButton.querySelector('iron-icon').hidden);
 
     toolbar.addEventListener('display-annotations-changed', (e) => {
       chrome.test.assertEq(false, e.detail);
+      chrome.test.assertEq(
+          'false', showAnnotationsButton.getAttribute('aria-checked'));
       chrome.test.assertTrue(
           showAnnotationsButton.querySelector('iron-icon').hidden);
       chrome.test.succeed();
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
index 3483370e..ed5d756 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -389,7 +389,7 @@
   policy::PolicyMap policy;
   policy.Set(policy::key::kEnableMediaRouter, policy::POLICY_LEVEL_MANDATORY,
              policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
-             std::make_unique<base::Value>(enable), nullptr);
+             base::Value(enable), nullptr);
   provider_.UpdateChromePolicy(policy);
   base::RunLoop().RunUntilIdle();
 }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 352cb6c..76fc03b 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-13387.0.0
\ No newline at end of file
+13389.0.0
\ No newline at end of file
diff --git a/chromeos/dbus/system_proxy/fake_system_proxy_client.cc b/chromeos/dbus/system_proxy/fake_system_proxy_client.cc
index baa7569..f45acf4 100644
--- a/chromeos/dbus/system_proxy/fake_system_proxy_client.cc
+++ b/chromeos/dbus/system_proxy/fake_system_proxy_client.cc
@@ -24,13 +24,6 @@
       FROM_HERE, base::BindOnce(std::move(callback), response));
 }
 
-void FakeSystemProxyClient::ShutDownDaemon(ShutDownDaemonCallback callback) {
-  ++shut_down_call_count_;
-  system_proxy::ShutDownResponse response;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), response));
-}
-
 void FakeSystemProxyClient::ClearUserCredentials(
     const system_proxy::ClearUserCredentialsRequest& request,
     ClearUserCredentialsCallback callback) {
@@ -40,6 +33,15 @@
       FROM_HERE, base::BindOnce(std::move(callback), response));
 }
 
+void FakeSystemProxyClient::ShutDownProcess(
+    const system_proxy::ShutDownRequest& request,
+    ShutDownProcessCallback callback) {
+  ++shut_down_call_count_;
+  system_proxy::ShutDownResponse response;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), response));
+}
+
 void FakeSystemProxyClient::SetWorkerActiveSignalCallback(
     WorkerActiveCallback callback) {
   worker_active_callback_ = callback;
diff --git a/chromeos/dbus/system_proxy/fake_system_proxy_client.h b/chromeos/dbus/system_proxy/fake_system_proxy_client.h
index 300b68b..10a6952 100644
--- a/chromeos/dbus/system_proxy/fake_system_proxy_client.h
+++ b/chromeos/dbus/system_proxy/fake_system_proxy_client.h
@@ -24,13 +24,14 @@
   void SetAuthenticationDetails(
       const system_proxy::SetAuthenticationDetailsRequest& request,
       SetAuthenticationDetailsCallback callback) override;
-  void ShutDownDaemon(ShutDownDaemonCallback callback) override;
   void SetWorkerActiveSignalCallback(WorkerActiveCallback callback) override;
   void SetAuthenticationRequiredSignalCallback(
       AuthenticationRequiredCallback callback) override;
   void ClearUserCredentials(
       const system_proxy::ClearUserCredentialsRequest& request,
       ClearUserCredentialsCallback callback) override;
+  void ShutDownProcess(const system_proxy::ShutDownRequest& request,
+                       ShutDownProcessCallback callback) override;
 
   void ConnectToWorkerSignals() override;
 
diff --git a/chromeos/dbus/system_proxy/system_proxy_client.cc b/chromeos/dbus/system_proxy/system_proxy_client.cc
index 8bd005b..d6bdba1 100644
--- a/chromeos/dbus/system_proxy/system_proxy_client.cc
+++ b/chromeos/dbus/system_proxy/system_proxy_client.cc
@@ -67,10 +67,6 @@
                                request, std::move(callback));
   }
 
-  void ShutDownDaemon(ShutDownDaemonCallback callback) override {
-    CallProtoMethod(system_proxy::kShutDownMethod, std::move(callback));
-  }
-
   void ClearUserCredentials(
       const system_proxy::ClearUserCredentialsRequest& request,
       ClearUserCredentialsCallback callback) override {
@@ -78,6 +74,12 @@
                                request, std::move(callback));
   }
 
+  void ShutDownProcess(const system_proxy::ShutDownRequest& request,
+                       ShutDownProcessCallback callback) override {
+    CallProtoMethodWithRequest(system_proxy::kShutDownProcessMethod, request,
+                               std::move(callback));
+  }
+
   void SetWorkerActiveSignalCallback(WorkerActiveCallback callback) override {
     DCHECK(callback);
     DCHECK(!worker_active_callback_);
diff --git a/chromeos/dbus/system_proxy/system_proxy_client.h b/chromeos/dbus/system_proxy/system_proxy_client.h
index 2955dd8..178d396 100644
--- a/chromeos/dbus/system_proxy/system_proxy_client.h
+++ b/chromeos/dbus/system_proxy/system_proxy_client.h
@@ -23,14 +23,14 @@
  public:
   using SetAuthenticationDetailsCallback = base::OnceCallback<void(
       const system_proxy::SetAuthenticationDetailsResponse& response)>;
-  using ShutDownDaemonCallback =
-      base::OnceCallback<void(const system_proxy::ShutDownResponse& response)>;
   using WorkerActiveCallback = base::RepeatingCallback<void(
       const system_proxy::WorkerActiveSignalDetails& details)>;
   using AuthenticationRequiredCallback = base::RepeatingCallback<void(
       const system_proxy::AuthenticationRequiredDetails& details)>;
   using ClearUserCredentialsCallback = base::OnceCallback<void(
       const system_proxy::ClearUserCredentialsResponse& response)>;
+  using ShutDownProcessCallback =
+      base::OnceCallback<void(const system_proxy::ShutDownResponse& response)>;
 
   // Interface with testing functionality. Accessed through GetTestInterface(),
   // only implemented in the fake implementation.
@@ -38,7 +38,7 @@
    public:
     // Returns how many times |SetAuthenticationDetails| was called.
     virtual int GetSetAuthenticationDetailsCallCount() const = 0;
-    // Returns how many times |ShutDownDaemon| was called.
+    // Returns how many times |ShutDownProcess| was called.
     virtual int GetShutDownCallCount() const = 0;
     // Returns how many times |ClearUserCredentials| was called.
     virtual int GetClearUserCredentialsCount() const = 0;
@@ -79,14 +79,16 @@
       const system_proxy::SetAuthenticationDetailsRequest& request,
       SetAuthenticationDetailsCallback callback) = 0;
 
-  // When receiving a shut-down call, System-proxy will schedule a shut-down
-  // task and reply. |callback| is called when the daemon starts to shut-down.
-  virtual void ShutDownDaemon(ShutDownDaemonCallback callback) = 0;
-
   virtual void ClearUserCredentials(
       const system_proxy::ClearUserCredentialsRequest& request,
       ClearUserCredentialsCallback callback) = 0;
 
+  // When receiving a shut down call, System-proxy will schedule a shut down
+  // task and reply. |callback| is called when the daemon or one of the
+  // processes starts to shut down.
+  virtual void ShutDownProcess(const system_proxy::ShutDownRequest& request,
+                               ShutDownProcessCallback callback) = 0;
+
   // Returns an interface for testing (fake only), or returns nullptr.
   virtual TestInterface* GetTestInterface() = 0;
 
diff --git a/components/arc/clipboard/arc_clipboard_bridge.cc b/components/arc/clipboard/arc_clipboard_bridge.cc
index ce9fc07..af34838b 100644
--- a/components/arc/clipboard/arc_clipboard_bridge.cc
+++ b/components/arc/clipboard/arc_clipboard_bridge.cc
@@ -4,6 +4,7 @@
 
 #include "components/arc/clipboard/arc_clipboard_bridge.h"
 
+#include <memory>
 #include <utility>
 #include <vector>
 
@@ -15,6 +16,7 @@
 #include "components/arc/session/arc_bridge_service.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/clipboard_constants.h"
+#include "ui/base/clipboard/clipboard_data_endpoint.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 
@@ -172,7 +174,9 @@
 
   // Order is important. AutoReset should outlive ScopedClipboardWriter.
   base::AutoReset<bool> auto_reset(&event_originated_at_instance_, true);
-  ui::ScopedClipboardWriter writer(ui::ClipboardBuffer::kCopyPaste);
+  ui::ScopedClipboardWriter writer(
+      ui::ClipboardBuffer::kCopyPaste,
+      std::make_unique<ui::ClipboardDataEndpoint>(ui::EndpointType::kVm));
 
   for (const auto& repr : clip_data->representations) {
     const std::string& mime_type(repr->mime_type);
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 7e3163b..4283808 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -38,6 +38,7 @@
 #include "components/autofill/core/browser/metrics/form_events.h"
 #include "components/autofill/core/browser/mock_autocomplete_history_manager.h"
 #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
+#include "components/autofill/core/browser/payments/test_credit_card_save_strike_database.h"
 #include "components/autofill/core/browser/payments/test_payments_client.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
@@ -373,6 +374,11 @@
         /*call_parent_methods=*/false);
     autofill_manager_->SetExternalDelegate(external_delegate_.get());
 
+    std::unique_ptr<TestStrikeDatabase> test_strike_database =
+        std::make_unique<TestStrikeDatabase>();
+    strike_database_ = test_strike_database.get();
+    autofill_client_.set_test_strike_database(std::move(test_strike_database));
+
     // Initialize the TestPersonalDataManager with some default data.
     CreateTestAutofillProfiles();
     CreateTestCreditCards();
@@ -633,6 +639,7 @@
   TestPersonalDataManager personal_data_;
   std::unique_ptr<MockAutocompleteHistoryManager> autocomplete_history_manager_;
   base::test::ScopedFeatureList scoped_feature_list_;
+  TestStrikeDatabase* strike_database_;
 
  private:
   int ToHistogramSample(AutofillMetrics::CardUploadDecisionMetric metric) {
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
index 8798b03..fe9c470 100644
--- a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
@@ -476,6 +476,9 @@
   histogram_tester.ExpectTotalCount("Autofill.CardUploadDecisionMetric", 0);
 }
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) {
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -535,6 +538,7 @@
       payments_client_->addresses_in_upload_card(),
       testing::UnorderedElementsAreArray({*personal_data_.GetProfiles()[0]}));
 }
+#endif
 
 // Tests metrics for SaveCardWithFirstAndLastNameComplete for local cards.
 TEST_F(CreditCardSaveManagerTest, LocalCreditCard_FirstAndLastName) {
@@ -675,6 +679,9 @@
 }
 
 // Tests metrics for supporting unfocused card form.
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_WithNonFocusableField) {
   credit_card_save_manager_->SetCreditCardUploadEnabled(true);
 
@@ -718,6 +725,7 @@
       AutofillMetrics::UPLOAD_OFFERED |
       AutofillMetrics::UPLOAD_OFFERED_FROM_NON_FOCUSABLE_FIELD);
 }
+#endif
 
 // Tests local card save will still work as usual when supporting unfocused card
 // form feature is already on.
@@ -1094,6 +1102,9 @@
 
 // Tests that a credit card inferred from a form with a credit card first and
 // last name can be uploaded.
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FirstAndLastName) {
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1142,10 +1153,14 @@
   histogram_tester.ExpectTotalCount(
       "Autofill.SaveCardWithFirstAndLastNameComplete.Server", 1);
 }
+#endif
 
 // Tests that a credit card inferred from a form with a credit card first and
 // last name can be uploaded when the last name comes before first name on the
 // form.
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LastAndFirstName) {
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1216,6 +1231,7 @@
   histogram_tester.ExpectTotalCount(
       "Autofill.SaveCardWithFirstAndLastNameComplete.Server", 1);
 }
+#endif
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NotSavedLocally) {
   personal_data_.ClearCreditCards();
@@ -1289,6 +1305,9 @@
   histogram_tester.ExpectTotalCount("Autofill.CardUploadDecisionMetric", 0);
 }
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) {
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1329,7 +1348,11 @@
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED |
                               AutofillMetrics::CVC_VALUE_NOT_FOUND);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) {
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1367,7 +1390,11 @@
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED |
                               AutofillMetrics::INVALID_CVC_VALUE);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) {
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1422,7 +1449,11 @@
   // Verify that the correct UKM was logged.
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) {
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1474,7 +1505,11 @@
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED |
                               AutofillMetrics::CVC_FIELD_NOT_FOUND);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_NoCvcFieldOnForm_InvalidCvcInNonCvcField) {
   // Create, fill and submit an address form in order to establish a recent
@@ -1530,7 +1565,11 @@
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED |
                               AutofillMetrics::CVC_FIELD_NOT_FOUND);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_NoCvcFieldOnForm_CvcInNonCvcField) {
   // Create, fill and submit an address form in order to establish a recent
@@ -1588,7 +1627,11 @@
       AutofillMetrics::UPLOAD_OFFERED |
       AutofillMetrics::FOUND_POSSIBLE_CVC_VALUE_IN_NON_CVC_FIELD);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_NoCvcFieldOnForm_CvcInAddressField) {
   // Create, fill and submit an address form in order to establish a recent
@@ -1644,7 +1687,11 @@
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED |
                               AutofillMetrics::CVC_FIELD_NOT_FOUND);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) {
   // Don't fill or submit an address form.
 
@@ -1677,7 +1724,11 @@
       AutofillMetrics::UPLOAD_OFFERED |
       AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS_PROFILE);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoRecentlyUsedProfile) {
   // Create the test clock and set the time to a specific value.
   TestAutofillClock test_clock;
@@ -1724,7 +1775,11 @@
       AutofillMetrics::UPLOAD_OFFERED |
       AutofillMetrics::UPLOAD_NOT_OFFERED_NO_RECENTLY_USED_ADDRESS);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_CvcUnavailableAndNoProfileAvailable) {
   // Don't fill or submit an address form.
@@ -1760,7 +1815,11 @@
       AutofillMetrics::UPLOAD_OFFERED | AutofillMetrics::CVC_VALUE_NOT_FOUND |
       AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ADDRESS_PROFILE);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoNameAvailable) {
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1803,7 +1862,11 @@
       AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME |
       AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_NoNameAvailableAndNoProfileAvailable) {
   // Don't fill or submit an address form.
@@ -1843,7 +1906,11 @@
       AutofillMetrics::UPLOAD_NOT_OFFERED_NO_NAME |
       AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) {
   // Create, fill and submit two address forms with different zip codes.
   FormData address_form1, address_form2;
@@ -1892,7 +1959,11 @@
       AutofillMetrics::UPLOAD_OFFERED |
       AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_ZIPS);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_ZipCodesDoNotDiscardWhitespace) {
   // Create two separate profiles with different zip codes. Must directly add
@@ -1940,7 +2011,11 @@
       AutofillMetrics::UPLOAD_OFFERED |
       AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_ZIPS);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) {
   // Create, fill and submit two address forms with different zip codes.
   FormData address_form1, address_form2;
@@ -1983,7 +2058,11 @@
   // Verify that the correct UKM was logged.
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) {
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -2028,7 +2107,11 @@
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED |
                               AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) {
   // Create, fill and submit two address forms with different names.
   FormData address_form1, address_form2;
@@ -2070,7 +2153,11 @@
   // Verify that the correct UKM was logged.
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) {
   // Create, fill and submit two address forms with different names.
   FormData address_form1, address_form2;
@@ -2109,7 +2196,11 @@
   // Verify that the correct UKM was logged.
   ExpectCardUploadDecisionUkm(AutofillMetrics::UPLOAD_OFFERED);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_CCFormHasCardholderMiddleName) {
   // Create, fill and submit address form without middle name.
@@ -2152,7 +2243,11 @@
       AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES |
       AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasAddressMiddleName) {
   // Create, fill and submit address form with middle name.
   FormData address_form;
@@ -2194,7 +2289,11 @@
       AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES |
       AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NamesCanMismatch) {
   // Create, fill and submit two address forms with different names.
   FormData address_form1, address_form2;
@@ -2245,7 +2344,11 @@
       AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_NAMES |
       AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_IgnoreOldProfiles) {
   // Create the test clock and set the time to a specific value.
   TestAutofillClock test_clock;
@@ -2290,6 +2393,7 @@
   ExpectUniqueCardUploadDecision(histogram_tester,
                                  AutofillMetrics::UPLOAD_OFFERED);
 }
+#endif
 
 TEST_F(
     CreditCardSaveManagerTest,
@@ -2440,6 +2544,9 @@
 TEST_F(
     CreditCardSaveManagerTest,
     UploadCreditCard_DoNotRequestCardholderNameIfNameExistsAndNoPaymentsCustomer) {
+// On iOS the cardholder name fix flow and expiration date fix flow no longer
+// apply since the user is forced to always set correct data before submitting.
+#if !defined(OS_IOS)
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
   FormData address_form;
@@ -2473,11 +2580,16 @@
       AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
   EXPECT_FALSE(payments_client_->detected_values_in_upload_details() &
                CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
+#endif
 }
 
 TEST_F(
     CreditCardSaveManagerTest,
     UploadCreditCard_DoNotRequestCardholderNameIfNameMissingAndPaymentsCustomer) {
+  // On iOS the cardholder name fix flow and expiration date fix flow no longer
+  // apply since the user is forced to always set correct data before
+  // submitting.
+#if !defined(OS_IOS)
   // Set the billing_customer_number to designate existence of a Payments
   // account.
   personal_data_.SetPaymentsCustomerData(
@@ -2518,11 +2630,16 @@
       AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
   EXPECT_FALSE(payments_client_->detected_values_in_upload_details() &
                CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
+#endif
 }
 
 TEST_F(
     CreditCardSaveManagerTest,
     UploadCreditCard_DoNotRequestCardholderNameIfNameConflictingAndPaymentsCustomer) {
+  // On iOS the cardholder name fix flow and expiration date fix flow no longer
+  // apply since the user is forced to always set correct data before
+  // submitting.
+#if !defined(OS_IOS)
   // Set the billing_customer_number to designate existence of a Payments
   // account.
   personal_data_.SetPaymentsCustomerData(
@@ -2563,6 +2680,7 @@
       AutofillMetrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
   EXPECT_FALSE(payments_client_->detected_values_in_upload_details() &
                CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
+#endif
 }
 
 // This test ensures |should_request_name_from_user_| is reset between offers to
@@ -2570,6 +2688,10 @@
 TEST_F(
     CreditCardSaveManagerTest,
     UploadCreditCard_ShouldRequestCardholderName_ResetBetweenConsecutiveSaves) {
+  // On iOS the cardholder name fix flow and expiration date fix flow no longer
+  // apply since the user is forced to always set correct data before
+  // submitting.
+#if !defined(OS_IOS)
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
   FormData address_form;
@@ -2612,6 +2734,7 @@
 
   // Verify the |credit_card_save_manager_| is NOT requesting cardholder name.
   EXPECT_FALSE(credit_card_save_manager_->should_request_name_from_user_);
+#endif
 }
 
 // This test ensures |should_request_expiration_date_from_user_|
@@ -2619,6 +2742,10 @@
 TEST_F(
     CreditCardSaveManagerTest,
     UploadCreditCard_ShouldRequestExpirationDate_ResetBetweenConsecutiveSaves) {
+  // On iOS the cardholder name fix flow and expiration date fix flow no longer
+  // apply since the user is forced to always set correct data before
+  // submitting.
+#if !defined(OS_IOS)
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
   FormData address_form;
@@ -2660,6 +2787,7 @@
   // Verify the |credit_card_save_manager_| is NOT requesting expiration date.
   EXPECT_FALSE(
       credit_card_save_manager_->should_request_expiration_date_from_user_);
+#endif
 }
 
 // This test ensures |should_request_expiration_date_from_user_|
@@ -2667,6 +2795,10 @@
 TEST_F(
     CreditCardSaveManagerTest,
     UploadCreditCard_WalletSyncTransportEnabled_ShouldNotRequestExpirationDate) {
+  // On iOS the cardholder name fix flow and expiration date fix flow no longer
+  // apply since the user is forced to always set correct data before
+  // submitting.
+#if !defined(OS_IOS)
   // Wallet Sync Transport is enabled.
   personal_data_.SetSyncAndSignInState(
       AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled);
@@ -2691,11 +2823,13 @@
   credit_card_form.fields[3].value = ASCIIToUTF16("");
   credit_card_form.fields[4].value = ASCIIToUTF16("123");
 
+  FormSubmitted(credit_card_form);
+
   // Save should not be offered because implicit Sync + Expiration date fix flow
   // aborts offering save
-  FormSubmitted(credit_card_form);
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded());
+#endif
 }
 
 // This test ensures |should_request_expiration_date_from_user_|
@@ -2703,6 +2837,10 @@
 TEST_F(
     CreditCardSaveManagerTest,
     UploadCreditCard_WalletSyncTransportNotEnabled_ShouldRequestExpirationDate) {
+  // On iOS the cardholder name fix flow and expiration date fix flow no longer
+  // apply since the user is forced to always set correct data before
+  // submitting.
+#if !defined(OS_IOS)
   // Wallet Sync Transport is not enabled.
   personal_data_.SetSyncAndSignInState(
       AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled);
@@ -2736,11 +2874,16 @@
   // Verify the |credit_card_save_manager_| is requesting expiration date.
   EXPECT_TRUE(
       credit_card_save_manager_->should_request_expiration_date_from_user_);
+#endif
 }
 
 TEST_F(
     CreditCardSaveManagerTest,
     UploadCreditCard_DoNotRequestExpirationDateIfMissingNameAndExpirationDate) {
+  // On iOS the cardholder name fix flow and expiration date fix flow no longer
+  // apply since the user is forced to always set correct data before
+  // submitting.
+#if !defined(OS_IOS)
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
   FormData address_form;
@@ -2767,6 +2910,46 @@
   FormSubmitted(credit_card_form);
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded());
+#endif
+}
+
+// iOS should always provide a valid expiration date when attempting to
+// upload a Saved Card due to the Messages SaveCard modal.
+TEST_F(CreditCardSaveManagerTest,
+       UploadCreditCard_AlwaysRequestCardholderNameAndExpirationDateOnIOS) {
+#if defined(OS_IOS)
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, CreditCardFormOptions());
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, and submit.
+  credit_card_form.fields[0].value = ASCIIToUTF16("");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
+  credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+  base::HistogramTester histogram_tester;
+
+  FormSubmitted(credit_card_form);
+  EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
+  EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
+  EXPECT_TRUE(
+      payments_client_->detected_values_in_upload_details() &
+      CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
+  EXPECT_TRUE(payments_client_->detected_values_in_upload_details() &
+              CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
+
+#endif
 }
 
 TEST_F(CreditCardSaveManagerTest,
@@ -3030,6 +3213,9 @@
       CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
 }
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadDetailsFails) {
   // Anything other than "en-US" will cause GetUploadDetails to return a failure
   // response.
@@ -3070,6 +3256,7 @@
   ExpectCardUploadDecisionUkm(
       AutofillMetrics::UPLOAD_NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED);
 }
+#endif
 
 TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard_NoUpload) {
   // Create, fill and submit an address form in order to establish a recent
@@ -3595,6 +3782,9 @@
             expected_detected_values);
 }
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_LogAdditionalErrorsWithUploadDetailsFailure) {
   // Anything other than "en-US" will cause GetUploadDetails to return a failure
@@ -3649,6 +3839,7 @@
                UkmCardUploadDecisionType::kEntryName, upload_decision,
                1 /* expected_num_matching_entries */);
 }
+#endif
 
 TEST_F(
     CreditCardSaveManagerTest,
@@ -3777,6 +3968,9 @@
   EXPECT_FALSE(credit_card_save_manager_->CreditCardWasUploaded());
 }
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_PaymentsDecidesOfferToSaveIfNoCvc) {
   // Create, fill and submit an address form in order to establish a recent
@@ -3818,7 +4012,11 @@
       AutofillMetrics::UPLOAD_OFFERED | AutofillMetrics::CVC_VALUE_NOT_FOUND,
       1 /* expected_num_matching_entries */);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_PaymentsDecidesOfferToSaveIfNoName) {
   // Create, fill and submit an address form in order to establish a recent
@@ -3866,7 +4064,11 @@
                UkmCardUploadDecisionType::kEntryName, upload_decision,
                1 /* expected_num_matching_entries */);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_PaymentsDecidesOfferToSaveIfConflictingNames) {
   // Create, fill and submit an address form in order to establish a recent
@@ -3913,7 +4115,11 @@
                UkmCardUploadDecisionType::kEntryName, upload_decision,
                1 /* expected_num_matching_entries */);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_PaymentsDecidesOfferToSaveIfNoZip) {
   // Set up a new address profile without a postal code.
@@ -3957,7 +4163,11 @@
                    AutofillMetrics::UPLOAD_NOT_OFFERED_NO_ZIP_CODE,
                1 /* expected_num_matching_entries */);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_PaymentsDecidesOfferToSaveIfConflictingZips) {
   // Set up two new address profiles with conflicting postal codes.
@@ -4013,7 +4223,11 @@
                    AutofillMetrics::UPLOAD_NOT_OFFERED_CONFLICTING_ZIPS,
                1 /* expected_num_matching_entries */);
 }
+#endif
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_PaymentsDecidesOfferToSaveIfNothingFound) {
   // Set up a new address profile without a name or postal code.
@@ -4066,6 +4280,7 @@
                UkmCardUploadDecisionType::kEntryName, upload_decision,
                1 /* expected_num_matching_entries */);
 }
+#endif
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadOfLocalCard) {
   // Add a local credit card whose |TypeAndLastFourDigits| matches what we will
@@ -4425,6 +4640,9 @@
       AutofillMetrics::SaveTypeMetric::LOCAL, 1);
 }
 
+// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
+// permanently if the test doesn't apply to iOS flow.
+#if !defined(OS_IOS)
 // Tests that a card with max strikes does not offer save on mobile at all.
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) {
   TestCreditCardSaveStrikeDatabase credit_card_save_strike_database =
@@ -4477,6 +4695,7 @@
   ExpectCardUploadDecisionUkm(
       AutofillMetrics::UPLOAD_NOT_OFFERED_MAX_STRIKES_ON_MOBILE);
 }
+#endif
 
 #else  // !defined(OS_ANDROID) && !defined(OS_IOS)
 // Tests that a card with max strikes should still offer to save on Desktop via
diff --git a/components/autofill/core/browser/ui/accessory_sheet_enums.h b/components/autofill/core/browser/ui/accessory_sheet_enums.h
index 97a2cbf5..a6d5fa1 100644
--- a/components/autofill/core/browser/ui/accessory_sheet_enums.h
+++ b/components/autofill/core/browser/ui/accessory_sheet_enums.h
@@ -37,6 +37,7 @@
   MANAGE_ADDRESSES = 4,
   GENERATE_PASSWORD_MANUAL = 5,
   TOGGLE_SAVE_PASSWORDS = 6,
+  USE_OTHER_PASSWORD = 7,
   COUNT,
 };
 
diff --git a/components/browser_sync/PRESUBMIT.py b/components/browser_sync/PRESUBMIT.py
index e7128a2..6d8aa48 100644
--- a/components/browser_sync/PRESUBMIT.py
+++ b/components/browser_sync/PRESUBMIT.py
@@ -14,7 +14,7 @@
 
 def CheckChangeLintsClean(input_api, output_api):
   source_filter = lambda x: input_api.FilterSourceFile(
-    x, white_list=BROWSER_SYNC_SOURCE_FILES, black_list=None)
+    x, files_to_check=BROWSER_SYNC_SOURCE_FILES, files_to_skip=None)
   return input_api.canned_checks.CheckChangeLintsClean(
       input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
 
diff --git a/components/country_codes/README.md b/components/country_codes/README.md
new file mode 100644
index 0000000..7ae597aa
--- /dev/null
+++ b/components/country_codes/README.md
@@ -0,0 +1,3 @@
+The country codes component deals with 2-letter country codes (aka ISO 3166-1).
+Its primary purpose is to interface with platform-specific functionality to
+provide a unified API to find out "what is the system's current country code".
diff --git a/components/cronet/PRESUBMIT.py b/components/cronet/PRESUBMIT.py
index 3c02298..1c940c4 100644
--- a/components/cronet/PRESUBMIT.py
+++ b/components/cronet/PRESUBMIT.py
@@ -49,7 +49,7 @@
   impl_package_pattern = input_api.re.compile(r'^package org.chromium.net;')
 
   source_filter = lambda path: input_api.FilterSourceFile(path,
-      white_list=[r'^components/cronet/android/.*\.(java|template)$'])
+      files_to_check=[r'^components/cronet/android/.*\.(java|template)$'])
 
   problems = []
   for f in input_api.AffectedSourceFiles(source_filter):
diff --git a/components/exo/seat.cc b/components/exo/seat.cc
index 5a19ee3..022dd31 100644
--- a/components/exo/seat.cc
+++ b/components/exo/seat.cc
@@ -4,6 +4,8 @@
 
 #include "components/exo/seat.h"
 
+#include <memory>
+
 #if defined(OS_CHROMEOS)
 #include "ash/shell.h"
 #endif  // defined(OS_CHROMEOS)
@@ -24,7 +26,9 @@
 #include "components/exo/wm_helper.h"
 #include "services/data_decoder/public/cpp/decode_image.h"
 #include "ui/aura/client/focus_client.h"
+#include "ui/base/clipboard/clipboard_data_endpoint.h"
 #include "ui/base/clipboard/clipboard_monitor.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/events/event_utils.h"
 #include "ui/events/platform/platform_event_source.h"
 
@@ -108,8 +112,7 @@
   }
   selection_source_ = std::make_unique<ScopedDataSource>(source, this);
   scoped_refptr<RefCountedScopedClipboardWriter> writer =
-      base::MakeRefCounted<RefCountedScopedClipboardWriter>(
-          ui::ClipboardBuffer::kCopyPaste);
+      base::MakeRefCounted<RefCountedScopedClipboardWriter>();
 
   base::RepeatingClosure data_read_callback = base::BarrierClosure(
       kMaxClipboardDataTypes,
@@ -128,6 +131,20 @@
       data_read_callback);
 }
 
+class Seat::RefCountedScopedClipboardWriter
+    : public ui::ScopedClipboardWriter,
+      public base::RefCounted<RefCountedScopedClipboardWriter> {
+ public:
+  explicit RefCountedScopedClipboardWriter()
+      : ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste,
+                              std::make_unique<ui::ClipboardDataEndpoint>(
+                                  ui::EndpointType::kVm)) {}
+
+ private:
+  friend class base::RefCounted<RefCountedScopedClipboardWriter>;
+  virtual ~RefCountedScopedClipboardWriter() = default;
+};
+
 void Seat::OnTextRead(scoped_refptr<RefCountedScopedClipboardWriter> writer,
                       base::OnceClosure callback,
                       const std::string& mime_type,
diff --git a/components/exo/seat.h b/components/exo/seat.h
index e2b028ad..b9d9f06b 100644
--- a/components/exo/seat.h
+++ b/components/exo/seat.h
@@ -107,17 +107,7 @@
   }
 
  private:
-  class RefCountedScopedClipboardWriter
-      : public ui::ScopedClipboardWriter,
-        public base::RefCounted<RefCountedScopedClipboardWriter> {
-   public:
-    RefCountedScopedClipboardWriter(ui::ClipboardBuffer buffer)
-        : ScopedClipboardWriter(buffer) {}
-
-   private:
-    friend class base::RefCounted<RefCountedScopedClipboardWriter>;
-    virtual ~RefCountedScopedClipboardWriter() = default;
-  };
+  class RefCountedScopedClipboardWriter;
 
   // Called when data is read from FD passed from a client.
   // |data| is read data. |source| is source of the data, or nullptr if
diff --git a/components/exo/wayland/clients/blur.cc b/components/exo/wayland/clients/blur.cc
index bde71187..3b3cfe5f 100644
--- a/components/exo/wayland/clients/blur.cc
+++ b/components/exo/wayland/clients/blur.cc
@@ -184,9 +184,9 @@
       SkIRect subset;
       SkIPoint offset;
       sk_sp<SkImage> blur_image = content_surfaces.back()->makeImageSnapshot();
-      sk_sp<SkImage> blurred_image =
-          blur_image->makeWithFilter(blur_filter.get(), blur_image->bounds(),
-                                     blur_image->bounds(), &subset, &offset);
+      sk_sp<SkImage> blurred_image = blur_image->makeWithFilter(
+          gr_context_.get(), blur_filter.get(), blur_image->bounds(),
+          blur_image->bounds(), &subset, &offset);
       SkCanvas* canvas = buffer->sk_surface->getCanvas();
       canvas->save();
       SkSize size = SkSize::Make(size_.width(), size_.height());
diff --git a/components/google/README.md b/components/google/README.md
new file mode 100644
index 0000000..3b7ebe7e
--- /dev/null
+++ b/components/google/README.md
@@ -0,0 +1,10 @@
+The Google component deals with Google- (and Google-owned-property-)specific
+URLs and utilities.  This includes functions that determine if URLs are various
+types of Google URLs, getters for Google search URLs, and various URL
+manipulation functions.
+
+Since Chrome should serve users of all search engines, URLs, and products well,
+be hesitant before keying behavior to these functions.  Consider whether the
+proposed behavior would appear innocuous and appealing if you worked for a
+direct Google competitor, as well as whether you'd want a standardized mechanism
+for other sites to achieve the same results.
diff --git a/components/infobars/README b/components/infobars/README
deleted file mode 100644
index 8b736f1..0000000
--- a/components/infobars/README
+++ /dev/null
@@ -1,7 +0,0 @@
-- Infobars is a layered component
-(https://sites.google.com/a/chromium.org/dev/developers/design-documents/layered-components-design)
-to enable it to be shared cleanly on iOS.
-
-Directory structure:
-core/: shared code that does not depend on src/content/
-content/: Driver for the shared code based on the content layer.
diff --git a/components/infobars/README.md b/components/infobars/README.md
new file mode 100644
index 0000000..6c005f8
--- /dev/null
+++ b/components/infobars/README.md
@@ -0,0 +1,21 @@
+The infobars component contains the core types for infobars, a UI surface that
+shows informative but generally nonblocking updates to users related to their
+current page content.  This is used on both desktop and mobile, though the
+presentation and available infobars both differ.  On desktop, for example,
+infobars are a thin bar atop the page, while on Android an "infobar" is a
+larger, popup-like surface at screen bottom.
+
+Infobars are a problematic UI design for various reasons (spoofability,
+dynamically modifying content area size, not being visually anchored and scoped
+well), and are occasionally used for purposes outside their original intent
+(e.g. the "default browser" infobar, which does not relate to the page content).
+Be cautious about adding new ones.
+
+Infobars is a layered component
+(https://sites.google.com/a/chromium.org/dev/developers/design-documents/layered-components-design)
+to enable it to be shared cleanly on iOS.
+
+Directory structure:
+android/: Android-specific specializations
+core/: Shared code that does not depend on src/content/
+content/: Driver for the shared code based on the content layer
diff --git a/components/infobars/core/infobar_feature.cc b/components/infobars/core/infobar_feature.cc
index e64333d..0553d65 100644
--- a/components/infobars/core/infobar_feature.cc
+++ b/components/infobars/core/infobar_feature.cc
@@ -5,4 +5,4 @@
 #include "components/infobars/core/infobar_feature.h"
 
 const base::Feature kIOSInfobarUIReboot{"InfobarUIReboot",
-                                        base::FEATURE_DISABLED_BY_DEFAULT};
+                                        base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/location/android/java/src/org/chromium/components/location/LocationUtils.java b/components/location/android/java/src/org/chromium/components/location/LocationUtils.java
index 19978a2..ab5518a 100644
--- a/components/location/android/java/src/org/chromium/components/location/LocationUtils.java
+++ b/components/location/android/java/src/org/chromium/components/location/LocationUtils.java
@@ -13,8 +13,6 @@
 import android.os.Process;
 import android.provider.Settings;
 
-import androidx.annotation.VisibleForTesting;
-
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
@@ -153,7 +151,6 @@
      * Call this to use a different subclass of LocationUtils throughout the program.
      * This can be used by embedders in addition to tests.
      */
-    @VisibleForTesting
     public static void setFactory(Factory factory) {
         sFactory = factory;
         sInstance = null;
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h
index 7e9d19b..9ee8571 100644
--- a/components/omnibox/browser/autocomplete_controller.h
+++ b/components/omnibox/browser/autocomplete_controller.h
@@ -176,7 +176,9 @@
                            RedundantKeywordsIgnoredInResult);
   FRIEND_TEST_ALL_PREFIXES(AutocompleteProviderTest, UpdateAssistedQueryStats);
   FRIEND_TEST_ALL_PREFIXES(OmniboxPopupContentsViewTest,
-                           EmitTextChangedAccessibilityEvent);
+                           EmitAccessibilityEvents);
+  FRIEND_TEST_ALL_PREFIXES(OmniboxPopupContentsViewTest,
+                           EmitAccessibilityEventsOnButtonFocusHint);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewTest, DoesNotUpdateAutocompleteOnBlur);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, CloseOmniboxPopupOnTextDrag);
   FRIEND_TEST_ALL_PREFIXES(OmniboxViewViewsTest, FriendlyAccessibleLabel);
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index a90e884..76471877 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -1509,7 +1509,7 @@
     "Omnibox.CutOrCopyAllText";
 
 void OmniboxEditModel::SetAccessibilityLabel(const AutocompleteMatch& match) {
-  view_->SetAccessibilityLabel(view_->GetText(), match);
+  view_->SetAccessibilityLabel(view_->GetText(), match, true);
 }
 
 bool OmniboxEditModel::PopupIsOpen() const {
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc
index 6efe67e..4f5745f 100644
--- a/components/omnibox/browser/omnibox_popup_model.cc
+++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -588,6 +588,7 @@
 
 base::string16 OmniboxPopupModel::GetAccessibilityLabelForCurrentSelection(
     const base::string16& match_text,
+    bool include_positional_info,
     int* label_prefix_length) {
   size_t line = selection_.line;
   DCHECK_NE(line, kNoMatch)
@@ -636,10 +637,14 @@
       break;
   }
 
+  if (selection_.IsButtonFocused())
+    include_positional_info = false;
+
+  size_t total_matches = include_positional_info ? result().size() : 0;
+
   // If there's a button focused, we don't want the "n of m" message announced.
-  size_t total_matches = selection_.IsButtonFocused() ? 0 : result().size();
   return AutocompleteMatchType::ToAccessibilityLabel(
-      match, match_text, selection_.line, total_matches, additional_message_id,
+      match, match_text, line, total_matches, additional_message_id,
       label_prefix_length);
 }
 
diff --git a/components/omnibox/browser/omnibox_popup_model.h b/components/omnibox/browser/omnibox_popup_model.h
index 01eb9629..9d1f4f7d 100644
--- a/components/omnibox/browser/omnibox_popup_model.h
+++ b/components/omnibox/browser/omnibox_popup_model.h
@@ -249,6 +249,7 @@
   // Never call this when the current selection is kNoMatch.
   base::string16 GetAccessibilityLabelForCurrentSelection(
       const base::string16& match_text,
+      bool include_positional_info,
       int* label_prefix_length = nullptr);
 
  private:
diff --git a/components/omnibox/browser/omnibox_view.h b/components/omnibox/browser/omnibox_view.h
index e9b22e3..df7beb99 100644
--- a/components/omnibox/browser/omnibox_view.h
+++ b/components/omnibox/browser/omnibox_view.h
@@ -165,7 +165,8 @@
 
   // Updates the accessibility state by enunciating any on-focus text.
   virtual void SetAccessibilityLabel(const base::string16& display_text,
-                                     const AutocompleteMatch& match) {}
+                                     const AutocompleteMatch& match,
+                                     bool notify_text_changed) {}
 
   // Called when the temporary text in the model may have changed.
   // |display_text| is the new text to show; |match_type| is the type of the
diff --git a/components/password_manager/core/browser/credential_manager_impl.cc b/components/password_manager/core/browser/credential_manager_impl.cc
index 874b7f9..22da527 100644
--- a/components/password_manager/core/browser/credential_manager_impl.cc
+++ b/components/password_manager/core/browser/credential_manager_impl.cc
@@ -202,7 +202,10 @@
             ? CredentialType::CREDENTIAL_TYPE_PASSWORD
             : CredentialType::CREDENTIAL_TYPE_FEDERATED;
     info = CredentialInfo(*form, type_to_return);
-    if (PasswordStore* store = GetProfilePasswordStore()) {
+    PasswordStore* store = form->IsUsingAccountStore()
+                               ? GetAccountPasswordStore()
+                               : GetProfilePasswordStore();
+    if (store) {
       if (form->skip_zero_click && IsZeroClickAllowed()) {
         autofill::PasswordForm update_form = *form;
         update_form.skip_zero_click = false;
diff --git a/components/password_manager/core/browser/credential_manager_impl_unittest.cc b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index a1598ed4..a20567a 100644
--- a/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -1302,7 +1302,7 @@
   EXPECT_NE(CredentialType::CREDENTIAL_TYPE_EMPTY, credential_1->type);
 }
 
-TEST_P(CredentialManagerImplTest, ResetSkipZeroClickAfterPrompt) {
+TEST_P(CredentialManagerImplTest, ResetSkipZeroClickInProfileStoreAfterPrompt) {
   // Turn on the global zero-click flag, and add two credentials in separate
   // origins, both set to skip zero-click.
   client_->set_zero_click_enabled(true);
@@ -1351,6 +1351,92 @@
   EXPECT_TRUE(passwords[cross_origin_form_.signon_realm][0].skip_zero_click);
 }
 
+TEST_P(CredentialManagerImplTest, ResetSkipZeroClickInAccountStoreAfterPrompt) {
+  // This test is relevant only for account store users.
+  if (!GetParam())
+    return;
+  DCHECK(account_store_);
+  // This is simplified version of the test above that tests against the account
+  // store.
+  // Turn on the global zero-click flag, and add the credential for
+  // |kTestWebOrigin| and set to skip zero-click.
+  client_->set_zero_click_enabled(true);
+  form_.skip_zero_click = true;
+  account_store_->AddLogin(form_);
+
+  // Trigger a request which should return the credential found in |form_|, and
+  // wait for it to process.
+  // Check that the form in the database has been updated. `OnRequestCredential`
+  // generates a call to prompt the user to choose a credential.
+  // MockPasswordManagerClient mocks a user choice, and when users choose a
+  // credential (and have the global zero-click flag enabled), we make sure that
+  // they'll be logged in again next time.
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr)
+      .Times(testing::Exactly(1));
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+
+  bool called = false;
+  CredentialManagerError error;
+  base::Optional<CredentialInfo> credential;
+  CallGet(CredentialMediationRequirement::kOptional, true, /*federations=*/{},
+          base::BindOnce(&GetCredentialCallback, &called, &error, &credential));
+
+  RunAllPendingTasks();
+
+  TestPasswordStore::PasswordMap passwords = account_store_->stored_passwords();
+  ASSERT_EQ(1U, passwords.size());
+  ASSERT_EQ(1U, passwords[form_.signon_realm].size());
+  EXPECT_FALSE(passwords[form_.signon_realm][0].skip_zero_click);
+}
+
+TEST_P(CredentialManagerImplTest,
+       ResetSkipZeroClickInAccountStoreAfterPromptIfExistsInBothStores) {
+  // This test is relevant only for account store users.
+  if (!GetParam())
+    return;
+  DCHECK(account_store_);
+  // This is simplified version of the test above that tests against both the
+  // profile the account stores. When the same credential is stored in both
+  // stores, we favor the one in the account.
+
+  // Turn on the global zero-click flag, and add the credential for
+  // |kTestWebOrigin| , both set to skip zero-click on both stores.
+  client_->set_zero_click_enabled(true);
+  form_.skip_zero_click = true;
+  account_store_->AddLogin(form_);
+  store_->AddLogin(form_);
+
+  // Trigger a request which should return the credential found in |form_|, and
+  // wait for it to process.
+  // Check that the form in the database has been updated. `OnRequestCredential`
+  // generates a call to prompt the user to choose a credential.
+  // MockPasswordManagerClient mocks a user choice, and when users choose a
+  // credential (and have the global zero-click flag enabled), we make sure that
+  // they'll be logged in again next time.
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr)
+      .Times(testing::Exactly(1));
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+
+  bool called = false;
+  CredentialManagerError error;
+  base::Optional<CredentialInfo> credential;
+  CallGet(CredentialMediationRequirement::kOptional, true, /*federations=*/{},
+          base::BindOnce(&GetCredentialCallback, &called, &error, &credential));
+
+  RunAllPendingTasks();
+
+  // Only the one in the account store is affected.
+  TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
+  ASSERT_EQ(1U, passwords.size());
+  ASSERT_EQ(1U, passwords[form_.signon_realm].size());
+  EXPECT_TRUE(passwords[form_.signon_realm][0].skip_zero_click);
+
+  passwords = account_store_->stored_passwords();
+  ASSERT_EQ(1U, passwords.size());
+  ASSERT_EQ(1U, passwords[form_.signon_realm].size());
+  EXPECT_FALSE(passwords[form_.signon_realm][0].skip_zero_click);
+}
+
 TEST_P(CredentialManagerImplTest, IncognitoZeroClickRequestCredential) {
   EXPECT_CALL(*client_, IsIncognito()).WillRepeatedly(testing::Return(true));
   store_->AddLogin(form_);
diff --git a/components/password_manager/core/browser/form_parsing/form_parser.cc b/components/password_manager/core/browser/form_parsing/form_parser.cc
index c87a2f1..0acfce13 100644
--- a/components/password_manager/core/browser/form_parsing/form_parser.cc
+++ b/components/password_manager/core/browser/form_parsing/form_parser.cc
@@ -45,16 +45,6 @@
 constexpr char kAutocompleteCreditCardPrefix[] = "cc-";
 constexpr char kAutocompleteOneTimePassword[] = "one-time-code";
 
-// The susbset of autocomplete flags related to passwords.
-enum class AutocompleteFlag {
-  kNone,
-  kUsername,
-  kCurrentPassword,
-  kNewPassword,
-  // Represents the whole family of cc-* flags + OTP flag.
-  kNonPassword
-};
-
 // The autocomplete attribute has one of the following structures:
 //   [section-*] [shipping|billing] [type_hint] field_type
 //   on | off | false
@@ -89,42 +79,6 @@
   return AutocompleteFlag::kNone;
 }
 
-// How likely is user interaction for a given field?
-// Note: higher numeric values should match higher likeliness to allow using the
-// standard operator< for comparison of likeliness.
-enum class Interactability {
-  // When the field is invisible.
-  kUnlikely = 0,
-  // When the field is visible/focusable.
-  kPossible = 1,
-  // When the user actually typed into the field before.
-  kCertain = 2,
-};
-
-// A wrapper around FormFieldData, carrying some additional data used during
-// parsing.
-struct ProcessedField {
-  // This points to the wrapped FormFieldData.
-  const FormFieldData* field;
-
-  // The flag derived from field->autocomplete_attribute.
-  AutocompleteFlag autocomplete_flag = AutocompleteFlag::kNone;
-
-  // True if field->form_control_type == "password".
-  bool is_password = false;
-
-  // True if field is predicted to be a password.
-  bool is_predicted_as_password = false;
-
-  // True if the server predicts that this field is not a password field.
-  bool server_hints_not_password = false;
-
-  // True if the server predicts that this field is not a username field.
-  bool server_hints_not_username = false;
-
-  Interactability interactability = Interactability::kUnlikely;
-};
-
 // Returns true if the |str| contains words related to CVC fields.
 bool StringMatchesCVC(const base::string16& str) {
   static const base::NoDestructor<base::string16> kCardCvcReCached(
@@ -909,27 +863,6 @@
   return result;
 }
 
-// Find the first element in |username_predictions| (i.e. the most reliable
-// prediction) that occurs in |processed_fields| and has interactability level
-// at least |username_max|.
-const FormFieldData* FindUsernameInPredictions(
-    const std::vector<autofill::FieldRendererId>& username_predictions,
-    const std::vector<ProcessedField>& processed_fields,
-    Interactability username_max) {
-  for (autofill::FieldRendererId predicted_id : username_predictions) {
-    auto iter = std::find_if(
-        processed_fields.begin(), processed_fields.end(),
-        [predicted_id, username_max](const ProcessedField& processed_field) {
-          return processed_field.field->unique_renderer_id == predicted_id &&
-                 MatchesInteractability(processed_field, username_max);
-        });
-    if (iter != processed_fields.end()) {
-      return iter->field;
-    }
-  }
-  return nullptr;
-}
-
 // Return true if |significant_fields| has an username field and
 // |form_predictions| has |may_use_prefilled_placeholder| == true for the
 // username field.
@@ -1103,4 +1036,22 @@
   return url.ReplaceComponents(rep).spec();
 }
 
+const FormFieldData* FindUsernameInPredictions(
+    const std::vector<autofill::FieldRendererId>& username_predictions,
+    const std::vector<ProcessedField>& processed_fields,
+    Interactability username_max) {
+  for (autofill::FieldRendererId predicted_id : username_predictions) {
+    auto iter = std::find_if(
+        processed_fields.begin(), processed_fields.end(),
+        [predicted_id, username_max](const ProcessedField& processed_field) {
+          return processed_field.field->unique_renderer_id == predicted_id &&
+                 MatchesInteractability(processed_field, username_max);
+        });
+    if (iter != processed_fields.end()) {
+      return iter->field;
+    }
+  }
+  return nullptr;
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/form_parsing/form_parser.h b/components/password_manager/core/browser/form_parsing/form_parser.h
index a69e144..7f248ad 100644
--- a/components/password_manager/core/browser/form_parsing/form_parser.h
+++ b/components/password_manager/core/browser/form_parsing/form_parser.h
@@ -21,6 +21,52 @@
 
 namespace password_manager {
 
+// The susbset of autocomplete flags related to passwords.
+enum class AutocompleteFlag {
+  kNone,
+  kUsername,
+  kCurrentPassword,
+  kNewPassword,
+  // Represents the whole family of cc-* flags + OTP flag.
+  kNonPassword
+};
+
+// How likely is user interaction for a given field?
+// Note: higher numeric values should match higher likeliness to allow using the
+// standard operator< for comparison of likeliness.
+enum class Interactability {
+  // When the field is invisible.
+  kUnlikely = 0,
+  // When the field is visible/focusable.
+  kPossible = 1,
+  // When the user actually typed into the field before.
+  kCertain = 2,
+};
+
+// A wrapper around FormFieldData, carrying some additional data used during
+// parsing.
+struct ProcessedField {
+  // This points to the wrapped FormFieldData.
+  const autofill::FormFieldData* field;
+
+  // The flag derived from field->autocomplete_attribute.
+  AutocompleteFlag autocomplete_flag = AutocompleteFlag::kNone;
+
+  // True if field->form_control_type == "password".
+  bool is_password = false;
+
+  // True if field is predicted to be a password.
+  bool is_predicted_as_password = false;
+
+  // True if the server predicts that this field is not a password field.
+  bool server_hints_not_password = false;
+
+  // True if the server predicts that this field is not a username field.
+  bool server_hints_not_username = false;
+
+  Interactability interactability = Interactability::kUnlikely;
+};
+
 // This class takes care of parsing FormData into PasswordForm and managing
 // related metadata.
 class FormDataParser {
@@ -104,6 +150,14 @@
 // origin |url|.
 std::string GetSignonRealm(const GURL& url);
 
+// Find the first element in |username_predictions| (i.e. the most reliable
+// prediction) that occurs in |processed_fields| and has interactability level
+// at least |username_max|.
+const autofill::FormFieldData* FindUsernameInPredictions(
+    const std::vector<autofill::FieldRendererId>& username_predictions,
+    const std::vector<ProcessedField>& processed_fields,
+    Interactability username_max);
+
 }  // namespace password_manager
 
 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_PARSING_IOS_FORM_PARSER_H_
diff --git a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
index e05dd61..65dca71 100644
--- a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
+++ b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
@@ -2522,6 +2522,53 @@
   EXPECT_FALSE(parser.Parse(form_data, FormDataParser::Mode::kSaving));
 }
 
+TEST(FormParserTest, FindUsernameInPredictions_SkipPrediction) {
+  // Searching username field should skip prediction that is less
+  // likely to be user interaction. For example, if a field has no
+  // user input while others have, the field cannot be an username
+  // field.
+
+  // Create a form containing username, email, id, password, submit.
+  const FormParsingTestCase form_desc = {
+      .fields = {
+          {.name = "username", .form_control_type = "text"},
+          {.name = "email", .form_control_type = "text"},
+          {.name = "id", .form_control_type = "text"},
+          {.name = "password", .form_control_type = "password"},
+          {.name = "submit", .form_control_type = "submit"},
+      }};
+
+  FormPredictions no_predictions;
+  ParseResultIds dummy;
+  const FormData form_data =
+      GetFormDataAndExpectation(form_desc, &no_predictions, &dummy, &dummy);
+
+  // Add all form fields in ProcessedField. A user typed only into
+  // "id" and "password" fields. So, the prediction for "email" field
+  // should be ignored despite it is more reliable than prediction for
+  // "id" field.
+  std::vector<ProcessedField> processed_fields;
+  for (const auto& form_field_data : form_data.fields)
+    processed_fields.push_back(ProcessedField{.field = &form_field_data});
+
+  processed_fields[2].interactability = Interactability::kCertain;  // id
+  processed_fields[3].interactability = Interactability::kCertain;  // password
+
+  // Add predictions for "email" and "id" fields. The "email" is in
+  // front of "id", indicating "email" is more reliable.
+  const std::vector<autofill::FieldRendererId> predictions = {
+      form_data.fields[1].unique_renderer_id,  // email
+      form_data.fields[2].unique_renderer_id,  // id
+  };
+
+  // Now search the username field. The username field is supposed to
+  // be "id", not "email".
+  const autofill::FormFieldData* field_data = FindUsernameInPredictions(
+      predictions, processed_fields, Interactability::kCertain);
+  ASSERT_TRUE(field_data);
+  EXPECT_EQ(base::UTF8ToUTF16("id"), field_data->name);
+}
+
 }  // namespace
 
 }  // namespace password_manager
diff --git a/components/policy/android/java/src/org/chromium/policy/PolicyProvider.java b/components/policy/android/java/src/org/chromium/policy/PolicyProvider.java
index ad4f7d941..a626dd7 100644
--- a/components/policy/android/java/src/org/chromium/policy/PolicyProvider.java
+++ b/components/policy/android/java/src/org/chromium/policy/PolicyProvider.java
@@ -6,8 +6,6 @@
 
 import android.os.Bundle;
 
-import androidx.annotation.VisibleForTesting;
-
 import org.chromium.base.ThreadUtils;
 
 /**
@@ -24,9 +22,6 @@
         mCombinedPolicyProvider.onSettingsAvailable(mSource, settings);
     }
 
-    // Within Chromium only used in tests, although used in downstream code. @VisibleForTesting
-    // required to prevent removal by Proguard when building upstream.
-    @VisibleForTesting
     protected void terminateIncognitoSession() {
         mCombinedPolicyProvider.terminateIncognitoSession();
     }
diff --git a/components/policy/core/browser/policy_pref_mapping_test.cc b/components/policy/core/browser/policy_pref_mapping_test.cc
index 7dcdf70..14a5aa5a 100644
--- a/components/policy/core/browser/policy_pref_mapping_test.cc
+++ b/components/policy/core/browser/policy_pref_mapping_test.cc
@@ -359,7 +359,7 @@
     ASSERT_TRUE(policy_details);
     policy_map.Set(
         it.first, level, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
-        it.second.CreateDeepCopy(),
+        it.second.Clone(),
         policy_details->max_external_data_size
             ? std::make_unique<ExternalDataFetcher>(nullptr, it.first)
             : nullptr);
diff --git a/components/policy/core/common/async_policy_provider_unittest.cc b/components/policy/core/common/async_policy_provider_unittest.cc
index a9d618e2..7594fd225 100644
--- a/components/policy/core/common/async_policy_provider_unittest.cc
+++ b/components/policy/core/common/async_policy_provider_unittest.cc
@@ -34,8 +34,7 @@
                const std::string& value) {
   bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
       .Set(name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-           POLICY_SOURCE_PLATFORM, std::make_unique<base::Value>(value),
-           nullptr);
+           POLICY_SOURCE_PLATFORM, base::Value(value), nullptr);
 }
 
 class MockPolicyLoader : public AsyncPolicyLoader {
diff --git a/components/policy/core/common/cloud/component_cloud_policy_store.cc b/components/policy/core/common/cloud/component_cloud_policy_store.cc
index 1c39b22..4800bfbd 100644
--- a/components/policy/core/common/cloud/component_cloud_policy_store.cc
+++ b/components/policy/core/common/cloud/component_cloud_policy_store.cc
@@ -435,8 +435,7 @@
       level = POLICY_LEVEL_RECOMMENDED;
 
     policy->Set(policy_name, level, domain_constants_->scope, policy_source_,
-                base::Value::ToUniquePtrValue(std::move(value.value())),
-                nullptr);
+                std::move(value.value()), nullptr);
   }
 
   return true;
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.cc b/components/policy/core/common/cloud/user_cloud_policy_manager.cc
index 9384f98..4201a729 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_manager.cc
+++ b/components/policy/core/common/cloud/user_cloud_policy_manager.cc
@@ -114,8 +114,7 @@
       !policy_map->Get(key::kNTPContentSuggestionsEnabled)) {
     policy_map->Set(key::kNTPContentSuggestionsEnabled, POLICY_LEVEL_MANDATORY,
                     POLICY_SCOPE_USER, POLICY_SOURCE_ENTERPRISE_DEFAULT,
-                    std::make_unique<base::Value>(false),
-                    nullptr /* external_data_fetcher */);
+                    base::Value(false), nullptr /* external_data_fetcher */);
   }
 #endif
 }
diff --git a/components/policy/core/common/generate_policy_source_unittest.cc b/components/policy/core/common/generate_policy_source_unittest.cc
index 59de129..d7c75da 100644
--- a/components/policy/core/common/generate_policy_source_unittest.cc
+++ b/components/policy/core/common/generate_policy_source_unittest.cc
@@ -221,7 +221,7 @@
   // If policy already configured, it's not changed to enterprise defaults.
   policy_map.Set(key::kChromeOsMultiProfileUserBehavior, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
-                 std::make_unique<base::Value>("test_value"), nullptr);
+                 base::Value("test_value"), nullptr);
   SetEnterpriseUsersDefaults(&policy_map);
   multiprof_behavior =
       policy_map.GetValue(key::kChromeOsMultiProfileUserBehavior);
diff --git a/components/policy/core/common/legacy_chrome_policy_migrator_unittest.cc b/components/policy/core/common/legacy_chrome_policy_migrator_unittest.cc
index 2577ad0..f9cac88c 100644
--- a/components/policy/core/common/legacy_chrome_policy_migrator_unittest.cc
+++ b/components/policy/core/common/legacy_chrome_policy_migrator_unittest.cc
@@ -28,9 +28,7 @@
   *val = base::Value(val->GetInt() * 3);
 }
 
-void SetPolicy(PolicyMap* policy,
-               const char* policy_name,
-               std::unique_ptr<base::Value> value) {
+void SetPolicy(PolicyMap* policy, const char* policy_name, base::Value value) {
   policy->Set(policy_name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
               POLICY_SOURCE_CLOUD, std::move(value), nullptr);
 }
@@ -42,9 +40,8 @@
 
   PolicyMap& chrome_map = bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
 
-  SetPolicy(&chrome_map, kOldPolicy, std::make_unique<base::Value>(kOldValue));
-  SetPolicy(&chrome_map, kOtherPolicy,
-            std::make_unique<base::Value>(kOtherValue));
+  SetPolicy(&chrome_map, kOldPolicy, base::Value(kOldValue));
+  SetPolicy(&chrome_map, kOtherPolicy, base::Value(kOtherValue));
 
   LegacyChromePolicyMigrator migrator(kOldPolicy, kNewPolicy);
 
@@ -71,7 +68,7 @@
 
   PolicyMap& chrome_map = bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
 
-  SetPolicy(&chrome_map, kOldPolicy, std::make_unique<base::Value>(kOldValue));
+  SetPolicy(&chrome_map, kOldPolicy, base::Value(kOldValue));
 
   LegacyChromePolicyMigrator migrator(kOldPolicy, kNewPolicy,
                                       base::BindRepeating(&MultiplyByThree));
@@ -88,8 +85,8 @@
 
   PolicyMap& chrome_map = bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
 
-  SetPolicy(&chrome_map, kOldPolicy, std::make_unique<base::Value>(kOldValue));
-  SetPolicy(&chrome_map, kNewPolicy, std::make_unique<base::Value>(kNewValue));
+  SetPolicy(&chrome_map, kOldPolicy, base::Value(kOldValue));
+  SetPolicy(&chrome_map, kNewPolicy, base::Value(kNewValue));
 
   LegacyChromePolicyMigrator migrator(kOldPolicy, kNewPolicy);
 
diff --git a/components/policy/core/common/policy_bundle_unittest.cc b/components/policy/core/common/policy_bundle_unittest.cc
index 6625447e..09104ea 100644
--- a/components/policy/core/common/policy_bundle_unittest.cc
+++ b/components/policy/core/common/policy_bundle_unittest.cc
@@ -37,10 +37,10 @@
               POLICY_SOURCE_CLOUD, base::Value("omg"), nullptr);
   policy->Set("recommended-user", POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
               POLICY_SOURCE_CLOUD, base::Value(true), nullptr);
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-  dict->SetBoolean("false", false);
-  dict->SetInteger("int", 456);
-  dict->SetString("str", "bbq");
+  base::Value dict(base::Value::Type::DICTIONARY);
+  dict.SetBoolKey("false", false);
+  dict.SetIntKey("int", 456);
+  dict.SetStringKey("str", "bbq");
   policy->Set("recommended-machine", POLICY_LEVEL_RECOMMENDED,
               POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, std::move(dict),
               nullptr);
diff --git a/components/policy/core/common/policy_loader_ios.h b/components/policy/core/common/policy_loader_ios.h
index c04a579..ca4682c 100644
--- a/components/policy/core/common/policy_loader_ios.h
+++ b/components/policy/core/common/policy_loader_ios.h
@@ -40,9 +40,8 @@
   // Validates the given policy data against the stored |schema_|, converting
   // data to the expected type if necessary.  The returned value is suitable for
   // adding to a PolicyMap.
-  std::unique_ptr<base::Value> ConvertPolicyDataIfNecessary(
-      const std::string& key,
-      const base::Value& value);
+  base::Value ConvertPolicyDataIfNecessary(const std::string& key,
+                                           const base::Value& value);
 
   // The schema used by |ValidatePolicyData()|.
   const Schema* policy_schema_;
diff --git a/components/policy/core/common/policy_loader_ios.mm b/components/policy/core/common/policy_loader_ios.mm
index 36b57d8..8e58ebf 100644
--- a/components/policy/core/common/policy_loader_ios.mm
+++ b/components/policy/core/common/policy_loader_ios.mm
@@ -149,13 +149,13 @@
   }
 }
 
-std::unique_ptr<base::Value> PolicyLoaderIOS::ConvertPolicyDataIfNecessary(
+base::Value PolicyLoaderIOS::ConvertPolicyDataIfNecessary(
     const std::string& key,
     const base::Value& value) {
   const Schema schema = policy_schema_->GetKnownProperty(key);
 
   if (!schema.valid()) {
-    return value.CreateDeepCopy();
+    return value.Clone();
   }
 
   // Handle the case of a JSON-encoded string for a dict policy.
@@ -163,12 +163,12 @@
     base::Optional<base::Value> decoded_value = base::JSONReader::Read(
         value.GetString(), base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS);
     if (decoded_value.has_value()) {
-      return base::Value::ToUniquePtrValue(std::move(decoded_value.value()));
+      return std::move(decoded_value.value());
     }
   }
 
   // Otherwise return an unchanged value.
-  return value.CreateDeepCopy();
+  return value.Clone();
 }
 
 }  // namespace policy
diff --git a/components/policy/core/common/policy_loader_mac.mm b/components/policy/core/common/policy_loader_mac.mm
index bb19a66..7bbe6c5 100644
--- a/components/policy/core/common/policy_loader_mac.mm
+++ b/components/policy/core/common/policy_loader_mac.mm
@@ -134,7 +134,7 @@
     std::unique_ptr<base::Value> policy = PropertyToValue(value);
     if (policy) {
       chrome_policy.Set(it.key(), level, POLICY_SCOPE_MACHINE,
-                        POLICY_SOURCE_PLATFORM, std::move(policy), nullptr);
+                        POLICY_SOURCE_PLATFORM, std::move(*policy), nullptr);
     } else {
       status.Add(POLICY_LOAD_STATUS_PARSE_ERROR);
     }
@@ -234,7 +234,7 @@
     std::unique_ptr<base::Value> policy_value = PropertyToValue(value);
     if (policy_value) {
       policy->Set(it.key(), level, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
-                  std::move(policy_value), nullptr);
+                  std::move(*policy_value), nullptr);
     }
   }
 }
diff --git a/components/policy/core/common/policy_loader_mac_unittest.cc b/components/policy/core/common/policy_loader_mac_unittest.cc
index 846af796..1e5ea05 100644
--- a/components/policy/core/common/policy_loader_mac_unittest.cc
+++ b/components/policy/core/common/policy_loader_mac_unittest.cc
@@ -197,7 +197,7 @@
   expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
       .Set(test_keys::kKeyString, POLICY_LEVEL_RECOMMENDED,
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
-           std::make_unique<base::Value>("string value"), nullptr);
+           base::Value("string value"), nullptr);
   EXPECT_TRUE(provider_->policies().Equals(expected_bundle));
 }
 
diff --git a/components/policy/core/common/policy_map.cc b/components/policy/core/common/policy_map.cc
index 3fa33e9..8c8cb7d 100644
--- a/components/policy/core/common/policy_map.cc
+++ b/components/policy/core/common/policy_map.cc
@@ -217,19 +217,6 @@
     PolicyLevel level,
     PolicyScope scope,
     PolicySource source,
-    std::unique_ptr<base::Value> value,
-    std::unique_ptr<ExternalDataFetcher> external_data_fetcher) {
-  Entry entry(level, scope, source,
-              value ? base::make_optional(std::move(*value)) : base::nullopt,
-              std::move(external_data_fetcher));
-  Set(policy, std::move(entry));
-}
-
-void PolicyMap::Set(
-    const std::string& policy,
-    PolicyLevel level,
-    PolicyScope scope,
-    PolicySource source,
     base::Optional<base::Value> value,
     std::unique_ptr<ExternalDataFetcher> external_data_fetcher) {
   Entry entry(level, scope, source, std::move(value),
diff --git a/components/policy/core/common/policy_map.h b/components/policy/core/common/policy_map.h
index 5990345..9b07543 100644
--- a/components/policy/core/common/policy_map.h
+++ b/components/policy/core/common/policy_map.h
@@ -143,16 +143,6 @@
 
   // Overwrites any existing information stored in the map for the key |policy|.
   // Resets the error for that policy to the empty string.
-  // DEPRECATED: Use the other version that takes base::Optional<base::Value>
-  // below.
-  // TODO(crbug.com/1092469): Migrate the existing usages and delete this
-  // method.
-  void Set(const std::string& policy,
-           PolicyLevel level,
-           PolicyScope scope,
-           PolicySource source,
-           std::unique_ptr<base::Value> value,
-           std::unique_ptr<ExternalDataFetcher> external_data_fetcher);
   void Set(const std::string& policy,
            PolicyLevel level,
            PolicyScope scope,
diff --git a/components/policy/core/common/policy_service_impl.cc b/components/policy/core/common/policy_service_impl.cc
index 81dad68d..aeb346a 100644
--- a/components/policy/core/common/policy_service_impl.cc
+++ b/components/policy/core/common/policy_service_impl.cc
@@ -47,21 +47,19 @@
   // first, and then only policies with those exact attributes are merged.
   PolicyMap::Entry current_priority;  // Defaults to the lowest priority.
   PolicySource inherited_source = POLICY_SOURCE_ENTERPRISE_DEFAULT;
-  std::unique_ptr<base::DictionaryValue> proxy_settings(
-      new base::DictionaryValue);
+  base::Value proxy_settings(base::Value::Type::DICTIONARY);
   for (size_t i = 0; i < base::size(kProxyPolicies); ++i) {
     const PolicyMap::Entry* entry = policies->Get(kProxyPolicies[i]);
     if (entry) {
       if (entry->has_higher_priority_than(current_priority)) {
-        proxy_settings->Clear();
+        proxy_settings = base::Value(base::Value::Type::DICTIONARY);
         current_priority = entry->DeepCopy();
         if (entry->source > inherited_source)  // Higher priority?
           inherited_source = entry->source;
       }
       if (!entry->has_higher_priority_than(current_priority) &&
           !current_priority.has_higher_priority_than(*entry)) {
-        proxy_settings->Set(kProxyPolicies[i],
-                            entry->value()->CreateDeepCopy());
+        proxy_settings.SetKey(kProxyPolicies[i], entry->value()->Clone());
       }
       policies->Erase(kProxyPolicies[i]);
     }
@@ -69,7 +67,7 @@
   // Sets the new |proxy_settings| if kProxySettings isn't set yet, or if the
   // new priority is higher.
   const PolicyMap::Entry* existing = policies->Get(key::kProxySettings);
-  if (!proxy_settings->empty() &&
+  if (!proxy_settings.DictEmpty() &&
       (!existing || current_priority.has_higher_priority_than(*existing))) {
     policies->Set(key::kProxySettings, current_priority.level,
                   current_priority.scope, inherited_source,
diff --git a/components/policy/core/common/policy_statistics_collector_unittest.cc b/components/policy/core/common/policy_statistics_collector_unittest.cc
index 2d01549..d6fdb11 100644
--- a/components/policy/core/common/policy_statistics_collector_unittest.cc
+++ b/components/policy/core/common/policy_statistics_collector_unittest.cc
@@ -116,8 +116,7 @@
 
   void SetPolicy(const std::string& name) {
     policy_map_.Set(name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-                    POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(true),
-                    nullptr);
+                    POLICY_SOURCE_CLOUD, base::Value(true), nullptr);
   }
 
   void SetPolicyIgnoredByAtomicGroup(const std::string& name) {
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py
index 6d6c9ea..0fed66a 100755
--- a/components/policy/tools/generate_policy_source.py
+++ b/components/policy/tools/generate_policy_source.py
@@ -1009,17 +1009,17 @@
 
   |value|: The deserialized value to convert to base::Value."""
   if type(value) == bool or type(value) == int:
-    return [], 'std::make_unique<base::Value>(%s)' % json.dumps(value)
+    return [], 'base::Value(%s)' % json.dumps(value)
   elif type(value) == str:
-    return [], 'std::make_unique<base::Value>("%s")' % value
+    return [], 'base::Value("%s")' % value
   elif type(value) == list:
-    setup = ['auto default_value = std::make_unique<base::ListValue>();']
+    setup = ['base::Value default_value(base::Value::Type::LIST);']
     for entry in value:
       decl, fetch = _GenerateDefaultValue(entry)
       # Nested lists are not supported.
       if decl:
         return [], None
-      setup.append('default_value->Append(%s);' % fetch)
+      setup.append('default_value.Append(%s);' % fetch)
     return setup, 'std::move(default_value)'
   return [], None
 
diff --git a/components/sync/PRESUBMIT.py b/components/sync/PRESUBMIT.py
index d256b782..e5dcafa 100644
--- a/components/sync/PRESUBMIT.py
+++ b/components/sync/PRESUBMIT.py
@@ -370,7 +370,7 @@
 
 def CheckChangeLintsClean(input_api, output_api):
   source_filter = lambda x: input_api.FilterSourceFile(
-    x, white_list=SYNC_SOURCE_FILES, black_list=None)
+    x, files_to_check=SYNC_SOURCE_FILES, files_to_skip=None)
   return input_api.canned_checks.CheckChangeLintsClean(
       input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
 
diff --git a/components/sync_bookmarks/PRESUBMIT.py b/components/sync_bookmarks/PRESUBMIT.py
index ef269b0..ae36e52 100644
--- a/components/sync_bookmarks/PRESUBMIT.py
+++ b/components/sync_bookmarks/PRESUBMIT.py
@@ -15,7 +15,7 @@
 
 def CheckChangeLintsClean(input_api, output_api):
   source_filter = lambda x: input_api.FilterSourceFile(
-    x, white_list=SYNC_BOOKMARKS_SOURCE_FILES, black_list=None)
+    x, files_to_check=SYNC_BOOKMARKS_SOURCE_FILES, files_to_skip=None)
   return input_api.canned_checks.CheckChangeLintsClean(
       input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
 
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
index b3ec5b1..a92ed2d3 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -4,6 +4,7 @@
 
 #include "components/sync_bookmarks/bookmark_remote_updates_handler.h"
 
+#include <algorithm>
 #include <memory>
 #include <set>
 #include <string>
@@ -94,27 +95,40 @@
   }
 }
 
+syncer::UniquePosition ComputeUniquePositionForTrackedBookmarkNode(
+    const SyncedBookmarkTracker* bookmark_tracker,
+    const bookmarks::BookmarkNode* bookmark_node) {
+  DCHECK(bookmark_tracker);
+
+  const SyncedBookmarkTracker::Entity* child_entity =
+      bookmark_tracker->GetEntityForBookmarkNode(bookmark_node);
+  DCHECK(child_entity);
+  // TODO(crbug.com/1113139): precompute UniquePosition to prevent its
+  // calculation on each remote update.
+  return syncer::UniquePosition::FromProto(
+      child_entity->metadata()->unique_position());
+}
+
 size_t ComputeChildNodeIndex(const bookmarks::BookmarkNode* parent,
                              const sync_pb::UniquePosition& unique_position,
                              const SyncedBookmarkTracker* bookmark_tracker) {
-  // TODO(crbug.com/1084150): remove after investigations are completed.
-  TRACE_EVENT0("sync", "ComputeChildNodeIndex");
+  DCHECK(parent);
+  DCHECK(bookmark_tracker);
 
   const syncer::UniquePosition position =
       syncer::UniquePosition::FromProto(unique_position);
-  for (size_t i = 0; i < parent->children().size(); ++i) {
-    const bookmarks::BookmarkNode* child = parent->children()[i].get();
-    const SyncedBookmarkTracker::Entity* child_entity =
-        bookmark_tracker->GetEntityForBookmarkNode(child);
-    DCHECK(child_entity);
-    const syncer::UniquePosition child_position =
-        syncer::UniquePosition::FromProto(
-            child_entity->metadata()->unique_position());
-    if (position.LessThan(child_position)) {
-      return i;
-    }
-  }
-  return parent->children().size();
+
+  auto iter = std::partition_point(
+      parent->children().begin(), parent->children().end(),
+      [bookmark_tracker,
+       position](const std::unique_ptr<bookmarks::BookmarkNode>& child) {
+        // Return true for all |parent|'s children whose position is less than
+        // |position|.
+        return !position.LessThan(ComputeUniquePositionForTrackedBookmarkNode(
+            bookmark_tracker, child.get()));
+      });
+
+  return iter - parent->children().begin();
 }
 
 void ApplyRemoteUpdate(
@@ -429,6 +443,14 @@
 }
 
 // static
+size_t BookmarkRemoteUpdatesHandler::ComputeChildNodeIndexForTest(
+    const bookmarks::BookmarkNode* parent,
+    const sync_pb::UniquePosition& unique_position,
+    const SyncedBookmarkTracker* bookmark_tracker) {
+  return ComputeChildNodeIndex(parent, unique_position, bookmark_tracker);
+}
+
+// static
 std::vector<const syncer::UpdateResponseData*>
 BookmarkRemoteUpdatesHandler::ReorderUpdates(
     const syncer::UpdateResponseDataList* updates) {
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.h b/components/sync_bookmarks/bookmark_remote_updates_handler.h
index 6f71b9f..8b501ff 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.h
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.h
@@ -56,6 +56,11 @@
     return valid_updates_without_full_title_;
   }
 
+  static size_t ComputeChildNodeIndexForTest(
+      const bookmarks::BookmarkNode* parent,
+      const sync_pb::UniquePosition& unique_position,
+      const SyncedBookmarkTracker* bookmark_tracker);
+
  private:
   // Reorders incoming updates such that parent creation is before child
   // creation and child deletion is before parent deletion, and deletions should
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
index a927aec..26fed76 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -2035,6 +2035,94 @@
   EXPECT_TRUE(entity->has_final_guid());
 }
 
+TEST(BookmarkRemoteUpdatesHandlerTest,
+     ShouldComputeRightChildNodeIndexForEmptyParent) {
+  const std::string suffix = syncer::UniquePosition::RandomSuffix();
+  const syncer::UniquePosition pos1 =
+      syncer::UniquePosition::InitialPosition(suffix);
+
+  std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
+      bookmarks::TestBookmarkClient::CreateModel();
+  std::unique_ptr<SyncedBookmarkTracker> tracker =
+      SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
+          bookmark_model.get(),
+          CreateMetadataForPermanentNodes(bookmark_model.get()));
+
+  const bookmarks::BookmarkNode* bookmark_bar_node =
+      bookmark_model->bookmark_bar_node();
+
+  // Should always return 0 for any UniquePosition in the initial state.
+  EXPECT_EQ(0u, BookmarkRemoteUpdatesHandler::ComputeChildNodeIndexForTest(
+                    bookmark_bar_node, pos1.ToProto(), tracker.get()));
+}
+
+TEST(BookmarkRemoteUpdatesHandlerTest, ShouldComputeRightChildNodeIndex) {
+  std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
+      bookmarks::TestBookmarkClient::CreateModel();
+
+  const bookmarks::BookmarkNode* bookmark_bar_node =
+      bookmark_model->bookmark_bar_node();
+  const std::string suffix = syncer::UniquePosition::RandomSuffix();
+
+  const syncer::UniquePosition pos1 =
+      syncer::UniquePosition::InitialPosition(suffix);
+  const syncer::UniquePosition pos2 =
+      syncer::UniquePosition::After(pos1, suffix);
+  const syncer::UniquePosition pos3 =
+      syncer::UniquePosition::After(pos2, suffix);
+
+  // Create 3 nodes using remote update.
+  const bookmarks::BookmarkNode* node1 = bookmark_model->AddFolder(
+      bookmark_bar_node, /*index=*/0, /*title=*/base::string16());
+  const bookmarks::BookmarkNode* node2 = bookmark_model->AddFolder(
+      bookmark_bar_node, /*index=*/1, /*title=*/base::string16());
+  const bookmarks::BookmarkNode* node3 = bookmark_model->AddFolder(
+      bookmark_bar_node, /*index=*/2, /*title=*/base::string16());
+
+  sync_pb::BookmarkModelMetadata model_metadata =
+      CreateMetadataForPermanentNodes(bookmark_model.get());
+  *model_metadata.add_bookmarks_metadata() =
+      CreateNodeMetadata(node1->id(), "folder1_id", pos1);
+  *model_metadata.add_bookmarks_metadata() =
+      CreateNodeMetadata(node2->id(), "folder2_id", pos2);
+  *model_metadata.add_bookmarks_metadata() =
+      CreateNodeMetadata(node3->id(), "folder3_id", pos3);
+
+  std::unique_ptr<SyncedBookmarkTracker> tracker =
+      SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
+          bookmark_model.get(), std::move(model_metadata));
+
+  // Check for the same position as existing bookmarks have. In practice this
+  // shouldn't happen.
+  EXPECT_EQ(1u, BookmarkRemoteUpdatesHandler::ComputeChildNodeIndexForTest(
+                    bookmark_bar_node, pos1.ToProto(), tracker.get()));
+  EXPECT_EQ(2u, BookmarkRemoteUpdatesHandler::ComputeChildNodeIndexForTest(
+                    bookmark_bar_node, pos2.ToProto(), tracker.get()));
+  EXPECT_EQ(3u, BookmarkRemoteUpdatesHandler::ComputeChildNodeIndexForTest(
+                    bookmark_bar_node, pos3.ToProto(), tracker.get()));
+
+  EXPECT_EQ(0u, BookmarkRemoteUpdatesHandler::ComputeChildNodeIndexForTest(
+                    bookmark_bar_node,
+                    syncer::UniquePosition::Before(pos1, suffix).ToProto(),
+                    tracker.get()));
+  EXPECT_EQ(1u, BookmarkRemoteUpdatesHandler::ComputeChildNodeIndexForTest(
+                    bookmark_bar_node,
+                    syncer::UniquePosition::Between(/*before=*/pos1,
+                                                    /*after=*/pos2, suffix)
+                        .ToProto(),
+                    tracker.get()));
+  EXPECT_EQ(2u, BookmarkRemoteUpdatesHandler::ComputeChildNodeIndexForTest(
+                    bookmark_bar_node,
+                    syncer::UniquePosition::Between(/*before=*/pos2,
+                                                    /*after=*/pos3, suffix)
+                        .ToProto(),
+                    tracker.get()));
+  EXPECT_EQ(3u, BookmarkRemoteUpdatesHandler::ComputeChildNodeIndexForTest(
+                    bookmark_bar_node,
+                    syncer::UniquePosition::After(pos3, suffix).ToProto(),
+                    tracker.get()));
+}
+
 }  // namespace
 
 }  // namespace sync_bookmarks
diff --git a/components/sync_sessions/PRESUBMIT.py b/components/sync_sessions/PRESUBMIT.py
index 3768c7d7..f375bb6 100644
--- a/components/sync_sessions/PRESUBMIT.py
+++ b/components/sync_sessions/PRESUBMIT.py
@@ -14,7 +14,7 @@
 
 def CheckChangeLintsClean(input_api, output_api):
   source_filter = lambda x: input_api.FilterSourceFile(
-    x, white_list=SYNC_SESSIONS_SOURCE_FILES, black_list=None)
+    x, files_to_check=SYNC_SESSIONS_SOURCE_FILES, files_to_skip=None)
   return input_api.canned_checks.CheckChangeLintsClean(
       input_api, output_api, source_filter, lint_filters=[], verbose_level=1)
 
diff --git a/components/url_formatter/README.md b/components/url_formatter/README.md
new file mode 100644
index 0000000..bbe2582
--- /dev/null
+++ b/components/url_formatter/README.md
@@ -0,0 +1,15 @@
+The URL Formatter component contains utilities to convert between URLs and
+human-entered/human-readable strings.  Broadly, consuming human-entered URLs
+happens via "fixup", which tries to make "reasonable" adjustments to strings to
+convert them into URLs (e.g. auto-prepending schemes, but also many more, some
+of which may be surprising).  Producing human-readable URLs happens via
+"formatting", which can strip unimportant parts of the URL, unescape/decode
+sections, etc.
+
+These functions are meant to work in conjunction with the stricter, more limited
+capabilities of GURL, and were originally designed for use with the omnibox,
+though they've since been used in other parts of the UI as well.
+
+Because these functions are powerful, it's possible to introduce security risks
+with incautious use.  Be sure you understand what you need and what they're
+doing before using them; don't just copy existing callers.
diff --git a/components/webdata/README b/components/webdata/README
deleted file mode 100644
index a82334ca..0000000
--- a/components/webdata/README
+++ /dev/null
@@ -1,5 +0,0 @@
-WebData is not allowed to depend on content/, because it is used by iOS.
-If dependences on content/ need to be added to WebData, it will have to be made
-into a layered component: see
-http://www.chromium.org/developers/design-documents/layered-components-design
-for more information.
diff --git a/components/webdata/README.md b/components/webdata/README.md
new file mode 100644
index 0000000..88c6fb1
--- /dev/null
+++ b/components/webdata/README.md
@@ -0,0 +1,8 @@
+The webdata component manages the "web database", a SQLite database stored in
+the user's profile containing various webpage-related metadata such as autofill
+and web search engine data.
+
+This component is not allowed to depend on content/, because it is used by iOS.
+If dependencies on content/ need to be added, this component will have to be
+made into a layered component: see
+https://www.chromium.org/developers/design-documents/layered-components-design .
diff --git a/components/webdata_services/README.md b/components/webdata_services/README.md
new file mode 100644
index 0000000..11ecf5ee
--- /dev/null
+++ b/components/webdata_services/README.md
@@ -0,0 +1,5 @@
+The webdata services component contains the wrappers used to access the specific
+services built atop the web database (see //components/webdata/).  Because there
+is a single database instance, the various services accessing different tables
+are created and destroyed together, and this component is what does that tying
+together.
diff --git a/content/browser/DEPS b/content/browser/DEPS
index ba84fad..14481d50 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -113,7 +113,6 @@
   "+third_party/blink/public/platform/web_fullscreen_video_status.h",
   "+third_party/blink/public/platform/web_mixed_content_context_type.h",
   "+third_party/blink/public/common/widget/screen_info.h",
-  "+third_party/blink/public/platform/web_text_autosizer_page_info.h",
   "+third_party/blink/public/platform/web_text_input_type.h",
   "+third_party/blink/public/platform/mac/web_scrollbar_theme.h",
   "+third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h",
diff --git a/content/browser/accessibility/accessibility_event_recorder.h b/content/browser/accessibility/accessibility_event_recorder.h
index 6a9adf7..dfed6174 100644
--- a/content/browser/accessibility/accessibility_event_recorder.h
+++ b/content/browser/accessibility/accessibility_event_recorder.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/process/process_handle.h"
@@ -68,6 +69,8 @@
     callback_ = std::move(callback);
   }
 
+  void StopListeningToEvents() { callback_ = base::NullCallback(); }
+
   // Called to ensure the event recorder has finished recording async events.
   virtual void FlushAsyncEvents() {}
 
diff --git a/content/browser/accessibility/accessibility_tree_formatter_android.cc b/content/browser/accessibility/accessibility_tree_formatter_android.cc
index afeb78a..40ba95a 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_android.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_android.cc
@@ -89,6 +89,7 @@
   const std::string GetAllowString() override;
   const std::string GetDenyString() override;
   const std::string GetDenyNodeString() override;
+  const std::string GetRunUntilEventString() override;
 
   void RecursiveBuildAccessibilityTree(const BrowserAccessibility& node,
                                        base::DictionaryValue* dict) const;
@@ -324,4 +325,8 @@
   return "@ANDROID-DENY-NODE:";
 }
 
+const std::string AccessibilityTreeFormatterAndroid::GetRunUntilEventString() {
+  return "@ANDROID-RUN-UNTIL-EVENT:";
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc b/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
index 3266071..91f6ff6 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_auralinux.cc
@@ -36,6 +36,7 @@
   const std::string GetAllowString() override;
   const std::string GetDenyString() override;
   const std::string GetDenyNodeString() override;
+  const std::string GetRunUntilEventString() override;
 
   base::string16 ProcessTreeForOutput(
       const base::DictionaryValue& node,
@@ -747,4 +748,9 @@
   return "@AURALINUX-DENY-NODE:";
 }
 
+const std::string
+AccessibilityTreeFormatterAuraLinux::GetRunUntilEventString() {
+  return "@AURALINUX-RUN-UNTIL-EVENT:";
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.cc b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
index 8820306..2f5be04f 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_blink.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_blink.cc
@@ -632,4 +632,8 @@
   return "@BLINK-DENY-NODE:";
 }
 
+const std::string AccessibilityTreeFormatterBlink::GetRunUntilEventString() {
+  return "@BLINK-RUN-UNTIL-EVENT:";
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/accessibility_tree_formatter_blink.h b/content/browser/accessibility/accessibility_tree_formatter_blink.h
index 29f82df..440ced2e 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_blink.h
+++ b/content/browser/accessibility/accessibility_tree_formatter_blink.h
@@ -42,6 +42,7 @@
   const std::string GetAllowString() override;
   const std::string GetDenyString() override;
   const std::string GetDenyNodeString() override;
+  const std::string GetRunUntilEventString() override;
 
   void RecursiveBuildAccessibilityTree(const BrowserAccessibility& node,
                                        base::DictionaryValue* dict) const;
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
index 6074fd6..d4ff1fc0 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_mac.mm
+++ b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -110,6 +110,7 @@
   const std::string GetAllowString() override;
   const std::string GetDenyString() override;
   const std::string GetDenyNodeString() override;
+  const std::string GetRunUntilEventString() override;
 
   void AddProperties(const BrowserAccessibilityCocoa* node,
                      const LineIndexesMap& line_indexes_map,
@@ -817,6 +818,10 @@
   return "@MAC-DENY-NODE:";
 }
 
+const std::string AccessibilityTreeFormatterMac::GetRunUntilEventString() {
+  return "@MAC-RUN-UNTIL-EVENT:";
+}
+
 }  // namespace content
 
 #pragma clang diagnostic pop
diff --git a/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc b/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc
index b718114..b751a10e 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_uia_win.cc
@@ -1200,4 +1200,8 @@
   return "@UIA-WIN-DENY-NODE:";
 }
 
+const std::string AccessibilityTreeFormatterUia::GetRunUntilEventString() {
+  return "@UIA-WIN-RUN-UNTIL-EVENT:";
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/accessibility_tree_formatter_uia_win.h b/content/browser/accessibility/accessibility_tree_formatter_uia_win.h
index 45fbaaa..86c85f2 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_uia_win.h
+++ b/content/browser/accessibility/accessibility_tree_formatter_uia_win.h
@@ -100,6 +100,7 @@
   const std::string GetAllowString() override;
   const std::string GetDenyString() override;
   const std::string GetDenyNodeString() override;
+  const std::string GetRunUntilEventString() override;
   base::string16 ProcessTreeForOutput(
       const base::DictionaryValue& node,
       base::DictionaryValue* filtered_result = nullptr) override;
diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.cc b/content/browser/accessibility/accessibility_tree_formatter_win.cc
index cf876bc..f4f137e8 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -71,6 +71,7 @@
   const std::string GetAllowString() override;
   const std::string GetDenyString() override;
   const std::string GetDenyNodeString() override;
+  const std::string GetRunUntilEventString() override;
   void AddProperties(const Microsoft::WRL::ComPtr<IAccessible>,
                      base::DictionaryValue* dict,
                      LONG root_x,
@@ -1036,4 +1037,8 @@
   return "@WIN-DENY-NODE:";
 }
 
+const std::string AccessibilityTreeFormatterWin::GetRunUntilEventString() {
+  return "@WIN-RUN-UNTIL-EVENT:";
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index cd07323..e1db266 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -171,7 +171,7 @@
     const std::string& no_load_expected_str = "@NO-LOAD-EXPECTED:";
     const std::string& wait_str = "@WAIT-FOR:";
     const std::string& execute_str = "@EXECUTE-AND-WAIT-FOR:";
-    const std::string& until_str = "@RUN-UNTIL-EVENT:";
+    const std::string& until_str = formatter_->GetRunUntilEventString();
     const std::string& default_action_on_str = "@DEFAULT-ACTION-ON:";
     if (base::StartsWith(line, allow_empty_str, base::CompareCase::SENSITIVE)) {
       property_filters_.push_back(
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index d430f19..35b8f41 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -93,13 +93,18 @@
   void RunEventTest(const base::FilePath::CharType* file_path);
 
  private:
+  void OnEventRecorded(AccessibilityNotificationWaiter* waiter,
+                       const std::string& event) {
+    waiter->Quit();
+  }
+
   base::string16 initial_tree_;
   base::string16 final_tree_;
 };
 
 bool IsRecordingComplete(AccessibilityEventRecorder& event_recorder,
                          std::vector<std::string>& run_until) {
-  // If no @RUN-UNTIL-EVENT directives, then having any events is enough.
+  // If no @*-RUN-UNTIL-EVENT directives, then having any events is enough.
   LOG(ERROR) << "=== IsRecordingComplete#1 run_until size=" << run_until.size();
   if (run_until.empty())
     return true;
@@ -145,16 +150,27 @@
     waiter.reset(new AccessibilityNotificationWaiter(
         shell()->web_contents(), ui::kAXModeComplete, ax::mojom::Event::kNone));
 
+    // It's possible for platform events to be received after all blink or
+    // generated events have been fired. Unblock the |waiter| when this happens.
+    event_recorder->ListenToEvents(
+        base::BindRepeating(&DumpAccessibilityEventsTest::OnEventRecorded,
+                            base::Unretained(this), waiter.get()));
+
     base::Value go_results =
         ExecuteScriptAndGetValue(web_contents->GetMainFrame(), "go()");
     run_go_again = go_results.is_bool() && go_results.GetBool();
 
     for (;;) {
-      waiter->WaitForNotification();  // Run at least once.
+      // Wait for at least one event. This may unblock either when |waiter|
+      // observes either an ax::mojom::Event or ui::AXEventGenerator::Event, or
+      // when |event_recorder| records a platform event.
+      waiter->WaitForNotification();
       if (IsRecordingComplete(*event_recorder, run_until))
         break;
     }
 
+    event_recorder->StopListeningToEvents();
+
     // More than one accessibility event could have been generated.
     // To make sure we've received all accessibility events, add a
     // sentinel by calling SignalEndOfTest and waiting for a kEndOfTest
@@ -529,6 +545,22 @@
 }
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
+                       AccessibilityEventsAriaHiddenDescendants) {
+  RunEventTest(FILE_PATH_LITERAL("aria-hidden-descendants.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
+                       AccessibilityEventsAriaHiddenDescendantsAlreadyIgnored) {
+  RunEventTest(
+      FILE_PATH_LITERAL("aria-hidden-descendants-already-ignored.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
+                       AccessibilityEventsCSSDisplayDescendants) {
+  RunEventTest(FILE_PATH_LITERAL("css-display-descendants.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
                        AccessibilityEventsCSSFlexTextUpdate) {
   RunEventTest(FILE_PATH_LITERAL("css-flex-text-update.html"));
 }
@@ -539,6 +571,11 @@
 }
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
+                       AccessibilityEventsCSSVisibilityDescendants) {
+  RunEventTest(FILE_PATH_LITERAL("css-visibility-descendants.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
                        AccessibilityEventsCSSCollapse) {
   RunEventTest(FILE_PATH_LITERAL("css-visibility-collapse.html"));
 }
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 5a75e004..4d8877a4 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -346,6 +346,21 @@
 }
 
 // static
+void BrowserContext::FirePushSubscriptionChangeEvent(
+    BrowserContext* browser_context,
+    const GURL& origin,
+    int64_t service_worker_registration_id,
+    blink::mojom::PushSubscriptionPtr new_subscription,
+    blink::mojom::PushSubscriptionPtr old_subscription,
+    base::OnceCallback<void(blink::mojom::PushDeliveryStatus)> callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  PushMessagingRouter::FireSubscriptionChangeEvent(
+      browser_context, origin, service_worker_registration_id,
+      std::move(new_subscription), std::move(old_subscription),
+      std::move(callback));
+}
+
+// static
 void BrowserContext::NotifyWillBeDestroyed(BrowserContext* browser_context) {
   TRACE_EVENT1("shutdown", "BrowserContext::NotifyWillBeDestroyed",
                "browser_context", browser_context);
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index bd599f8..4d70646a0 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -218,6 +218,10 @@
   return std::string();
 }
 
+bool DevToolsAgentHostImpl::CanAccessOpener() {
+  return false;
+}
+
 std::string DevToolsAgentHostImpl::GetDescription() {
   return std::string();
 }
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 3e8e4a8..ac5abf76 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -40,6 +40,7 @@
       scoped_refptr<base::RefCountedMemory> data) override;
   std::string GetParentId() override;
   std::string GetOpenerId() override;
+  bool CanAccessOpener() override;
   std::string GetDescription() override;
   GURL GetFaviconURL() override;
   std::string GetFrontendURL() override;
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index ecb7483..cd06933 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -85,6 +85,7 @@
           .SetUrl(host->GetURL().spec())
           .SetType(host->GetType())
           .SetAttached(host->IsAttached())
+          .SetCanAccessOpener(host->CanAccessOpener())
           .Build();
   if (!host->GetOpenerId().empty())
     target_info->SetOpenerId(host->GetOpenerId());
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 33fb314..6b7d5286 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -668,6 +668,10 @@
   return opener ? opener->devtools_frame_token().ToString() : std::string();
 }
 
+bool RenderFrameDevToolsAgentHost::CanAccessOpener() {
+  return (frame_tree_node_ && frame_tree_node_->opener());
+}
+
 std::string RenderFrameDevToolsAgentHost::GetType() {
   if (web_contents() &&
       static_cast<WebContentsImpl*>(web_contents())->IsPortal()) {
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index 9bacadd..f366576 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -88,6 +88,7 @@
   WebContents* GetWebContents() override;
   std::string GetParentId() override;
   std::string GetOpenerId() override;
+  bool CanAccessOpener() override;
   std::string GetType() override;
   std::string GetTitle() override;
   std::string GetDescription() override;
diff --git a/content/browser/frame_host/ancestor_throttle.cc b/content/browser/frame_host/ancestor_throttle.cc
index 9b8c5e9..99910c1 100644
--- a/content/browser/frame_host/ancestor_throttle.cc
+++ b/content/browser/frame_host/ancestor_throttle.cc
@@ -188,24 +188,24 @@
     return NavigationThrottle::PROCEED;
   }
 
-  if (EvaluateXFrameOptions(logging) == CheckResult::BLOCK) {
-    return NavigationThrottle::BLOCK_RESPONSE;
-  }
-
-  // X-Frame-Option is checked on both redirect and final responses. However,
-  // CSP:Frame-ancestor is checked only for the final response.
-  if (!is_response_check)
-    return NavigationThrottle::PROCEED;
-
   const std::vector<network::mojom::ContentSecurityPolicyPtr>&
       content_security_policies =
           request->response()->parsed_headers->content_security_policy;
 
-  if (EvaluateFrameAncestors(content_security_policies) == CheckResult::BLOCK)
+  // CSP: frame-ancestors is checked only for the final response.
+  if (is_response_check &&
+      EvaluateFrameAncestors(content_security_policies) == CheckResult::BLOCK) {
+    return NavigationThrottle::BLOCK_RESPONSE;
+  }
+
+  if (EvaluateXFrameOptions(logging) == CheckResult::BLOCK)
     return NavigationThrottle::BLOCK_RESPONSE;
 
-  if (EvaluateCSPEmbeddedEnforcement() == CheckResult::BLOCK)
+  // CSPEE is checked only for the final response.
+  if (is_response_check &&
+      EvaluateCSPEmbeddedEnforcement() == CheckResult::BLOCK) {
     return NavigationThrottle::BLOCK_RESPONSE;
+  }
 
   return NavigationThrottle::PROCEED;
 }
diff --git a/content/browser/frame_host/clipboard_host_impl.cc b/content/browser/frame_host/clipboard_host_impl.cc
index cf0c987..e48ce21 100644
--- a/content/browser/frame_host/clipboard_host_impl.cc
+++ b/content/browser/frame_host/clipboard_host_impl.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/frame_host/clipboard_host_impl.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
@@ -332,8 +333,15 @@
 }
 
 void ClipboardHostImpl::CommitWrite() {
-  clipboard_writer_.reset(
-      new ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste));
+  std::unique_ptr<ui::ClipboardDataEndpoint> data_src;
+  RenderFrameHostImpl* render_frame_host =
+      RenderFrameHostImpl::FromID(render_frame_pid_, render_frame_routing_id_);
+  if (render_frame_host) {
+    data_src = std::make_unique<ui::ClipboardDataEndpoint>(
+        render_frame_host->GetLastCommittedURL());
+  }
+  clipboard_writer_ = std::make_unique<ui::ScopedClipboardWriter>(
+      ui::ClipboardBuffer::kCopyPaste, std::move(data_src));
 }
 
 void ClipboardHostImpl::PerformPasteIfAllowed(
diff --git a/content/browser/frame_host/raw_clipboard_host_impl.cc b/content/browser/frame_host/raw_clipboard_host_impl.cc
index 5f311fad5..9f1d3b7 100644
--- a/content/browser/frame_host/raw_clipboard_host_impl.cc
+++ b/content/browser/frame_host/raw_clipboard_host_impl.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/frame_host/raw_clipboard_host_impl.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/i18n/number_formatting.h"
 #include "content/browser/frame_host/clipboard_host_impl.h"
@@ -16,11 +18,25 @@
 #include "third_party/blink/public/mojom/clipboard/raw_clipboard.mojom.h"
 #include "third_party/blink/public/mojom/permissions/permission_status.mojom-shared.h"
 #include "ui/base/clipboard/clipboard.h"
+#include "ui/base/clipboard/clipboard_data_endpoint.h"
 #include "ui/base/clipboard/clipboard_format_type.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 
 namespace content {
 
+namespace {
+
+std::unique_ptr<ui::ClipboardDataEndpoint> CreateDataEndpoint(
+    RenderFrameHost* render_frame_host) {
+  if (render_frame_host)
+    return std::make_unique<ui::ClipboardDataEndpoint>(
+        render_frame_host->GetLastCommittedURL());
+
+  return nullptr;
+}
+
+}  // namespace
+
 void RawClipboardHostImpl::Create(
     RenderFrameHost* render_frame_host,
     mojo::PendingReceiver<blink::mojom::RawClipboardHost> receiver) {
@@ -80,7 +96,8 @@
     : receiver_(this, std::move(receiver)),
       clipboard_(ui::Clipboard::GetForCurrentThread()),
       clipboard_writer_(
-          new ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)),
+          new ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste,
+                                        CreateDataEndpoint(render_frame_host))),
       render_frame_host_(render_frame_host) {
   DCHECK(render_frame_host);
 }
@@ -152,8 +169,8 @@
 }
 
 void RawClipboardHostImpl::CommitWrite() {
-  clipboard_writer_.reset(
-      new ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste));
+  clipboard_writer_ = std::make_unique<ui::ScopedClipboardWriter>(
+      ui::ClipboardBuffer::kCopyPaste, CreateDataEndpoint(render_frame_host_));
 }
 
 bool RawClipboardHostImpl::HasTransientUserActivation() const {
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 7016b59..a8aab86 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -3036,19 +3036,16 @@
   // separated, it might be possible/desirable to just route to the view.
   DCHECK(!frame_tree_node_->parent());
 
-  if (frame_tree_node_->parent())
-    return;
-
   // When calling a PageBroadcast Mojo method for an inner WebContents, we don't
   // want to also call it for the outer WebContent's frame as well.
   RenderFrameProxyHost* outer_delegate_proxy =
       IsMainFrameForInnerDelegate() ? GetProxyToOuterDelegate() : nullptr;
   for (const auto& pair : proxy_hosts_) {
-    if (outer_delegate_proxy != pair.second.get()) {
-      if (pair.second->GetSiteInstance() == instance_to_skip)
-        continue;
-      callback.Run(pair.second->GetRenderViewHost());
-    }
+    if (outer_delegate_proxy == pair.second.get())
+      continue;
+    if (pair.second->GetSiteInstance() == instance_to_skip)
+      continue;
+    callback.Run(pair.second->GetRenderViewHost());
   }
 
   if (speculative_render_frame_host_ &&
@@ -3061,6 +3058,25 @@
   }
 }
 
+void RenderFrameHostManager::ExecuteRemoteFramesBroadcastMethod(
+    RemoteFramesBroadcastMethodCallback callback,
+    SiteInstance* instance_to_skip) {
+  DCHECK(!frame_tree_node_->parent());
+
+  // When calling a ExecuteRemoteFramesBroadcastMethod() for an inner
+  // WebContents, we don't want to also call it for the outer WebContent's
+  // frame as well.
+  RenderFrameProxyHost* outer_delegate_proxy =
+      IsMainFrameForInnerDelegate() ? GetProxyToOuterDelegate() : nullptr;
+  for (const auto& pair : proxy_hosts_) {
+    if (outer_delegate_proxy == pair.second.get())
+      continue;
+    if (pair.second->GetSiteInstance() == instance_to_skip)
+      continue;
+    callback.Run(pair.second.get());
+  }
+}
+
 void RenderFrameHostManager::EnsureRenderFrameHostVisibilityConsistent() {
   RenderWidgetHostView* view = GetRenderWidgetHostView();
   if (view && static_cast<RenderWidgetHostImpl*>(view->GetRenderWidgetHost())
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index 13da871..87e02bc 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -49,6 +49,9 @@
 using PageBroadcastMethodCallback =
     base::RepeatingCallback<void(RenderViewHostImpl*)>;
 
+using RemoteFramesBroadcastMethodCallback =
+    base::RepeatingCallback<void(RenderFrameProxyHost*)>;
+
 // Manages RenderFrameHosts for a FrameTreeNode. It maintains a
 // current_frame_host() which is the content currently visible to the user. When
 // a frame is told to navigate to a different web site (as determined by
@@ -447,11 +450,19 @@
 
   // Executes a PageBroadcast Mojo method to every RenderView in the FrameTree.
   // This should only be called in the top-level RenderFrameHostManager.
-  // The |callback| is called synchronously and the git |instance_to_skip| won't
+  // The |callback| is called synchronously and the |instance_to_skip| won't
   // be referenced after this method returns.
   void ExecutePageBroadcastMethod(PageBroadcastMethodCallback callback,
                                   SiteInstance* instance_to_skip = nullptr);
 
+  // Executes a RemoteMainFrame Mojo method to every instance in |proxy_hosts|.
+  // This should only be called in the top-level RenderFrameHostManager.
+  // The |callback| is called synchronously and the |instance_to_skip| won't
+  // be referenced after this method returns.
+  void ExecuteRemoteFramesBroadcastMethod(
+      RemoteFramesBroadcastMethodCallback callback,
+      SiteInstance* instance_to_skip = nullptr);
+
   // Returns a const reference to the map of proxy hosts. The keys are
   // SiteInstance IDs, the values are RenderFrameProxyHosts.
   const RenderFrameProxyHostMap& GetAllProxyHostsForTesting() const {
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index c2790bc..e3c8a6ca 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -3204,8 +3204,16 @@
   EXPECT_FALSE(proxy_observer.IsLoading(proxy_to_child));
 }
 
-// Tests that a BeginNavigation IPC from a no longer active RFH is ignored.
-TEST_P(RenderFrameHostManagerTest, BeginNavigationIgnoredWhenNotActive) {
+// Tests that a BeginNavigation IPC from a no longer active RFH in pending
+// deletion state is ignored.
+TEST_P(RenderFrameHostManagerTest,
+       BeginNavigationIgnoredWhenInPendingDeletion) {
+  // When a page enters the BackForwardCache, the RenderFrameHost is not
+  // deleted and is in BackForwardCache instead of being in pending deletion.
+  // Disabling to consider this scenario.
+  contents()->GetController().GetBackForwardCache().DisableForTesting(
+      BackForwardCache::TEST_ASSUMES_NO_CACHING);
+
   const GURL kUrl1("http://www.google.com");
   const GURL kUrl2("http://www.chromium.org");
   const GURL kUrl3("http://foo.com");
@@ -3224,6 +3232,8 @@
   navigation_to_kUrl2->Commit();
   EXPECT_NE(initial_rfh, main_test_rfh());
   ASSERT_FALSE(delete_observer.deleted());
+  EXPECT_NE(initial_rfh->lifecycle_state(),
+            RenderFrameHostImpl::LifecycleState::kActive);
   EXPECT_TRUE(initial_rfh->IsPendingDeletion());
 
   // The initial RFH receives a BeginNavigation IPC. The navigation should not
@@ -3234,6 +3244,60 @@
   EXPECT_FALSE(main_test_rfh()->frame_tree_node()->navigation_request());
 }
 
+// Run tests with BackForwardCache.
+class RenderFrameHostManagerTestWithBackForwardCache
+    : public RenderFrameHostManagerTest {
+ public:
+  RenderFrameHostManagerTestWithBackForwardCache() {
+    scoped_feature_list_.InitWithFeaturesAndParameters(
+        {{features::kBackForwardCache,
+          {
+              {"TimeToLiveInBackForwardCacheInSeconds", "3600"},
+              {"service_worker_supported", "true"},
+          }}},
+        /*disabled_features=*/{});
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Tests that a BeginNavigation IPC from a no longer active RFH in
+// BackForwardCache is ignored. This test is a copy of
+// "RenderFrameHostManagerTest.BeginNavigationIgnoredWhenInPendingDeletion" with
+// BackForwardCache consideration.
+TEST_P(RenderFrameHostManagerTestWithBackForwardCache,
+       BeginNavigationIgnoredWhenInBackForwardCache) {
+  const GURL kUrl1("http://www.google.com");
+  const GURL kUrl2("http://www.chromium.org");
+  const GURL kUrl3("http://foo.com");
+
+  contents()->NavigateAndCommit(kUrl1);
+
+  TestRenderFrameHost* initial_rfh = main_test_rfh();
+  RenderViewHostDeletedObserver delete_observer(
+      initial_rfh->GetRenderViewHost());
+
+  // Navigate cross-site but don't simulate the swap out ACK. The initial RFH
+  // should be in BackForwardCache.
+  auto navigation_to_kUrl2 =
+      NavigationSimulatorImpl::CreateBrowserInitiated(kUrl2, contents());
+  navigation_to_kUrl2->set_drop_unload_ack(true);
+  navigation_to_kUrl2->Commit();
+  EXPECT_NE(initial_rfh, main_test_rfh());
+  ASSERT_FALSE(delete_observer.deleted());
+  EXPECT_NE(initial_rfh->lifecycle_state(),
+            RenderFrameHostImpl::LifecycleState::kActive);
+  EXPECT_TRUE(initial_rfh->IsInBackForwardCache());
+
+  // The initial RFH receives a BeginNavigation IPC. The navigation should not
+  // start as initial RFH is not active.
+  auto navigation_to_kUrl3 =
+      NavigationSimulator::CreateRendererInitiated(kUrl3, initial_rfh);
+  navigation_to_kUrl3->Start();
+  EXPECT_FALSE(main_test_rfh()->frame_tree_node()->navigation_request());
+}
+
 // Tests that sandbox flags received after a navigation away has started do not
 // affect the document being navigated to.
 TEST_P(RenderFrameHostManagerTest, ReceivedFramePolicyAfterNavigationStarted) {
@@ -3634,5 +3698,7 @@
 INSTANTIATE_TEST_SUITE_P(All,
                          RenderFrameHostManagerAdTaggingSignalTest,
                          testing::ValuesIn(RenderDocumentFeatureLevelValues()));
-
+INSTANTIATE_TEST_SUITE_P(All,
+                         RenderFrameHostManagerTestWithBackForwardCache,
+                         testing::ValuesIn(RenderDocumentFeatureLevelValues()));
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index 053b3543..3903806 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -338,6 +338,13 @@
   return remote_frame_;
 }
 
+const mojo::AssociatedRemote<blink::mojom::RemoteMainFrame>&
+RenderFrameProxyHost::GetAssociatedRemoteMainFrame() {
+  if (!remote_main_frame_)
+    GetRemoteAssociatedInterfaces()->GetInterface(&remote_main_frame_);
+  return remote_main_frame_;
+}
+
 const mojo::AssociatedRemote<content::mojom::RenderFrameProxy>&
 RenderFrameProxyHost::GetAssociatedRenderFrameProxy() {
   if (!render_frame_proxy_)
diff --git a/content/browser/frame_host/render_frame_proxy_host.h b/content/browser/frame_host/render_frame_proxy_host.h
index 985f2cc8..5f87c00 100644
--- a/content/browser/frame_host/render_frame_proxy_host.h
+++ b/content/browser/frame_host/render_frame_proxy_host.h
@@ -149,6 +149,11 @@
   const mojo::AssociatedRemote<blink::mojom::RemoteFrame>&
   GetAssociatedRemoteFrame();
 
+  // Returns associated remote for the blink::mojom::RemoteMainFrame Mojo
+  // interface.
+  const mojo::AssociatedRemote<blink::mojom::RemoteMainFrame>&
+  GetAssociatedRemoteMainFrame();
+
   // blink::mojom::RemoteFrameHost
   void SetInheritedEffectiveTouchAction(cc::TouchAction touch_action) override;
   void UpdateRenderThrottlingStatus(bool is_throttled,
@@ -258,6 +263,10 @@
   // Holder of Mojo connection with the Frame service in Blink.
   mojo::AssociatedRemote<blink::mojom::RemoteFrame> remote_frame_;
 
+  // Holder of Mojo connection with the RemoteMainFrame in Blink. This remote
+  // will be valid when the frame is the active main frame.
+  mojo::AssociatedRemote<blink::mojom::RemoteMainFrame> remote_main_frame_;
+
   // Holder of Mojo connection with the content::mojom::RenderFrameProxy.
   mojo::AssociatedRemote<mojom::RenderFrameProxy> render_frame_proxy_;
 
diff --git a/content/browser/net/split_cache_browsertest.cc b/content/browser/net/split_cache_browsertest.cc
index efa7d49..8499009 100644
--- a/content/browser/net/split_cache_browsertest.cc
+++ b/content/browser/net/split_cache_browsertest.cc
@@ -614,8 +614,14 @@
                                GenURL("c.com", "/title1.html")));
 }
 
+// TODO(http://crbug.com/1104847): Flaky on Win10 and Linux ASAN.
+#if defined(OS_WIN) || (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER))
+#define MAYBE_SplitCacheDedicatedWorkers DISABLED_SplitCacheDedicatedWorkers
+#else
+#define MAYBE_SplitCacheDedicatedWorkers SplitCacheDedicatedWorkers
+#endif
 IN_PROC_BROWSER_TEST_F(SplitCacheWithFrameOriginContentBrowserTest,
-                       SplitCacheDedicatedWorkers) {
+                       MAYBE_SplitCacheDedicatedWorkers) {
   // Load 3p.com/script from a.com's worker. The first time it's loaded from the
   // network and the second it's cached.
   EXPECT_FALSE(TestResourceLoadFromDedicatedWorker(
diff --git a/content/browser/push_messaging/push_messaging_router.cc b/content/browser/push_messaging/push_messaging_router.cc
index 7c8d55be..b2bc352f 100644
--- a/content/browser/push_messaging/push_messaging_router.cc
+++ b/content/browser/push_messaging/push_messaging_router.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "content/browser/devtools/devtools_background_services_context_impl.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
@@ -16,6 +17,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_features.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom.h"
 
@@ -28,15 +30,15 @@
     scoped_refptr<DevToolsBackgroundServicesContextImpl>,
     blink::ServiceWorkerStatusCode)>;
 
-void RunDeliverCallback(
-    PushMessagingRouter::DeliverMessageCallback deliver_message_callback,
-    blink::mojom::PushDeliveryStatus delivery_status) {
+void RunPushEventCallback(
+    PushMessagingRouter::PushEventCallback deliver_message_callback,
+    blink::mojom::PushDeliveryStatus push_event_status) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   // Use PostTask() instead of RunOrPostTaskOnThread() to ensure the callback
   // is called asynchronously.
   GetUIThreadTaskRunner({})->PostTask(
       FROM_HERE,
-      base::BindOnce(std::move(deliver_message_callback), delivery_status));
+      base::BindOnce(std::move(deliver_message_callback), push_event_status));
 }
 
 // Given the |service_worker_registration|, this method finds and finishes the
@@ -123,7 +125,7 @@
     int64_t service_worker_registration_id,
     const std::string& message_id,
     base::Optional<std::string> payload,
-    DeliverMessageCallback deliver_message_callback) {
+    PushEventCallback deliver_message_callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   StartServiceWorkerForDispatch(
       ServiceWorkerMetrics::EventType::PUSH, browser_context, origin,
@@ -136,7 +138,7 @@
 void PushMessagingRouter::DeliverMessageToWorker(
     const std::string& message_id,
     base::Optional<std::string> payload,
-    DeliverMessageCallback deliver_message_callback,
+    PushEventCallback deliver_message_callback,
     scoped_refptr<ServiceWorkerVersion> service_worker,
     scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context,
     blink::ServiceWorkerStatusCode status) {
@@ -144,7 +146,7 @@
   // Service worker registration was not found, run callback immediately
   if (!service_worker) {
     DCHECK_NE(blink::ServiceWorkerStatusCode::kOk, status);
-    RunDeliverCallback(
+    RunPushEventCallback(
         std::move(deliver_message_callback),
         status == blink::ServiceWorkerStatusCode::kErrorNotFound
             ? blink::mojom::PushDeliveryStatus::NO_SERVICE_WORKER
@@ -153,7 +155,7 @@
   }
 
   // RunAfterStartWorker was not successful, end message delivery and log error
-  // in devtools_context before running RunDeliverCallback
+  // in devtools_context before running RunPushEventCallback
   if (status != blink::ServiceWorkerStatusCode::kOk) {
     DeliverMessageEnd(std::move(service_worker), std::move(devtools_context),
                       message_id, std::move(deliver_message_callback), status);
@@ -188,26 +190,26 @@
     scoped_refptr<ServiceWorkerVersion> service_worker,
     scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context,
     const std::string& message_id,
-    DeliverMessageCallback deliver_message_callback,
+    PushEventCallback deliver_message_callback,
     blink::ServiceWorkerStatusCode service_worker_status) {
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   UMA_HISTOGRAM_ENUMERATION("PushMessaging.DeliveryStatus.ServiceWorkerEvent",
                             service_worker_status);
-  blink::mojom::PushDeliveryStatus delivery_status =
+  blink::mojom::PushDeliveryStatus push_event_status =
       blink::mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR;
   std::string status_description;
   switch (service_worker_status) {
     case blink::ServiceWorkerStatusCode::kOk:
-      delivery_status = blink::mojom::PushDeliveryStatus::SUCCESS;
+      push_event_status = blink::mojom::PushDeliveryStatus::SUCCESS;
       status_description = "Success";
       break;
     case blink::ServiceWorkerStatusCode::kErrorEventWaitUntilRejected:
-      delivery_status =
+      push_event_status =
           blink::mojom::PushDeliveryStatus::EVENT_WAITUNTIL_REJECTED;
       status_description = "waitUntil Rejected";
       break;
     case blink::ServiceWorkerStatusCode::kErrorTimeout:
-      delivery_status = blink::mojom::PushDeliveryStatus::TIMEOUT;
+      push_event_status = blink::mojom::PushDeliveryStatus::TIMEOUT;
       status_description = "Timeout";
       break;
     case blink::ServiceWorkerStatusCode::kErrorFailed:
@@ -220,7 +222,8 @@
     case blink::ServiceWorkerStatusCode::kErrorDiskCache:
     case blink::ServiceWorkerStatusCode::kErrorRedundant:
     case blink::ServiceWorkerStatusCode::kErrorDisallowed:
-      delivery_status = blink::mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR;
+      push_event_status =
+          blink::mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR;
       break;
     case blink::ServiceWorkerStatusCode::kErrorExists:
     case blink::ServiceWorkerStatusCode::kErrorInstallWorkerFailed:
@@ -232,14 +235,15 @@
       NOTREACHED() << "Got unexpected error code: "
                    << static_cast<uint32_t>(service_worker_status) << " "
                    << blink::ServiceWorkerStatusToString(service_worker_status);
-      delivery_status = blink::mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR;
+      push_event_status =
+          blink::mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR;
       break;
   }
-  RunDeliverCallback(std::move(deliver_message_callback), delivery_status);
+  RunPushEventCallback(std::move(deliver_message_callback), push_event_status);
 
   if (devtools_context->IsRecording(
           DevToolsBackgroundService::kPushMessaging) &&
-      delivery_status !=
+      push_event_status !=
           blink::mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR) {
     devtools_context->LogBackgroundServiceEventOnCoreThread(
         service_worker->registration_id(), service_worker->script_origin(),
@@ -248,4 +252,89 @@
   }
 }
 
+// static
+void PushMessagingRouter::FireSubscriptionChangeEvent(
+    BrowserContext* browser_context,
+    const GURL& origin,
+    int64_t service_worker_registration_id,
+    blink::mojom::PushSubscriptionPtr new_subscription,
+    blink::mojom::PushSubscriptionPtr old_subscription,
+    PushEventCallback subscription_change_callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(base::FeatureList::IsEnabled(features::kPushSubscriptionChangeEvent));
+
+  StartServiceWorkerForDispatch(
+      ServiceWorkerMetrics::EventType::PUSH_SUBSCRIPTION_CHANGE,
+      browser_context, origin, service_worker_registration_id,
+      base::BindOnce(&PushMessagingRouter::FireSubscriptionChangeEventToWorker,
+                     std::move(new_subscription), std::move(old_subscription),
+                     std::move(subscription_change_callback)));
+}
+
+// static
+void PushMessagingRouter::FireSubscriptionChangeEventToWorker(
+    blink::mojom::PushSubscriptionPtr new_subscription,
+    blink::mojom::PushSubscriptionPtr old_subscription,
+    PushEventCallback subscription_change_callback,
+    scoped_refptr<ServiceWorkerVersion> service_worker,
+    scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context,
+    blink::ServiceWorkerStatusCode status) {
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  DCHECK(base::FeatureList::IsEnabled(features::kPushSubscriptionChangeEvent));
+
+  if (!service_worker) {
+    DCHECK_NE(blink::ServiceWorkerStatusCode::kOk, status);
+    RunPushEventCallback(
+        std::move(subscription_change_callback),
+        status == blink::ServiceWorkerStatusCode::kErrorNotFound
+            ? blink::mojom::PushDeliveryStatus::NO_SERVICE_WORKER
+            : blink::mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR);
+    return;
+  }
+
+  if (status != blink::ServiceWorkerStatusCode::kOk) {
+    FireSubscriptionChangeEventEnd(std::move(service_worker),
+                                   std::move(subscription_change_callback),
+                                   status);
+    return;
+  }
+
+  int request_id = service_worker->StartRequestWithCustomTimeout(
+      ServiceWorkerMetrics::EventType::PUSH_SUBSCRIPTION_CHANGE,
+      base::BindOnce(&PushMessagingRouter::FireSubscriptionChangeEventEnd,
+                     service_worker, std::move(subscription_change_callback)),
+      base::TimeDelta::FromSeconds(blink::mojom::kPushEventTimeoutSeconds),
+      ServiceWorkerVersion::KILL_ON_TIMEOUT);
+
+  service_worker->endpoint()->DispatchPushSubscriptionChangeEvent(
+      std::move(old_subscription), std::move(new_subscription),
+      service_worker->CreateSimpleEventCallback(request_id));
+}
+
+// static
+void PushMessagingRouter::FireSubscriptionChangeEventEnd(
+    scoped_refptr<ServiceWorkerVersion> service_worker,
+    PushEventCallback subscription_change_callback,
+    blink::ServiceWorkerStatusCode service_worker_status) {
+  DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
+  blink::mojom::PushDeliveryStatus push_event_status =
+      blink::mojom::PushDeliveryStatus::SERVICE_WORKER_ERROR;
+  switch (service_worker_status) {
+    case blink::ServiceWorkerStatusCode::kOk:
+      push_event_status = blink::mojom::PushDeliveryStatus::SUCCESS;
+      break;
+    case blink::ServiceWorkerStatusCode::kErrorEventWaitUntilRejected:
+      push_event_status =
+          blink::mojom::PushDeliveryStatus::EVENT_WAITUNTIL_REJECTED;
+      break;
+    case blink::ServiceWorkerStatusCode::kErrorTimeout:
+      push_event_status = blink::mojom::PushDeliveryStatus::TIMEOUT;
+      break;
+    default:
+      break;
+  }
+  RunPushEventCallback(std::move(subscription_change_callback),
+                       push_event_status);
+}
+
 }  // namespace content
diff --git a/content/browser/push_messaging/push_messaging_router.h b/content/browser/push_messaging/push_messaging_router.h
index 66a41534..b53d5a5 100644
--- a/content/browser/push_messaging/push_messaging_router.h
+++ b/content/browser/push_messaging/push_messaging_router.h
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/optional.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
+#include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-forward.h"
 #include "url/gurl.h"
 
 namespace blink {
@@ -28,7 +29,7 @@
 
 class PushMessagingRouter {
  public:
-  using DeliverMessageCallback =
+  using PushEventCallback =
       base::OnceCallback<void(blink::mojom::PushDeliveryStatus)>;
 
   // Delivers a push message with |payload| to the Service Worker identified by
@@ -39,26 +40,57 @@
                              int64_t service_worker_registration_id,
                              const std::string& message_id,
                              base::Optional<std::string> payload,
-                             DeliverMessageCallback deliver_message_callback);
+                             PushEventCallback deliver_message_callback);
+
+  // TODO(https://crbug.com/753163): Add the ability to trigger a push
+  // subscription change event in DevTools
+  // Fires a pushsubscriptionchangeevent with the arguments |new_subscription|
+  // and |old_subscription| to service workers.  Must be called on the UI
+  // thread.
+  static void FireSubscriptionChangeEvent(
+      BrowserContext* browser_context,
+      const GURL& origin,
+      int64_t service_worker_registration_id,
+      blink::mojom::PushSubscriptionPtr new_subscription,
+      blink::mojom::PushSubscriptionPtr old_subscription,
+      PushEventCallback subscription_change_callback);
 
  private:
   // Delivers a push message with |payload| to a specific |service_worker|.
-  // Must be called on the IO thread.
+  // Must be called on the ServiceWorkerContext core thread.
   static void DeliverMessageToWorker(
       const std::string& message_id,
       base::Optional<std::string> payload,
-      DeliverMessageCallback deliver_message_callback,
+      PushEventCallback deliver_message_callback,
       scoped_refptr<ServiceWorkerVersion> service_worker,
       scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context,
       blink::ServiceWorkerStatusCode status);
 
   // Gets called asynchronously after the Service Worker has dispatched the push
-  // event. Must be called on the IO thread.
+  // event. Must be called on the ServiceWorkerContext core thread.
   static void DeliverMessageEnd(
       scoped_refptr<ServiceWorkerVersion> service_worker,
       scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context,
       const std::string& message_id,
-      DeliverMessageCallback deliver_message_callback,
+      PushEventCallback deliver_message_callback,
+      blink::ServiceWorkerStatusCode service_worker_status);
+
+  // Fires a `pushsubscriptionchange` event to the |service_worker| if it is
+  // ready. Must be called on the ServiceWorkerContext core thread.
+  static void FireSubscriptionChangeEventToWorker(
+      blink::mojom::PushSubscriptionPtr new_subscription,
+      blink::mojom::PushSubscriptionPtr old_subscription,
+      PushEventCallback subscription_change_callback,
+      scoped_refptr<ServiceWorkerVersion> service_worker,
+      scoped_refptr<DevToolsBackgroundServicesContextImpl> devtools_context,
+      blink::ServiceWorkerStatusCode status);
+
+  // Gets called asynchronously after the Service Worker has dispatched the
+  // `pushsubscriptionchange` event. Must be called on the ServiceWorkerContext
+  // core thread.
+  static void FireSubscriptionChangeEventEnd(
+      scoped_refptr<ServiceWorkerVersion> service_worker,
+      PushEventCallback subscription_change_callback,
       blink::ServiceWorkerStatusCode service_worker_status);
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(PushMessagingRouter);
diff --git a/content/browser/service_worker/service_worker_metrics.cc b/content/browser/service_worker/service_worker_metrics.cc
index 93c515d..50b0e77 100644
--- a/content/browser/service_worker/service_worker_metrics.cc
+++ b/content/browser/service_worker/service_worker_metrics.cc
@@ -122,6 +122,8 @@
       return "_PERIODIC_SYNC";
     case ServiceWorkerMetrics::EventType::CONTENT_DELETE:
       return "_CONTENT_DELETE";
+    case ServiceWorkerMetrics::EventType::PUSH_SUBSCRIPTION_CHANGE:
+      return "_PUSH_SUBSCRIPTION_CHANGE";
   }
   return "_UNKNOWN";
 }
@@ -180,6 +182,8 @@
       return "Periodic Sync";
     case EventType::CONTENT_DELETE:
       return "Content Delete";
+    case EventType::PUSH_SUBSCRIPTION_CHANGE:
+      return "Push Subscription Change";
   }
   NOTREACHED() << "Got unexpected event type: " << static_cast<int>(event_type);
   return "error";
@@ -416,7 +420,10 @@
     case EventType::CONTENT_DELETE:
       UMA_HISTOGRAM_MEDIUM_TIMES("ServiceWorker.ContentDeleteEvent.Time", time);
       break;
-
+    case EventType::PUSH_SUBSCRIPTION_CHANGE:
+      UMA_HISTOGRAM_MEDIUM_TIMES(
+          "ServiceWorker.PushSubscriptionChangeEvent.Time", time);
+      break;
     case EventType::NAVIGATION_HINT:
     // The navigation hint should not be sent as an event.
     case EventType::UNKNOWN:
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h
index 7fef822c..316229e 100644
--- a/content/browser/service_worker/service_worker_metrics.h
+++ b/content/browser/service_worker/service_worker_metrics.h
@@ -101,8 +101,9 @@
     BACKGROUND_FETCH_SUCCESS = 32,
     PERIODIC_SYNC = 33,
     CONTENT_DELETE = 34,
+    PUSH_SUBSCRIPTION_CHANGE = 35,
     // Add new events to record here.
-    kMaxValue = CONTENT_DELETE,
+    kMaxValue = PUSH_SUBSCRIPTION_CHANGE,
   };
 
   // Used for UMA. Append only.
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 906a83b..7bcc883 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -127,11 +127,13 @@
 #include "services/network/public/mojom/web_sandbox_flags.mojom-shared.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
 #include "third_party/blink/public/common/feature_policy/policy_value.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
 #include "third_party/blink/public/mojom/frame/frame.mojom-test-utils.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom.h"
 #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom.h"
 #include "ui/display/display_switches.h"
 #include "ui/display/screen.h"
@@ -1077,70 +1079,85 @@
   base::Optional<float> target_device_scale_adjustment_;
 };
 
-class OutgoingTextAutosizerPageInfoIPCWatcher {
+// TODO(tonikitoo): Move to fake_remote_frame.h|cc in case it is useful
+// for other tests.
+class FakeRemoteMainFrame : public blink::mojom::RemoteMainFrame {
  public:
-  OutgoingTextAutosizerPageInfoIPCWatcher(
-      RenderProcessHostImpl* rph,
-      base::Optional<int> target_width,
-      base::Optional<float> target_device_scale_adjustment)
-      : rph_(rph),
-        outgoing_message_seen_(false),
-        target_width_(target_width),
-        target_device_scale_adjustment_(target_device_scale_adjustment) {
-    rph_->SetIpcSendWatcherForTesting(
-        base::BindRepeating(&OutgoingTextAutosizerPageInfoIPCWatcher::OnMessage,
+  FakeRemoteMainFrame() = default;
+  ~FakeRemoteMainFrame() override = default;
+
+  void Init(blink::AssociatedInterfaceProvider* provider) {
+    provider->OverrideBinderForTesting(
+        blink::mojom::RemoteMainFrame::Name_,
+        base::BindRepeating(&FakeRemoteMainFrame::BindFrameHostReceiver,
                             base::Unretained(this)));
   }
-  ~OutgoingTextAutosizerPageInfoIPCWatcher() {
-    rph_->SetIpcSendWatcherForTesting(
-        base::RepeatingCallback<void(const IPC::Message& msg)>());
+
+  // blink::mojom::RemoteMainFrame overrides:
+  void UpdateTextAutosizerPageInfo(
+      blink::mojom::TextAutosizerPageInfoPtr page_info) override {}
+
+ private:
+  void BindFrameHostReceiver(mojo::ScopedInterfaceEndpointHandle handle) {
+    receiver_.Bind(
+        mojo::PendingAssociatedReceiver<blink::mojom::RemoteMainFrame>(
+            std::move(handle)));
   }
 
-  void WaitForIPC() {
-    if (outgoing_message_seen_)
-      return;
-    run_loop_ = std::make_unique<base::RunLoop>();
-    run_loop_->Run();
-    run_loop_.reset();
+  mojo::AssociatedReceiver<blink::mojom::RemoteMainFrame> receiver_{this};
+};
+
+// This class intercepts RenderFrameProxyHost creations, and overrides their
+// respective blink::mojom::RemoteMainFrame instances, so that it can watch for
+// text autosizer page info updates.
+class UpdateTextAutosizerInfoProxyObserver {
+ public:
+  UpdateTextAutosizerInfoProxyObserver() {
+    RenderFrameProxyHost::SetCreatedCallbackForTesting(
+        base::BindRepeating(&UpdateTextAutosizerInfoProxyObserver::
+                                RenderFrameProxyHostCreatedCallback,
+                            base::Unretained(this)));
+  }
+  ~UpdateTextAutosizerInfoProxyObserver() {
+    RenderFrameProxyHost::SetCreatedCallbackForTesting(
+        RenderFrameProxyHost::CreatedCallback());
   }
 
-  const blink::WebTextAutosizerPageInfo& GetTextAutosizerPageInfo() {
-    return remote_page_info_;
+  const blink::mojom::TextAutosizerPageInfo& TextAutosizerPageInfo(
+      RenderFrameProxyHost* proxy) {
+    return remote_frames_[proxy]->page_info();
   }
 
  private:
-  void OnMessage(const IPC::Message& message) {
-    IPC_BEGIN_MESSAGE_MAP(OutgoingTextAutosizerPageInfoIPCWatcher, message)
-      IPC_MESSAGE_HANDLER(
-          PageMsg_UpdateTextAutosizerPageInfoForRemoteMainFrames,
-          ProcessMessage)
-    IPC_END_MESSAGE_MAP()
-  }
-
-  void ProcessMessage(const blink::WebTextAutosizerPageInfo& remote_page_info) {
-    if ((target_width_ && remote_page_info.main_frame_width != target_width_) ||
-        (target_device_scale_adjustment_ &&
-         remote_page_info.device_scale_adjustment !=
-             target_device_scale_adjustment_)) {
-      return;
+  class Remote : public FakeRemoteMainFrame {
+   public:
+    explicit Remote(RenderFrameProxyHost* proxy) {
+      Init(proxy->GetRemoteAssociatedInterfacesTesting());
     }
-    outgoing_message_seen_ = true;
-    remote_page_info_ = remote_page_info;
-    if (run_loop_)
-      run_loop_->Quit();
+    void UpdateTextAutosizerPageInfo(
+        blink::mojom::TextAutosizerPageInfoPtr page_info) override {
+      page_info_ = *page_info;
+    }
+    const blink::mojom::TextAutosizerPageInfo& page_info() {
+      return page_info_;
+    }
+
+   private:
+    blink::mojom::TextAutosizerPageInfo page_info_;
+  };
+
+  void RenderFrameProxyHostCreatedCallback(RenderFrameProxyHost* proxy_host) {
+    remote_frames_[proxy_host] = std::make_unique<Remote>(proxy_host);
   }
 
-  RenderProcessHostImpl* rph_;
-  bool outgoing_message_seen_;
-  base::Optional<int> target_width_;
-  base::Optional<float> target_device_scale_adjustment_;
-  std::unique_ptr<base::RunLoop> run_loop_;
-  blink::WebTextAutosizerPageInfo remote_page_info_;
+  std::map<RenderFrameProxyHost*, std::unique_ptr<Remote>> remote_frames_;
 };
 
 // Make sure that when a relevant feature of the main frame changes, e.g. the
 // frame width, that the browser is notified.
 IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest, TextAutosizerPageInfo) {
+  UpdateTextAutosizerInfoProxyObserver update_text_autosizer_info_observer;
+
   WebPreferences prefs = web_contents()->GetOrCreateWebPreferences();
   prefs.text_autosizing_enabled = true;
 
@@ -1152,23 +1169,19 @@
   FrameTreeNode* root = web_contents()->GetFrameTree()->root();
   ASSERT_EQ(1U, root->child_count());
   FrameTreeNode* b_child = root->child_at(0);
-  auto* child_rph = static_cast<RenderProcessHostImpl*>(
-      b_child->current_frame_host()->GetProcess());
 
   blink::mojom::TextAutosizerPageInfo received_page_info;
   auto interceptor = std::make_unique<TextAutosizerPageInfoInterceptor>(
       web_contents()->GetMainFrame());
 #if defined(OS_ANDROID)
   prefs.device_scale_adjustment += 0.05f;
-  OutgoingTextAutosizerPageInfoIPCWatcher ipc_watcher(
-      child_rph, base::Optional<int>(), prefs.device_scale_adjustment);
   // Change the device scale adjustment to trigger a RemotePageInfo update.
   web_contents()->SetWebPreferences(prefs);
   // Make sure we receive a ViewHostMsg from the main frame's renderer.
   interceptor->WaitForPageInfo(base::Optional<int>(),
                                prefs.device_scale_adjustment);
   // Make sure the correct page message is sent to the child.
-  ipc_watcher.WaitForIPC();
+  base::RunLoop().RunUntilIdle();
   received_page_info = interceptor->GetTextAutosizerPageInfo();
   EXPECT_EQ(prefs.device_scale_adjustment,
             received_page_info.device_scale_adjustment);
@@ -1180,13 +1193,12 @@
   gfx::Rect new_bounds(
       old_bounds.origin(),
       gfx::Size(old_bounds.width() - 20, old_bounds.height() - 20));
-  OutgoingTextAutosizerPageInfoIPCWatcher ipc_watcher(
-      child_rph, new_bounds.width(), base::Optional<float>());
+
   view->SetBounds(new_bounds);
   // Make sure we receive a ViewHostMsg from the main frame's renderer.
   interceptor->WaitForPageInfo(new_bounds.width(), base::Optional<float>());
   // Make sure the correct page message is sent to the child.
-  ipc_watcher.WaitForIPC();
+  base::RunLoop().RunUntilIdle();
   received_page_info = interceptor->GetTextAutosizerPageInfo();
   EXPECT_EQ(new_bounds.width(), received_page_info.main_frame_width);
 #endif  // defined(OS_ANDROID)
@@ -1206,8 +1218,6 @@
   ASSERT_TRUE(c_rph);
   ASSERT_NE(c_rph, root->current_frame_host()->GetProcess());
   ASSERT_NE(c_rph, b_child->current_frame_host()->GetProcess());
-  OutgoingTextAutosizerPageInfoIPCWatcher c_ipc_watcher(
-      c_rph, base::Optional<int>(), base::Optional<float>());
 
   // Create the subframe now.
   std::string create_frame_script = base::StringPrintf(
@@ -1219,16 +1229,21 @@
   ASSERT_EQ(2U, root->child_count());
 
   // Ensure IPC is sent.
-  c_ipc_watcher.WaitForIPC();
-  // TODO(hferreiro): use the comparison operator when
-  // PageMsg_UpdateTextAutosizerPageInfoForRemoteMainFrames is migrated to
-  // Mojo.
+  base::RunLoop().RunUntilIdle();
+  blink::mojom::TextAutosizerPageInfo page_info_sent_to_remote_main_frames =
+      update_text_autosizer_info_observer.TextAutosizerPageInfo(
+          web_contents()
+              ->GetRenderManager()
+              ->GetAllProxyHostsForTesting()
+              .begin()
+              ->second.get());
+
   EXPECT_EQ(received_page_info.main_frame_width,
-            c_ipc_watcher.GetTextAutosizerPageInfo().main_frame_width);
+            page_info_sent_to_remote_main_frames.main_frame_width);
   EXPECT_EQ(received_page_info.main_frame_layout_width,
-            c_ipc_watcher.GetTextAutosizerPageInfo().main_frame_layout_width);
+            page_info_sent_to_remote_main_frames.main_frame_layout_width);
   EXPECT_EQ(received_page_info.device_scale_adjustment,
-            c_ipc_watcher.GetTextAutosizerPageInfo().device_scale_adjustment);
+            page_info_sent_to_remote_main_frames.device_scale_adjustment);
 }
 
 // Ensure that navigating subframes in --site-per-process mode works and the
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 1cf8510..a2ebb0d 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5358,10 +5358,18 @@
       page_info->main_frame_layout_width;
   text_autosizer_page_info_.device_scale_adjustment =
       page_info->device_scale_adjustment;
-  frame_tree_.root()->render_manager()->SendPageMessage(
-      new PageMsg_UpdateTextAutosizerPageInfoForRemoteMainFrames(
-          MSG_ROUTING_NONE, text_autosizer_page_info_),
-      source->GetSiteInstance());
+
+  auto remote_frames_broadcast_callback = base::BindRepeating(
+      [](const blink::mojom::TextAutosizerPageInfo& page_info,
+         RenderFrameProxyHost* proxy_host) {
+        DCHECK(proxy_host);
+        proxy_host->GetAssociatedRemoteMainFrame()->UpdateTextAutosizerPageInfo(
+            page_info.Clone());
+      },
+      text_autosizer_page_info_);
+
+  frame_tree_.root()->render_manager()->ExecuteRemoteFramesBroadcastMethod(
+      std::move(remote_frames_broadcast_callback), source->GetSiteInstance());
 }
 
 void WebContentsImpl::EnumerateDirectory(
@@ -7043,9 +7051,10 @@
   // this state themselves from up-to-date values, so we shouldn't override it
   // with the cached values.
   if (!render_view_host->GetMainFrame()) {
-    render_view_host->Send(
-        new PageMsg_UpdateTextAutosizerPageInfoForRemoteMainFrames(
-            render_view_host->GetRoutingID(), text_autosizer_page_info_));
+    auto* proxy_host = GetRenderManager()->GetRenderFrameProxyHost(
+        render_view_host->GetSiteInstance());
+    proxy_host->GetAssociatedRemoteMainFrame()->UpdateTextAutosizerPageInfo(
+        text_autosizer_page_info_.Clone());
   }
 
   if (proxy_routing_id == MSG_ROUTING_NONE && node_.outer_web_contents())
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 7f381fd..7562784 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1287,6 +1287,7 @@
   FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, CrossSiteIframe);
   FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
                            TwoSubframesCreatePopupsSimultaneously);
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest, TextAutosizerPageInfo);
   FRIEND_TEST_ALL_PREFIXES(SitePerProcessBrowserTest,
                            TwoSubframesCreatePopupMenuWidgetsSimultaneously);
   FRIEND_TEST_ALL_PREFIXES(SitePerProcessAccessibilityBrowserTest,
@@ -2065,7 +2066,7 @@
 
   // Stores information from the main frame's renderer that needs to be shared
   // with OOPIF renderers.
-  blink::WebTextAutosizerPageInfo text_autosizer_page_info_;
+  blink::mojom::TextAutosizerPageInfo text_autosizer_page_info_;
 
   // Observe native theme for changes to dark mode, and preferred color scheme.
   // Used to notify the renderer of preferred color scheme changes.
diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc
index 2cc10a4..6385092a 100644
--- a/content/browser/webauth/authenticator_common.cc
+++ b/content/browser/webauth/authenticator_common.cc
@@ -26,6 +26,7 @@
 #include "content/browser/webauth/webauth_request_security_checker.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/device_service.h"
 #include "content/public/browser/is_uvpaa.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
@@ -520,6 +521,10 @@
         device::FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy);
   }
 
+  if (base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)) {
+    transports.insert(device::FidoTransportProtocol::kAndroidAccessory);
+  }
+
   return transports;
 }
 
diff --git a/content/browser/webauth/authenticator_mojom_traits.cc b/content/browser/webauth/authenticator_mojom_traits.cc
index 15dafc45..1eeaba5 100644
--- a/content/browser/webauth/authenticator_mojom_traits.cc
+++ b/content/browser/webauth/authenticator_mojom_traits.cc
@@ -24,6 +24,8 @@
       return blink::mojom::AuthenticatorTransport::CABLE;
     case ::device::FidoTransportProtocol::kInternal:
       return blink::mojom::AuthenticatorTransport::INTERNAL;
+    case ::device::FidoTransportProtocol::kAndroidAccessory:
+      return blink::mojom::AuthenticatorTransport::CABLE;
   }
   NOTREACHED();
   return blink::mojom::AuthenticatorTransport::USB;
diff --git a/content/common/content_param_traits_macros.h b/content/common/content_param_traits_macros.h
index 34fe450..7fbab97 100644
--- a/content/common/content_param_traits_macros.h
+++ b/content/common/content_param_traits_macros.h
@@ -17,7 +17,6 @@
 #include "third_party/blink/public/common/input/web_input_event.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
-#include "third_party/blink/public/platform/web_text_autosizer_page_info.h"
 #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/ipc/geometry/gfx_param_traits.h"
@@ -46,10 +45,4 @@
   IPC_STRUCT_TRAITS_MEMBER(end)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(blink::WebTextAutosizerPageInfo)
-  IPC_STRUCT_TRAITS_MEMBER(main_frame_width)
-  IPC_STRUCT_TRAITS_MEMBER(main_frame_layout_width)
-  IPC_STRUCT_TRAITS_MEMBER(device_scale_adjustment)
-IPC_STRUCT_TRAITS_END()
-
 #endif  // CONTENT_COMMON_CONTENT_PARAM_TRAITS_MACROS_H_
diff --git a/content/common/page_messages.h b/content/common/page_messages.h
index ea8b41f..bf96f06 100644
--- a/content/common/page_messages.h
+++ b/content/common/page_messages.h
@@ -8,8 +8,6 @@
 #include "content/public/common/common_param_traits.h"
 #include "content/public/common/page_visibility_state.h"
 #include "ipc/ipc_message_macros.h"
-#include "third_party/blink/public/platform/web_text_autosizer_page_info.h"
-#include "ui/gfx/geometry/rect.h"
 
 // IPC messages for page-level actions.
 // TODO(https://crbug.com/775827): Convert to mojo.
@@ -28,10 +26,6 @@
                     int /* history_offset */,
                     int /* history_length */)
 
-// blink::TextAutosizer changes in the main frame's renderer.
-IPC_MESSAGE_ROUTED1(PageMsg_UpdateTextAutosizerPageInfoForRemoteMainFrames,
-                    blink::WebTextAutosizerPageInfo /* page_info */)
-
 // Sends updated preferences to the renderer.
 IPC_MESSAGE_ROUTED1(PageMsg_SetRendererPrefs, blink::mojom::RendererPreferences)
 
diff --git a/content/public/browser/accessibility_tree_formatter.h b/content/public/browser/accessibility_tree_formatter.h
index b954cce0..59f08a2 100644
--- a/content/public/browser/accessibility_tree_formatter.h
+++ b/content/public/browser/accessibility_tree_formatter.h
@@ -186,6 +186,17 @@
   virtual const std::string GetAllowString() = 0;
   virtual const std::string GetDenyString() = 0;
   virtual const std::string GetDenyNodeString() = 0;
+
+  // A string that indicates event recording should continue at least until a
+  // specific event has been received.
+  // Overridden by each platform subclass.
+  // Example win value:
+  //   GetRunUntilEventString() -> "@WIN-RUN-UNTIL-EVENT"
+  // Example html:
+  // <!--
+  // @WIN-RUN-UNTIL-EVENT:IA2_EVENT_TEXT_CARET_MOVED
+  // -->
+  virtual const std::string GetRunUntilEventString() = 0;
 };
 
 }  // namespace content
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index ffd07b4a..f207ba3 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -25,6 +25,7 @@
 #include "services/network/public/mojom/cors_origin_pattern.mojom-forward.h"
 #include "services/network/public/mojom/network_context.mojom-forward.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom-forward.h"
+#include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-forward.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom-forward.h"
 
 #if !defined(OS_ANDROID)
@@ -67,10 +68,6 @@
 
 namespace content {
 
-namespace mojom {
-enum class PushDeliveryStatus;
-}
-
 class BackgroundFetchDelegate;
 class BackgroundSyncController;
 class BlobHandle;
@@ -197,6 +194,17 @@
       base::Optional<std::string> payload,
       base::OnceCallback<void(blink::mojom::PushDeliveryStatus)> callback);
 
+  // Fires a push subscription change event to the Service Worker identified by
+  // |origin| and |service_worker_registration_id| with |new_subscription| and
+  // |old_subscription| as event information.
+  static void FirePushSubscriptionChangeEvent(
+      BrowserContext* browser_context,
+      const GURL& origin,
+      int64_t service_worker_registration_id,
+      blink::mojom::PushSubscriptionPtr new_subscription,
+      blink::mojom::PushSubscriptionPtr old_subscription,
+      base::OnceCallback<void(blink::mojom::PushDeliveryStatus)> callback);
+
   static void NotifyWillBeDestroyed(BrowserContext* browser_context);
 
   // Ensures that the corresponding ResourceContext is initialized. Normally the
diff --git a/content/public/browser/devtools_agent_host.h b/content/public/browser/devtools_agent_host.h
index 7b9bb9e..d633f53 100644
--- a/content/public/browser/devtools_agent_host.h
+++ b/content/public/browser/devtools_agent_host.h
@@ -150,6 +150,10 @@
   // Returns the id of the opener host, or empty string if no opener.
   virtual std::string GetOpenerId() = 0;
 
+  // Returns whether the opened window has access to its opener (can be false
+  // when using 'noopener' or with enabled COOP).
+  virtual bool CanAccessOpener() = 0;
+
   // Returns web contents instance for this host if any.
   virtual WebContents* GetWebContents() = 0;
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 6d7b23c..efb6956 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -486,6 +486,12 @@
 const base::Feature kProactivelySwapBrowsingInstance{
     "ProactivelySwapBrowsingInstance", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Fires the `pushsubscriptionchange` event defined here:
+// https://w3c.github.io/push-api/#the-pushsubscriptionchange-event
+// for subscription refreshes, revoked permissions or subscription losses
+const base::Feature kPushSubscriptionChangeEvent{
+    "PushSubscriptionChangeEvent", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Reduce the amount of information in the default 'referer' header for
 // cross-origin requests.
 const base::Feature kReducedReferrerGranularity{
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 51ac685b..6dc1f16 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -108,6 +108,7 @@
     kProcessSharingWithDefaultSiteInstances;
 CONTENT_EXPORT extern const base::Feature
     kProcessSharingWithStrictSiteInstances;
+CONTENT_EXPORT extern const base::Feature kPushSubscriptionChangeEvent;
 CONTENT_EXPORT extern const base::Feature kReducedReferrerGranularity;
 CONTENT_EXPORT extern const base::Feature
     kRelaxIsolatedWorldCorsInFileUrlLoaderFactory;
diff --git a/content/public/test/accessibility_notification_waiter.cc b/content/public/test/accessibility_notification_waiter.cc
index 50bad44..ace62cb 100644
--- a/content/public/test/accessibility_notification_waiter.cc
+++ b/content/public/test/accessibility_notification_waiter.cc
@@ -208,4 +208,8 @@
   ListenToFrame(static_cast<RenderFrameHostImpl*>(new_host));
 }
 
+void AccessibilityNotificationWaiter::Quit() {
+  loop_runner_->Quit();
+}
+
 }  // namespace content
diff --git a/content/public/test/accessibility_notification_waiter.h b/content/public/test/accessibility_notification_waiter.h
index 9c5591c..aacd620b 100644
--- a/content/public/test/accessibility_notification_waiter.h
+++ b/content/public/test/accessibility_notification_waiter.h
@@ -67,6 +67,9 @@
   void RenderFrameHostChanged(RenderFrameHost* old_host,
                               RenderFrameHost* new_host) override;
 
+  // Quits listening and unblocks WaitForNotification* calls.
+  void Quit();
+
  private:
   // Listen to all frames within the frame tree of this WebContents.
   void ListenToAllFrames(WebContents* web_contents);
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index b76e278..b34393f 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -106,7 +106,6 @@
 #include "third_party/blink/public/platform/web_runtime_features.h"
 #include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/platform/web_text_autosizer_page_info.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"
@@ -1161,8 +1160,6 @@
     // Page messages.
     IPC_MESSAGE_HANDLER(PageMsg_SetHistoryOffsetAndLength,
                         OnSetHistoryOffsetAndLength)
-    IPC_MESSAGE_HANDLER(PageMsg_UpdateTextAutosizerPageInfoForRemoteMainFrames,
-                        OnTextAutosizerPageInfoChanged)
     IPC_MESSAGE_HANDLER(PageMsg_SetRendererPrefs, OnSetRendererPrefs)
 
     // Adding a new message? Add platform independent ones first, then put the
@@ -1560,6 +1557,16 @@
     observer.OnPageVisibilityChanged(visibility);
 }
 
+void RenderViewImpl::OnPageFrozenChanged(bool frozen) {
+  if (frozen) {
+    // Make sure browser has the latest info before the page is frozen. If the
+    // page goes into the back-forward cache it could be evicted and some of the
+    // updates lost.
+    nav_state_sync_timer_.Stop();
+    SendFrameStateUpdates();
+  }
+}
+
 bool RenderViewImpl::CanUpdateLayout() {
   return true;
 }
@@ -1668,20 +1675,6 @@
     GetWebView()->SetPageFrozen(frozen);
 }
 
-// This function receives TextAutosizerPageInfo from the main frame's renderer
-// and makes it available to other renderers with frames on the same page.
-void RenderViewImpl::OnTextAutosizerPageInfoChanged(
-    const blink::WebTextAutosizerPageInfo& page_info) {
-  // Only propagate the remote page info if our main frame is remote. It's
-  // possible a main frame renderer may receive this message, as SendPageMessage
-  // in RenderFrameHostManager may send to a speculative RenderFrameHost that
-  // corresponds to a local main frame. Since a local main frame will generate
-  // these values for itself, we shouldn't override them with values from
-  // another renderer.
-  if (!GetWebView()->MainFrame()->IsWebLocalFrame())
-    GetWebView()->SetTextAutosizerPageInfo(page_info);
-}
-
 void RenderViewImpl::DidAutoResize(const blink::WebSize& newSize) {
   // Auto resize should only happen on local main frames.
   DCHECK(main_render_frame_);
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index d3d1c042..780c4bf 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -235,6 +235,7 @@
   bool CanHandleGestureEvent() override;
   bool AllowPopupsDuringPageUnload() override;
   void OnPageVisibilityChanged(PageVisibilityState visibility) override;
+  void OnPageFrozenChanged(bool frozen) override;
   void ZoomLevelChanged() override;
 
   // RenderView implementation -------------------------------------------------
@@ -394,8 +395,6 @@
 
   // Page message handlers -----------------------------------------------------
   void SetPageFrozen(bool frozen);
-  void OnTextAutosizerPageInfoChanged(
-      const blink::WebTextAutosizerPageInfo& page_info);
 
   // Adding a new message handler? Please add it in alphabetical order above
   // and put it in the same position in the .cc file.
diff --git a/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored-expected-win.txt b/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored-expected-win.txt
new file mode 100644
index 0000000..de0c564
--- /dev/null
+++ b/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored-expected-win.txt
@@ -0,0 +1,4 @@
+EVENT_OBJECT_HIDE on <div#heading-root.a> role=ROLE_SYSTEM_GROUPING name="Heading" INVISIBLE level=2
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL
+IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL new_text={'<obj>' start=0 end=1}
+IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL old_text={'<obj>' start=0 end=1}
diff --git a/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored.html b/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored.html
new file mode 100644
index 0000000..b1f94e799
--- /dev/null
+++ b/content/test/data/accessibility/event/aria-hidden-descendants-already-ignored.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<body>
+<!-- Hide events only need to occur on the root of what's shown/hidden,
+     not for each descendant, with some descendants already ignored. -->
+<div role="toolbar">
+  <div id="heading-root" role="heading" aria-label="Heading" class="a">
+    <div> <!-- already ignored-->
+      <div> <!-- already ignored -->
+        <div id="heading-child">
+          <div id="heading-grandchild"></div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+<script>
+  function go() {
+    document.querySelector('.a').setAttribute("aria-hidden", "true");
+  }
+</script>
+</body>
+</html>
diff --git a/content/test/data/accessibility/event/aria-hidden-descendants-expected-win.txt b/content/test/data/accessibility/event/aria-hidden-descendants-expected-win.txt
new file mode 100644
index 0000000..269850a
--- /dev/null
+++ b/content/test/data/accessibility/event/aria-hidden-descendants-expected-win.txt
@@ -0,0 +1,5 @@
+EVENT_OBJECT_HIDE on <div#heading-root.a> role=ROLE_SYSTEM_GROUPING name="Heading" INVISIBLE level=2
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL
+EVENT_OBJECT_SHOW on <div#banner-root.b> role=ROLE_SYSTEM_GROUPING name="Banner"
+IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL new_text={'<obj>' start=0 end=1}
+IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL old_text={'<obj>' start=0 end=1}
diff --git a/content/test/data/accessibility/event/aria-hidden-descendants.html b/content/test/data/accessibility/event/aria-hidden-descendants.html
new file mode 100644
index 0000000..ab2441d
--- /dev/null
+++ b/content/test/data/accessibility/event/aria-hidden-descendants.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<body>
+<!-- Show/hide events only need to occur on the root of what's shown/hidden,
+     not for each descendant -->
+<div role="toolbar">
+  <div id="heading-root" role="heading" aria-label="Heading" class="a">
+    <div id="heading-child">
+      <div id="heading-grandchild"></div>
+    </div>
+  </div>
+  <div id="banner-root" role="banner" aria-label="Banner" aria-hidden="true" class="b">
+    <div id="banner-child">
+      <div id="banner-grandchild"></div>
+    </div>
+  </div>
+</div>
+<script>
+  function go() {
+    document.querySelector('.a').setAttribute("aria-hidden", "true");
+    document.querySelector('.b').removeAttribute("aria-hidden");
+  }
+</script>
+</body>
+</html>
diff --git a/content/test/data/accessibility/event/caret-hide.html b/content/test/data/accessibility/event/caret-hide.html
index 0845f54b..1d9b4b2 100644
--- a/content/test/data/accessibility/event/caret-hide.html
+++ b/content/test/data/accessibility/event/caret-hide.html
@@ -1,5 +1,5 @@
 <!--
-@RUN-UNTIL-EVENT:EVENT_OBJECT_VALUECHANGE
+@WIN-RUN-UNTIL-EVENT:EVENT_OBJECT_VALUECHANGE
 @WIN-DENY:IA2_EVENT_TEXT_INSERTED*
 @WIN-DENY:IA2_EVENT_TEXT_REMOVED*
 -->
@@ -22,4 +22,4 @@
 }
 </script>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/content/test/data/accessibility/event/caret-move.html b/content/test/data/accessibility/event/caret-move.html
index a4b641b..357ff32 100644
--- a/content/test/data/accessibility/event/caret-move.html
+++ b/content/test/data/accessibility/event/caret-move.html
@@ -1,5 +1,5 @@
 <!--
-@RUN-UNTIL-EVENT:EVENT_OBJECT_VALUECHANGE
+@WIN-RUN-UNTIL-EVENT:EVENT_OBJECT_VALUECHANGE
 @WIN-DENY:IA2_EVENT_TEXT_INSERTED*
 @WIN-DENY:IA2_EVENT_TEXT_REMOVED*
 -->
@@ -22,4 +22,4 @@
 }
 </script>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/content/test/data/accessibility/event/css-display-descendants-expected-win.txt b/content/test/data/accessibility/event/css-display-descendants-expected-win.txt
new file mode 100644
index 0000000..ea4bec0
--- /dev/null
+++ b/content/test/data/accessibility/event/css-display-descendants-expected-win.txt
@@ -0,0 +1,6 @@
+EVENT_OBJECT_HIDE on <div#heading-root.a> role=ROLE_SYSTEM_GROUPING name="Heading" level=2
+EVENT_OBJECT_REORDER on <div#banner-child> role=ROLE_SYSTEM_GROUPING
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL
+EVENT_OBJECT_SHOW on <div#banner-root.b> role=ROLE_SYSTEM_GROUPING name="Banner"
+IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL new_text={'<obj>' start=0 end=1}
+IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL old_text={'<obj>' start=0 end=1}
diff --git a/content/test/data/accessibility/event/css-display-descendants.html b/content/test/data/accessibility/event/css-display-descendants.html
new file mode 100644
index 0000000..832d8dbe
--- /dev/null
+++ b/content/test/data/accessibility/event/css-display-descendants.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+  .a { display: block; }
+  .b { display: none; }
+  body.flip .a { display: none; }
+  body.flip .b { display: block; }
+</style>
+</head>
+<body>
+<!-- Show/hide events only need to occur on the root of what's shown/hidden,
+     not for each descendant -->
+<div role="toolbar">
+  <div id="heading-root" role="heading" aria-label="Heading" class="a">
+    <div id="heading-child">
+      <div id="heading-grandchild"></div>
+    </div>
+  </div>
+  <div id="banner-root" role="banner" aria-label="Banner" class="b">
+    <div id="banner-child">
+      <div id="banner-grandchild"></div>
+    </div>
+  </div>
+</div>
+<script>
+  function go() {
+    document.body.className = 'flip';
+  }
+</script>
+</body>
+</html>
diff --git a/content/test/data/accessibility/event/css-visibility-descendants-expected-win.txt b/content/test/data/accessibility/event/css-visibility-descendants-expected-win.txt
new file mode 100644
index 0000000..269850a
--- /dev/null
+++ b/content/test/data/accessibility/event/css-visibility-descendants-expected-win.txt
@@ -0,0 +1,5 @@
+EVENT_OBJECT_HIDE on <div#heading-root.a> role=ROLE_SYSTEM_GROUPING name="Heading" INVISIBLE level=2
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL
+EVENT_OBJECT_SHOW on <div#banner-root.b> role=ROLE_SYSTEM_GROUPING name="Banner"
+IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL new_text={'<obj>' start=0 end=1}
+IA2_EVENT_TEXT_REMOVED on <div> role=ROLE_SYSTEM_TOOLBAR IA2_STATE_HORIZONTAL old_text={'<obj>' start=0 end=1}
diff --git a/content/test/data/accessibility/event/css-visibility-descendants.html b/content/test/data/accessibility/event/css-visibility-descendants.html
new file mode 100644
index 0000000..002e2b9
--- /dev/null
+++ b/content/test/data/accessibility/event/css-visibility-descendants.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+  .a { visibility: visible; }
+  .b { visibility: hidden; }
+  body.flip .a { visibility: hidden; }
+  body.flip .b { visibility: visible; }
+</style>
+</head>
+<body>
+<!-- Show/hide events only need to occur on the root of what's shown/hidden,
+     not for each descendant -->
+<div role="toolbar">
+  <div id="heading-root" role="heading" aria-label="Heading" class="a">
+    <div id="heading-child">
+      <div id="heading-grandchild"></div>
+    </div>
+  </div>
+  <div id="banner-root" role="banner" aria-label="Banner" class="b">
+    <div id="banner-child">
+      <div id="banner-grandchild"></div>
+    </div>
+  </div>
+</div>
+<script>
+  function go() {
+    document.body.className = 'flip';
+  }
+</script>
+</body>
+</html>
diff --git a/content/test/data/accessibility/readme.md b/content/test/data/accessibility/readme.md
index 833f390..dd12d32 100644
--- a/content/test/data/accessibility/readme.md
+++ b/content/test/data/accessibility/readme.md
@@ -127,14 +127,15 @@
 Example: `@EXECUTE-AND-WAIT-FOR: foo()`
 
 Or, you may need to write an event test that keeps dumping events until a
-specific event line. In this case, use `@RUN-UNTIL-EVENT` with a substring that
-should occur in the event log, e.g.,
-`@RUN-UNTIL-EVENT:IA2_EVENT_TEXT_CARET_MOVED`. Note that `@RUN-UNTIL-EVENT` is
-only used in dump events tests, and not used in dump tree tests.
+specific event line. In this case, use `@WIN-RUN-UNTIL-EVENT` (or similar for
+other platforms) with a substring that should occur in the event log, e.g.,
+`@WIN-RUN-UNTIL-EVENT:IA2_EVENT_TEXT_CARET_MOVED`.
+Note that `@*-RUN-UNTIL-EVENT` is only used in dump events tests, and not used
+in dump tree tests.
 
-If you add multiple `@RUN-UNTIL-EVENT` directives, the test will finish once any
-of them are satisfied. Note that any other events that come along with the last
-event will also be logged.
+If you add multiple `@*-RUN-UNTIL-EVENT` directives, the test will finish once
+any of them are satisfied. Note that any other events that come along with the
+last event will also be logged.
 
 To skip dumping a particular element, make its accessible name equal to
 `@NO_DUMP`, for example `<div aria-label="@NO_DUMP"></div>`.
diff --git a/content/test/data/conversions/register_conversion.js b/content/test/data/conversions/register_conversion.js
index fafe72c..14a6e9b 100644
--- a/content/test/data/conversions/register_conversion.js
+++ b/content/test/data/conversions/register_conversion.js
@@ -12,6 +12,7 @@
   img.src = origin +
       "/server-redirect?.well-known/register-conversion?conversion-data=" +
       data;
+  img.onerror = function () { document.title = "converted"; };
   document.body.appendChild(img);
 }
 
diff --git a/content/test/data/media/getusermedia.html b/content/test/data/media/getusermedia.html
index 15296225..e8d2ed54 100644
--- a/content/test/data/media/getusermedia.html
+++ b/content/test/data/media/getusermedia.html
@@ -689,39 +689,41 @@
   }
 
   function applyConstraintsVideoTwoStreams() {
-    navigator.mediaDevices.getUserMedia({video:true})
-      .then(stream => {
+    navigator.mediaDevices.getUserMedia({
+        video:{
+            width:{exact:640},
+            height: {exact:480}
+        }
+    }).then(stream => {
         assertEquals(stream.getVideoTracks().length, 1);
-        var track1 = stream.getVideoTracks()[0];
+        let track1 = stream.getVideoTracks()[0];
+        let deviceId1 = track1.getSettings().deviceId;
         track1.onmute = () => failTest("Unexpected mute of track1");
         track1.onunmute = () => failTest("Unexpected unmute of track1");
-        var settings1 = track1.getSettings();
-        var default_device_id = settings1.deviceId;
-        var default_width = settings1.width;
-        var default_height = settings1.height;
-        return navigator.mediaDevices.getUserMedia({video:true})
-          .then(stream2 => {
-            var track2 = stream2.getVideoTracks()[0];
+        return navigator.mediaDevices.getUserMedia({
+            video:{
+                deviceId: {exact: deviceId1},
+                width:{exact:640},
+                height: {exact:480}
+            }
+        }).then(stream2 => {
+            let track2 = stream2.getVideoTracks()[0];
             track2.onmute = () => failTest("Unexpected mute of track2");
             track2.onunmute = () => failTest("Unexpected unmute of track2");
-            var settings2 = track2.getSettings();
-            assertEquals(settings2.width, default_width);
-            assertEquals(settings2.height, default_height);
-            assertEquals(settings2.deviceId, default_device_id);
             return track1.applyConstraints({
-              width: default_width-1,
-              height: default_height-1
+              width: {exact: 639},
+              height: {exact: 479}
             }).then(()=> {
               assertEquals(track1.readyState, "live");
-              settings1 = track1.getSettings();
-              assertEquals(settings1.deviceId, default_device_id);
-              assertEquals(settings1.width, default_width - 1);
-              assertEquals(settings1.height, default_height - 1);
+              let settings1 = track1.getSettings();
+              assertEquals(639, settings1.width);
+              assertEquals(479, settings1.height);
               assertEquals(track2.readyState, "live");
-              settings2 = track2.getSettings();
-              assertEquals(settings2.deviceId, default_device_id);
-              assertEquals(settings2.width, default_width);
-              assertEquals(settings2.height, default_height);
+              let settings2 = track2.getSettings();
+              assertEquals(640, settings2.width);
+              assertEquals(480, settings2.height);
+              assertEquals(deviceId1, settings1.deviceId);
+              assertEquals(deviceId1, settings2.deviceId);
               track1.stop();
               track2.stop();
               reportTestSuccess();
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index 29effcf..14e07685 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -69,6 +69,10 @@
   # Android implementation of FIDO is delegated to GMSCore.
   if (!is_android) {
     sources += [
+      "aoa/android_accessory_device.cc",
+      "aoa/android_accessory_device.h",
+      "aoa/android_accessory_discovery.cc",
+      "aoa/android_accessory_discovery.h",
       "attestation_object.cc",
       "attestation_object.h",
       "attestation_statement.cc",
@@ -183,7 +187,9 @@
 
     deps += [
       "//services/device/public/cpp/hid",
+      "//services/device/public/cpp/usb",
       "//services/device/public/mojom",
+      "//services/device/public/mojom:usb",
     ]
   }
 
diff --git a/device/fido/aoa/android_accessory_device.cc b/device/fido/aoa/android_accessory_device.cc
new file mode 100644
index 0000000..3445015
--- /dev/null
+++ b/device/fido/aoa/android_accessory_device.cc
@@ -0,0 +1,155 @@
+// 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 "device/fido/aoa/android_accessory_device.h"
+
+#include <limits>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/notreached.h"
+#include "base/optional.h"
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/device_event_log/device_event_log.h"
+
+namespace device {
+
+static constexpr unsigned kTimeoutMilliseconds = 1000;
+static constexpr unsigned kLongTimeoutMilliseconds = 90 * 1000;
+
+AndroidAccessoryDevice::AndroidAccessoryDevice(
+    mojo::Remote<mojom::UsbDevice> device,
+    uint8_t in_endpoint,
+    uint8_t out_endpoint)
+    : device_(std::move(device)),
+      in_endpoint_(in_endpoint),
+      out_endpoint_(out_endpoint) {
+  base::RandBytes(id_, sizeof(id_));
+}
+
+AndroidAccessoryDevice::~AndroidAccessoryDevice() = default;
+
+FidoDevice::CancelToken AndroidAccessoryDevice::DeviceTransact(
+    std::vector<uint8_t> command,
+    DeviceCallback callback) {
+  if (static_cast<uint64_t>(command.size()) >
+      std::numeric_limits<uint32_t>::max()) {
+    NOTREACHED();
+    std::move(callback).Run(base::nullopt);
+    return 0;
+  }
+
+  uint8_t prefix[1 + sizeof(uint32_t)];
+  prefix[0] = kCoaoaMsg;
+  const uint32_t size32 = static_cast<uint32_t>(command.size());
+  memcpy(&prefix[1], &size32, sizeof(size32));
+
+  command.insert(command.begin(), prefix, &prefix[sizeof(prefix)]);
+
+  device_->GenericTransferOut(
+      out_endpoint_, std::move(command), kTimeoutMilliseconds,
+      base::BindOnce(&AndroidAccessoryDevice::OnWriteComplete,
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
+
+  return 0;
+}
+
+void AndroidAccessoryDevice::OnWriteComplete(DeviceCallback callback,
+                                             mojom::UsbTransferStatus result) {
+  if (result != mojom::UsbTransferStatus::COMPLETED) {
+    FIDO_LOG(ERROR) << "Failed to write to USB device ("
+                    << static_cast<int>(result) << ").";
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+
+  device_->GenericTransferIn(
+      in_endpoint_, 1 + sizeof(uint32_t), kLongTimeoutMilliseconds,
+      base::BindOnce(&AndroidAccessoryDevice::OnReadLengthComplete,
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void AndroidAccessoryDevice::OnReadLengthComplete(
+    DeviceCallback callback,
+    mojom::UsbTransferStatus result,
+    const std::vector<uint8_t>& payload) {
+  if (result != mojom::UsbTransferStatus::COMPLETED ||
+      payload.size() != 1 + sizeof(uint32_t)) {
+    FIDO_LOG(ERROR) << "Failed to read reply from USB device ("
+                    << static_cast<int>(result) << ")";
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+
+  if (payload[0] != kCoaoaMsg) {
+    FIDO_LOG(ERROR) << "Reply from USB device with wrong type ("
+                    << static_cast<int>(payload[0]) << ")";
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+
+  uint32_t length;
+  memcpy(&length, &payload[1], sizeof(length));
+  if (length > (1 << 20)) {
+    FIDO_LOG(ERROR) << "USB device sent excessive reply containing " << length
+                    << " bytes";
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+
+  buffer_.clear();
+  buffer_.reserve(length);
+
+  if (length == 0) {
+    std::move(callback).Run(std::move(buffer_));
+    return;
+  }
+
+  device_->GenericTransferIn(
+      in_endpoint_, length, kTimeoutMilliseconds,
+      base::BindOnce(&AndroidAccessoryDevice::OnReadComplete,
+                     weak_factory_.GetWeakPtr(), std::move(callback), length));
+}
+
+void AndroidAccessoryDevice::OnReadComplete(
+    DeviceCallback callback,
+    const uint32_t length,
+    mojom::UsbTransferStatus result,
+    const std::vector<uint8_t>& payload) {
+  if (result != mojom::UsbTransferStatus::COMPLETED ||
+      payload.size() + buffer_.size() > length) {
+    FIDO_LOG(ERROR) << "Failed to read from USB device ("
+                    << static_cast<int>(result) << ")";
+    std::move(callback).Run(base::nullopt);
+    return;
+  }
+
+  buffer_.insert(buffer_.end(), payload.begin(), payload.end());
+  if (buffer_.size() == length) {
+    std::move(callback).Run(std::move(buffer_));
+    return;
+  }
+
+  device_->GenericTransferIn(
+      in_endpoint_, length - buffer_.size(), kTimeoutMilliseconds,
+      base::BindOnce(&AndroidAccessoryDevice::OnReadComplete,
+                     weak_factory_.GetWeakPtr(), std::move(callback), length));
+}
+
+void AndroidAccessoryDevice::Cancel(CancelToken token) {}
+
+std::string AndroidAccessoryDevice::GetId() const {
+  return "aoa-" + base::HexEncode(id_);
+}
+
+FidoTransportProtocol AndroidAccessoryDevice::DeviceTransport() const {
+  return FidoTransportProtocol::kAndroidAccessory;
+}
+
+base::WeakPtr<FidoDevice> AndroidAccessoryDevice::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
+}  // namespace device
diff --git a/device/fido/aoa/android_accessory_device.h b/device/fido/aoa/android_accessory_device.h
new file mode 100644
index 0000000..6760074
--- /dev/null
+++ b/device/fido/aoa/android_accessory_device.h
@@ -0,0 +1,64 @@
+// 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 DEVICE_FIDO_AOA_ANDROID_ACCESSORY_DEVICE_H_
+#define DEVICE_FIDO_AOA_ANDROID_ACCESSORY_DEVICE_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "device/fido/fido_device.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/device/public/mojom/usb_device.mojom.h"
+
+namespace device {
+
+// AndroidAccessoryDevice sends CTAP messages over USB to a given device.
+class COMPONENT_EXPORT(DEVICE_FIDO) AndroidAccessoryDevice : public FidoDevice {
+ public:
+  // These enum values are magic values on the wire that indicate a
+  // synchronisation message and a CTAP2 message, respectively.
+  enum {
+    kCoaoaSync = 119,
+    kCoaoaMsg = 33,
+  };
+
+  AndroidAccessoryDevice(mojo::Remote<device::mojom::UsbDevice> device,
+                         uint8_t in_endpoint,
+                         uint8_t out_endpoint);
+  ~AndroidAccessoryDevice() override;
+
+  // FidoDevice:
+  CancelToken DeviceTransact(std::vector<uint8_t> command,
+                             DeviceCallback callback) override;
+  void Cancel(CancelToken token) override;
+  std::string GetId() const override;
+  FidoTransportProtocol DeviceTransport() const override;
+  base::WeakPtr<FidoDevice> GetWeakPtr() override;
+
+ private:
+  void OnWriteComplete(DeviceCallback callback,
+                       device::mojom::UsbTransferStatus result);
+  void OnReadLengthComplete(DeviceCallback callback,
+                            device::mojom::UsbTransferStatus result,
+                            const std::vector<uint8_t>& payload);
+  void OnReadComplete(DeviceCallback callback,
+                      const uint32_t length,
+                      device::mojom::UsbTransferStatus result,
+                      const std::vector<uint8_t>& payload);
+
+  mojo::Remote<device::mojom::UsbDevice> device_;
+  const uint8_t in_endpoint_;
+  const uint8_t out_endpoint_;
+  uint8_t id_[8];
+
+  std::vector<uint8_t> buffer_;
+
+  base::WeakPtrFactory<AndroidAccessoryDevice> weak_factory_{this};
+};
+
+}  // namespace device
+
+#endif  // DEVICE_FIDO_AOA_ANDROID_ACCESSORY_DEVICE_H_
diff --git a/device/fido/aoa/android_accessory_discovery.cc b/device/fido/aoa/android_accessory_discovery.cc
new file mode 100644
index 0000000..fec676d
--- /dev/null
+++ b/device/fido/aoa/android_accessory_discovery.cc
@@ -0,0 +1,422 @@
+// 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 "device/fido/aoa/android_accessory_discovery.h"
+
+#include "base/containers/flat_set.h"
+#include "base/location.h"
+#include "base/no_destructor.h"
+#include "base/rand_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/device_event_log/device_event_log.h"
+#include "device/fido/aoa/android_accessory_device.h"
+#include "services/device/public/mojom/usb_manager.mojom.h"
+#include "services/device/public/mojom/usb_manager_client.mojom.h"
+
+#include <utility>
+
+#include "base/bind.h"
+
+// See https://source.android.com/devices/accessories/aoa for details on the
+// protocol used to talk to apps on the phone here.
+
+namespace device {
+
+// KnownAccessories returns a global that stores the GUIDs of USB devices that
+// we have previously put into accessory mode and, if still connected, can be
+// used immediately. (GUIDs are not a USB concept, the Chromium USB layer
+// generates them to identity a specific USB connection.)
+static base::flat_set<std::string>& KnownAccessories() {
+  static base::NoDestructor<base::flat_set<std::string>> set;
+  return *set;
+}
+
+AndroidAccessoryDiscovery::AndroidAccessoryDiscovery(
+    mojo::Remote<device::mojom::UsbDeviceManager> device_manager)
+    : FidoDeviceDiscovery(FidoTransportProtocol::kUsbHumanInterfaceDevice),
+      device_manager_(std::move(device_manager)) {}
+
+AndroidAccessoryDiscovery::~AndroidAccessoryDiscovery() = default;
+
+void AndroidAccessoryDiscovery::StartInternal() {
+  FIDO_LOG(DEBUG) << "Android accessory discovery started";
+  device_manager_->EnumerateDevicesAndSetClient(
+      receiver_.BindNewEndpointAndPassRemote(),
+      base::BindOnce(&AndroidAccessoryDiscovery::OnGetDevices,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void AndroidAccessoryDiscovery::OnDeviceAdded(
+    device::mojom::UsbDeviceInfoPtr device_info) {
+  if (device_info->class_code != 0 || device_info->subclass_code != 0) {
+    FIDO_LOG(DEBUG) << "Ignoring new USB device with class: "
+                    << device_info->class_code
+                    << " subclass: " << device_info->subclass_code;
+    return;
+  }
+
+  mojo::Remote<device::mojom::UsbDevice> device;
+  device_manager_->GetDevice(device_info->guid,
+                             device.BindNewPipeAndPassReceiver(),
+                             mojo::NullRemote() /* device_client */);
+
+  auto* device_ptr = device.get();
+  if (device_info->vendor_id == 0x18d1 &&
+      (device_info->product_id & ~1) == 0x2d00) {
+    HandleAccessoryDevice(std::move(device), std::move(device_info));
+    return;
+  }
+
+  // Attempt to reconfigure the device into accessory mode.
+  device_ptr->Open(base::BindOnce(&AndroidAccessoryDiscovery::OnOpen,
+                                  weak_factory_.GetWeakPtr(),
+                                  std::move(device)));
+}
+
+static base::Optional<AndroidAccessoryDiscovery::InterfaceInfo>
+FindAccessoryInterface(const device::mojom::UsbDeviceInfoPtr& device_info) {
+  for (const device::mojom::UsbConfigurationInfoPtr& config :
+       device_info->configurations) {
+    for (const device::mojom::UsbInterfaceInfoPtr& interface :
+         config->interfaces) {
+      if (interface->alternates.empty()) {
+        // I don't believe that this is possible in USB.
+        continue;
+      }
+
+      const device::mojom::UsbAlternateInterfaceInfoPtr& info =
+          interface->alternates[0];
+      if (info->class_code == 0xff && info->subclass_code == 0xff &&
+          info->endpoints.size() == 2) {
+        // This is the AOA interface. (ADB, if enabled, has a subclass of 66.)
+        base::Optional<uint8_t> in_endpoint_num;
+        base::Optional<uint8_t> out_endpoint_num;
+
+        for (const device::mojom::UsbEndpointInfoPtr& endpoint :
+             info->endpoints) {
+          if (endpoint->direction == mojom::UsbTransferDirection::INBOUND) {
+            in_endpoint_num = endpoint->endpoint_number;
+          } else {
+            out_endpoint_num = endpoint->endpoint_number;
+          }
+        }
+
+        if (!in_endpoint_num || !out_endpoint_num) {
+          continue;
+        }
+
+        return AndroidAccessoryDiscovery::InterfaceInfo{
+            .configuration = config->configuration_value,
+            .interface = interface->interface_number,
+            .in_endpoint = *in_endpoint_num,
+            .out_endpoint = *out_endpoint_num,
+            .guid = device_info->guid,
+        };
+      }
+    }
+  }
+
+  return base::nullopt;
+}
+
+void AndroidAccessoryDiscovery::HandleAccessoryDevice(
+    mojo::Remote<device::mojom::UsbDevice> device,
+    device::mojom::UsbDeviceInfoPtr device_info) {
+  auto interface_info = FindAccessoryInterface(device_info);
+  if (!interface_info) {
+    FIDO_LOG(ERROR) << "Failed to find accessory interface on device";
+    return;
+  }
+
+  auto* device_ptr = device.get();
+  device_ptr->Open(base::BindOnce(&AndroidAccessoryDiscovery::OnOpenAccessory,
+                                  weak_factory_.GetWeakPtr(), std::move(device),
+                                  std::move(device_info), *interface_info));
+}
+
+enum AccessoryControlRequest : uint8_t {
+  kGetProtocol = 51,
+  kSendString = 52,
+  kStart = 53,
+};
+
+static mojom::UsbControlTransferParamsPtr ControlTransferParams(
+    AccessoryControlRequest request,
+    uint16_t index = 0) {
+  auto ret = mojom::UsbControlTransferParams::New();
+  ret->type = mojom::UsbControlTransferType::VENDOR;
+  ret->recipient = mojom::UsbControlTransferRecipient::DEVICE;
+  ret->request = request;
+  ret->value = 0;
+  ret->index = index;
+
+  return ret;
+}
+
+static constexpr unsigned kTimeoutMilliseconds = 1000;
+static constexpr unsigned kLongTimeoutMilliseconds = 90 * 1000;
+
+void AndroidAccessoryDiscovery::OnOpenAccessory(
+    mojo::Remote<device::mojom::UsbDevice> device,
+    device::mojom::UsbDeviceInfoPtr device_info,
+    InterfaceInfo interface_info,
+    device::mojom::UsbOpenDeviceError error) {
+  switch (error) {
+    case mojom::UsbOpenDeviceError::OK:
+    case mojom::UsbOpenDeviceError::ALREADY_OPEN:
+      break;
+    default:
+      FIDO_LOG(DEBUG) << "Failed to open accessory device. Ignoring.";
+      return;
+  }
+
+  FIDO_LOG(DEBUG) << "Accessory USB device opened";
+
+  if (interface_info.configuration != device_info->active_configuration) {
+    FIDO_LOG(DEBUG) << "Setting device configuration "
+                    << interface_info.configuration;
+    auto* device_ptr = device.get();
+    device_ptr->SetConfiguration(
+        interface_info.configuration,
+        base::BindOnce(&AndroidAccessoryDiscovery::OnAccessoryConfigured,
+                       weak_factory_.GetWeakPtr(), std::move(device),
+                       interface_info));
+  }
+
+  OnAccessoryConfigured(std::move(device), interface_info, /*success=*/true);
+}
+
+void AndroidAccessoryDiscovery::OnAccessoryConfigured(
+    mojo::Remote<device::mojom::UsbDevice> device,
+    InterfaceInfo interface_info,
+    bool success) {
+  if (!success) {
+    FIDO_LOG(DEBUG) << "Failed to set configuration on an accessory device";
+    return;
+  }
+
+  auto* device_ptr = device.get();
+  device_ptr->ClaimInterface(
+      interface_info.interface,
+      base::BindOnce(&AndroidAccessoryDiscovery::OnAccessoryInterfaceClaimed,
+                     weak_factory_.GetWeakPtr(), std::move(device),
+                     interface_info));
+}
+
+void AndroidAccessoryDiscovery::OnAccessoryInterfaceClaimed(
+    mojo::Remote<device::mojom::UsbDevice> device,
+    InterfaceInfo interface_info,
+    bool success) {
+  if (!success) {
+    FIDO_LOG(DEBUG) << "Failed to claim interface on an accessory device";
+    return;
+  }
+
+  std::array<uint8_t, kSyncNonceLength> nonce;
+  base::RandBytes(&nonce[0], kSyncNonceLength);
+
+  std::vector<uint8_t> packet;
+  packet.push_back(AndroidAccessoryDevice::kCoaoaSync);
+  packet.insert(packet.end(), nonce.begin(), nonce.end());
+
+  auto* device_ptr = device.get();
+  const uint8_t out_endpoint = interface_info.out_endpoint;
+  device_ptr->GenericTransferOut(
+      out_endpoint, std::move(packet), kLongTimeoutMilliseconds,
+      base::BindOnce(&AndroidAccessoryDiscovery::OnSyncWritten,
+                     weak_factory_.GetWeakPtr(), std::move(device),
+                     std::move(interface_info), nonce));
+}
+
+void AndroidAccessoryDiscovery::OnSyncWritten(
+    mojo::Remote<device::mojom::UsbDevice> device,
+    InterfaceInfo interface_info,
+    std::array<uint8_t, kSyncNonceLength> nonce,
+    mojom::UsbTransferStatus result) {
+  if (result != mojom::UsbTransferStatus::COMPLETED) {
+    FIDO_LOG(ERROR) << "Failed to write to USB device ("
+                    << static_cast<int>(result) << ").";
+    return;
+  }
+
+  FIDO_LOG(DEBUG) << "Awaiting response to sync message";
+
+  auto* device_ptr = device.get();
+  const uint8_t in_endpoint = interface_info.in_endpoint;
+  device_ptr->GenericTransferIn(
+      in_endpoint, kSyncMessageLength, kTimeoutMilliseconds,
+      base::BindOnce(&AndroidAccessoryDiscovery::OnReadComplete,
+                     weak_factory_.GetWeakPtr(), std::move(device),
+                     std::move(interface_info), nonce));
+}
+
+void AndroidAccessoryDiscovery::OnReadComplete(
+    mojo::Remote<device::mojom::UsbDevice> device,
+    InterfaceInfo interface_info,
+    std::array<uint8_t, kSyncNonceLength> nonce,
+    mojom::UsbTransferStatus result,
+    const std::vector<uint8_t>& payload) {
+  // BABBLE results if the message from the USB peer was longer than expected.
+  // That's fine because we're expecting potentially discard some messages in
+  // order to find the sync message.
+  if (result != mojom::UsbTransferStatus::COMPLETED &&
+      result != mojom::UsbTransferStatus::BABBLE) {
+    FIDO_LOG(ERROR) << "Failed to read from USB device ("
+                    << static_cast<int>(result) << ").";
+    return;
+  }
+
+  if (result == mojom::UsbTransferStatus::COMPLETED &&
+      payload.size() == kSyncMessageLength &&
+      payload[0] == AndroidAccessoryDevice::kCoaoaSync &&
+      memcmp(&payload[1], nonce.data(), kSyncNonceLength) == 0) {
+    FIDO_LOG(DEBUG) << "Accessory device discovered";
+    KnownAccessories().insert(interface_info.guid);
+    AddDevice(std::make_unique<AndroidAccessoryDevice>(
+        std::move(device), interface_info.in_endpoint,
+        interface_info.out_endpoint));
+    return;
+  }
+
+  auto* device_ptr = device.get();
+  const uint8_t in_endpoint = interface_info.in_endpoint;
+  device_ptr->GenericTransferIn(
+      in_endpoint, kSyncMessageLength, kTimeoutMilliseconds,
+      base::BindOnce(&AndroidAccessoryDiscovery::OnReadComplete,
+                     weak_factory_.GetWeakPtr(), std::move(device),
+                     std::move(interface_info), nonce));
+}
+
+void AndroidAccessoryDiscovery::OnOpen(
+    mojo::Remote<device::mojom::UsbDevice> device,
+    device::mojom::UsbOpenDeviceError error) {
+  switch (error) {
+    case mojom::UsbOpenDeviceError::OK:
+    case mojom::UsbOpenDeviceError::ALREADY_OPEN:
+      break;
+    default:
+      FIDO_LOG(DEBUG) << "Failed to open USB device. Ignoring.";
+      return;
+  }
+
+  auto* device_ptr = device.get();
+  device_ptr->ControlTransferIn(
+      ControlTransferParams(kGetProtocol),
+      /* reply length */ 2, kTimeoutMilliseconds,
+      base::BindOnce(&AndroidAccessoryDiscovery::OnVersionReply,
+                     weak_factory_.GetWeakPtr(), std::move(device)));
+}
+
+void AndroidAccessoryDiscovery::OnVersionReply(
+    mojo::Remote<device::mojom::UsbDevice> device,
+    device::mojom::UsbTransferStatus status,
+    const std::vector<uint8_t>& payload) {
+  if (status != mojom::UsbTransferStatus::COMPLETED || payload.size() != 2) {
+    FIDO_LOG(DEBUG) << "Android AOA version request failed with status: "
+                    << static_cast<unsigned>(status)
+                    << " payload.size: " << payload.size()
+                    << ". Ignoring device.";
+    return;
+  }
+
+  const uint16_t version = static_cast<uint16_t>(payload[0]) |
+                           (static_cast<uint16_t>(payload[1]) << 8);
+
+  if (version == 0) {
+    FIDO_LOG(DEBUG)
+        << "Android AOA version one not supported. Ignoring device.";
+    return;
+  }
+
+  OnConfigurationStepComplete(std::move(device), 0,
+                              mojom::UsbTransferStatus::COMPLETED);
+}
+
+static std::vector<uint8_t> VectorFromString(const char* str) {
+  return std::vector<uint8_t>(
+      reinterpret_cast<const uint8_t*>(str),
+      reinterpret_cast<const uint8_t*>(str + strlen(str) + 1));
+}
+
+void AndroidAccessoryDiscovery::OnConfigurationStepComplete(
+    mojo::Remote<device::mojom::UsbDevice> device,
+    unsigned step,
+    device::mojom::UsbTransferStatus status) {
+  if (status != mojom::UsbTransferStatus::COMPLETED) {
+    FIDO_LOG(DEBUG) << "Android AOA configuration failed at step " << step;
+    return;
+  }
+
+  static const size_t kNumStrings = 3;
+  static const char kStrings[kNumStrings][24] = {
+      "Chromium",              // manufacturer
+      "Chromium",              // model
+      "Security key request",  // description. TODO(agl): translate.
+  };
+
+  auto* device_ptr = device.get();
+  if (step < kNumStrings) {
+    device_ptr->ControlTransferOut(
+        ControlTransferParams(kSendString, step),
+        VectorFromString(kStrings[step]), kTimeoutMilliseconds,
+        base::BindOnce(&AndroidAccessoryDiscovery::OnConfigurationStepComplete,
+                       weak_factory_.GetWeakPtr(), std::move(device),
+                       step + 1));
+    return;
+  } else if (step == kNumStrings) {
+    device_ptr->ControlTransferOut(
+        ControlTransferParams(kSendString, step),
+        VectorFromString(kCableOverAOAVersion), kTimeoutMilliseconds,
+        base::BindOnce(&AndroidAccessoryDiscovery::OnConfigurationStepComplete,
+                       weak_factory_.GetWeakPtr(), std::move(device),
+                       step + 1));
+    return;
+  } else if (step == kNumStrings + 1) {
+    device_ptr->ControlTransferOut(
+        ControlTransferParams(kStart), {}, kTimeoutMilliseconds,
+        base::BindOnce(&AndroidAccessoryDiscovery::OnConfigurationStepComplete,
+                       weak_factory_.GetWeakPtr(), std::move(device),
+                       step + 1));
+    return;
+  }
+
+  FIDO_LOG(DEBUG) << "Device requested to switch to accessory mode";
+}
+
+void AndroidAccessoryDiscovery::OnDeviceRemoved(
+    device::mojom::UsbDeviceInfoPtr device_info) {}
+
+void AndroidAccessoryDiscovery::OnGetDevices(
+    std::vector<device::mojom::UsbDeviceInfoPtr> devices) {
+  base::flat_set<std::string>& known_guids(KnownAccessories());
+  base::flat_set<std::string> still_known_guids;
+
+  for (auto& device_info : devices) {
+    const std::string& guid = device_info->guid;
+    if (!base::Contains(known_guids, guid)) {
+      continue;
+    }
+
+    still_known_guids.insert(guid);
+    FIDO_LOG(DEBUG) << "Previously opened accessory device found.";
+
+    mojo::Remote<device::mojom::UsbDevice> device;
+    device_manager_->GetDevice(guid, device.BindNewPipeAndPassReceiver(),
+                               mojo::NullRemote() /* device_client */);
+
+    HandleAccessoryDevice(std::move(device), std::move(device_info));
+  }
+
+  // The global |known_guids| is updated to remove any GUIDs that have
+  // disappeared so that it doesn't grow over time.
+  known_guids.swap(still_known_guids);
+
+  // Other devices attached at the time that the discovery is started are
+  // ignored because we don't want to send USB vendor commands to random
+  // devices.
+  NotifyDiscoveryStarted(true);
+}
+
+}  // namespace device
diff --git a/device/fido/aoa/android_accessory_discovery.h b/device/fido/aoa/android_accessory_discovery.h
new file mode 100644
index 0000000..c22cc588
--- /dev/null
+++ b/device/fido/aoa/android_accessory_discovery.h
@@ -0,0 +1,113 @@
+// 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 DEVICE_FIDO_AOA_ANDROID_ACCESSORY_DISCOVERY_H_
+#define DEVICE_FIDO_AOA_ANDROID_ACCESSORY_DISCOVERY_H_
+
+#include <array>
+#include <memory>
+#include <tuple>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "device/fido/fido_device_discovery.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/device/public/mojom/usb_device.mojom.h"
+#include "services/device/public/mojom/usb_manager.mojom.h"
+#include "services/device/public/mojom/usb_manager_client.mojom.h"
+
+namespace device {
+
+// AndroidAccessoryDiscovery watches for USB devices that are inserted during
+// its lifetime and tries sending AOA[1] commands to them in case they are a
+// phone that can speak CTAP over the accessory protocol.
+//
+// [1] https://source.android.com/devices/accessories/aoa
+class COMPONENT_EXPORT(DEVICE_FIDO) AndroidAccessoryDiscovery
+    : public FidoDeviceDiscovery,
+      device::mojom::UsbDeviceManagerClient {
+ public:
+  // InterfaceInfo contains the results of evaluating the USB metadata from an
+  // accessory device.
+  struct InterfaceInfo {
+    // configuration is the USB configuration number that contains the AOA
+    // interface.
+    uint8_t configuration;
+    // interface is the interface number of the AOA interface.
+    uint8_t interface;
+    // in_endpoint and out_endpoint are the endpoint numbers for AOA.
+    uint8_t in_endpoint;
+    uint8_t out_endpoint;
+    // guid is the identifier assigned by Chromium's USB layer to this specific
+    // USB connection.
+    std::string guid;
+  };
+
+  explicit AndroidAccessoryDiscovery(
+      mojo::Remote<device::mojom::UsbDeviceManager>);
+  ~AndroidAccessoryDiscovery() override;
+
+ private:
+  static constexpr size_t kSyncNonceLength = 16;
+  static constexpr size_t kSyncMessageLength =
+      sizeof(uint8_t) + AndroidAccessoryDiscovery::kSyncNonceLength;
+
+  // FidoDeviceDiscovery:
+  void StartInternal() override;
+
+  // device::mojom::UsbDeviceManagerClient:
+  void OnDeviceAdded(device::mojom::UsbDeviceInfoPtr device_info) override;
+  void OnDeviceRemoved(device::mojom::UsbDeviceInfoPtr device_info) override;
+
+  void OnGetDevices(std::vector<device::mojom::UsbDeviceInfoPtr> devices);
+
+  void OnOpen(mojo::Remote<device::mojom::UsbDevice> device,
+              device::mojom::UsbOpenDeviceError error);
+  void OnVersionReply(mojo::Remote<device::mojom::UsbDevice> device,
+                      device::mojom::UsbTransferStatus status,
+                      const std::vector<uint8_t>& payload);
+  void OnConfigurationStepComplete(
+      mojo::Remote<device::mojom::UsbDevice> device,
+      unsigned step,
+      device::mojom::UsbTransferStatus status);
+
+  void HandleAccessoryDevice(mojo::Remote<device::mojom::UsbDevice> device,
+                             device::mojom::UsbDeviceInfoPtr device_info);
+  void OnAccessoryConfigured(mojo::Remote<device::mojom::UsbDevice> device,
+                             InterfaceInfo interface_info,
+                             bool success);
+  void OnOpenAccessory(mojo::Remote<device::mojom::UsbDevice> device,
+                       device::mojom::UsbDeviceInfoPtr device_info,
+                       InterfaceInfo interface_info,
+                       device::mojom::UsbOpenDeviceError error);
+  void OnSyncWritten(mojo::Remote<device::mojom::UsbDevice> device,
+                     InterfaceInfo interface_info,
+                     std::array<uint8_t, kSyncNonceLength> nonce,
+                     mojom::UsbTransferStatus result);
+  void OnReadComplete(mojo::Remote<device::mojom::UsbDevice> device,
+                      InterfaceInfo interface_info,
+                      std::array<uint8_t, kSyncNonceLength> nonce,
+                      mojom::UsbTransferStatus result,
+                      const std::vector<uint8_t>& payload);
+  void OnAccessoryInterfaceClaimed(
+      mojo::Remote<device::mojom::UsbDevice> device,
+      InterfaceInfo interface_info,
+      bool success);
+
+  mojo::Remote<device::mojom::UsbDeviceManager> device_manager_;
+  mojo::AssociatedReceiver<device::mojom::UsbDeviceManagerClient> receiver_{
+      this};
+  base::WeakPtrFactory<AndroidAccessoryDiscovery> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(AndroidAccessoryDiscovery);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_FIDO_AOA_ANDROID_ACCESSORY_DISCOVERY_H_
diff --git a/device/fido/fake_fido_discovery.cc b/device/fido/fake_fido_discovery.cc
index f27314e4..c49be71 100644
--- a/device/fido/fake_fido_discovery.cc
+++ b/device/fido/fake_fido_discovery.cc
@@ -88,6 +88,7 @@
     case FidoTransportProtocol::kNearFieldCommunication:
       return std::move(next_nfc_discovery_);
     case FidoTransportProtocol::kBluetoothLowEnergy:
+    case FidoTransportProtocol::kAndroidAccessory:
       return nullptr;
     case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
       return std::move(next_cable_discovery_);
diff --git a/device/fido/fido_constants.h b/device/fido/fido_constants.h
index 2763205..86dc634 100644
--- a/device/fido/fido_constants.h
+++ b/device/fido/fido_constants.h
@@ -356,6 +356,12 @@
 constexpr uint8_t kP1IndividualAttestation = 0x80;
 constexpr size_t kMaxKeyHandleLength = 255;
 
+// kCableOverAOAVersion is a magic value that is sent as the "version" in an
+// Android AOA[1] configuration to identity a security-key request.
+//
+// [1] https://source.android.com/devices/accessories/aoa
+constexpr char kCableOverAOAVersion[] = "12eba9f901039b36";
+
 // Maximum wait time before client error outs on device.
 COMPONENT_EXPORT(DEVICE_FIDO) extern const base::TimeDelta kDeviceTimeout;
 
diff --git a/device/fido/fido_discovery_factory.cc b/device/fido/fido_discovery_factory.cc
index 1bf6452..3491f67a 100644
--- a/device/fido/fido_discovery_factory.cc
+++ b/device/fido/fido_discovery_factory.cc
@@ -6,6 +6,7 @@
 
 #include "base/notreached.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/fido/aoa/android_accessory_discovery.h"
 #include "device/fido/cable/fido_cable_discovery.h"
 #include "device/fido/features.h"
 #include "device/fido/fido_discovery_base.h"
@@ -71,6 +72,12 @@
 #else
       return nullptr;
 #endif
+    case FidoTransportProtocol::kAndroidAccessory:
+      if (usb_device_manager_) {
+        return std::make_unique<AndroidAccessoryDiscovery>(
+            std::move(usb_device_manager_.value()));
+      }
+      return nullptr;
   }
   NOTREACHED() << "Unhandled transport type";
   return nullptr;
@@ -83,6 +90,11 @@
   qr_generator_key_ = std::move(qr_generator_key);
 }
 
+void FidoDiscoveryFactory::set_usb_device_manager(
+    mojo::Remote<device::mojom::UsbDeviceManager> usb_device_manager) {
+  usb_device_manager_.emplace(std::move(usb_device_manager));
+}
+
 void FidoDiscoveryFactory::set_cable_pairing_callback(
     base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>
         pairing_callback) {
diff --git a/device/fido/fido_discovery_factory.h b/device/fido/fido_discovery_factory.h
index 9610098..862c189 100644
--- a/device/fido/fido_discovery_factory.h
+++ b/device/fido/fido_discovery_factory.h
@@ -16,6 +16,8 @@
 #include "device/fido/fido_discovery_base.h"
 #include "device/fido/fido_request_handler_base.h"
 #include "device/fido/fido_transport_protocol.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/device/public/mojom/usb_manager.mojom.h"
 
 #if defined(OS_MAC)
 #include "device/fido/mac/authenticator_config.h"
@@ -44,6 +46,8 @@
   void set_cable_data(std::vector<CableDiscoveryData> cable_data,
                       base::Optional<QRGeneratorKey> qr_generator_key);
 
+  void set_usb_device_manager(mojo::Remote<device::mojom::UsbDeviceManager>);
+
   // set_cable_pairing_callback installs a repeating callback that will be
   // called when a QR handshake results in a phone wishing to pair with this
   // browser.
@@ -78,6 +82,8 @@
 #if defined(OS_MAC)
   base::Optional<fido::mac::AuthenticatorConfig> mac_touch_id_config_;
 #endif  // defined(OS_MAC)
+  base::Optional<mojo::Remote<device::mojom::UsbDeviceManager>>
+      usb_device_manager_;
   base::Optional<std::vector<CableDiscoveryData>> cable_data_;
   base::Optional<QRGeneratorKey> qr_generator_key_;
   base::Optional<
diff --git a/device/fido/fido_transport_protocol.cc b/device/fido/fido_transport_protocol.cc
index 19934f3..0c95160 100644
--- a/device/fido/fido_transport_protocol.cc
+++ b/device/fido/fido_transport_protocol.cc
@@ -14,14 +14,6 @@
 const char kCloudAssistedBluetoothLowEnergy[] = "cable";
 const char kInternal[] = "internal";
 
-base::flat_set<FidoTransportProtocol> GetAllTransportProtocols() {
-  return {FidoTransportProtocol::kUsbHumanInterfaceDevice,
-          FidoTransportProtocol::kBluetoothLowEnergy,
-          FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy,
-          FidoTransportProtocol::kNearFieldCommunication,
-          FidoTransportProtocol::kInternal};
-}
-
 base::Optional<FidoTransportProtocol> ConvertToFidoTransportProtocol(
     base::StringPiece protocol) {
   if (protocol == kUsbHumanInterfaceDevice)
@@ -51,6 +43,10 @@
       return kCloudAssistedBluetoothLowEnergy;
     case FidoTransportProtocol::kInternal:
       return kInternal;
+    case FidoTransportProtocol::kAndroidAccessory:
+      // The Android accessory transport is not exposed to the outside world and
+      // is considered a flavour of caBLE.
+      return kCloudAssistedBluetoothLowEnergy;
   }
   NOTREACHED();
   return "";
diff --git a/device/fido/fido_transport_protocol.h b/device/fido/fido_transport_protocol.h
index 634a53a0..afcaf9e 100644
--- a/device/fido/fido_transport_protocol.h
+++ b/device/fido/fido_transport_protocol.h
@@ -25,7 +25,8 @@
   kBluetoothLowEnergy = 2,
   kCloudAssistedBluetoothLowEnergy = 3,
   kInternal = 4,
-  kMaxValue = kInternal,
+  kAndroidAccessory = 5,
+  kMaxValue = kAndroidAccessory,
 };
 
 // String representation of above FidoTransportProtocol enum.
@@ -36,9 +37,6 @@
 extern const char kInternal[];
 
 COMPONENT_EXPORT(DEVICE_FIDO)
-base::flat_set<FidoTransportProtocol> GetAllTransportProtocols();
-
-COMPONENT_EXPORT(DEVICE_FIDO)
 base::Optional<FidoTransportProtocol> ConvertToFidoTransportProtocol(
     base::StringPiece protocol);
 
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc
index ad66381..2fffce7 100644
--- a/device/fido/get_assertion_request_handler.cc
+++ b/device/fido/get_assertion_request_handler.cc
@@ -17,6 +17,7 @@
 #include "components/cbor/diagnostic_writer.h"
 #include "components/device_event_log/device_event_log.h"
 #include "device/fido/cable/fido_cable_discovery.h"
+#include "device/fido/features.h"
 #include "device/fido/fido_authenticator.h"
 #include "device/fido/fido_discovery_factory.h"
 #include "device/fido/fido_parsing_utils.h"
@@ -189,7 +190,9 @@
       FidoTransportProtocol::kNearFieldCommunication,
       FidoTransportProtocol::kUsbHumanInterfaceDevice,
       FidoTransportProtocol::kBluetoothLowEnergy,
-      FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy};
+      FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy,
+      FidoTransportProtocol::kAndroidAccessory,
+  };
 
   const auto& allowed_list = request.allow_list;
   if (allowed_list.empty()) {
@@ -198,12 +201,17 @@
 
   base::flat_set<FidoTransportProtocol> transports;
   for (const auto& credential : allowed_list) {
-    if (credential.transports().empty())
+    if (credential.transports().empty()) {
       return kAllTransports;
+    }
     transports.insert(credential.transports().begin(),
                       credential.transports().end());
   }
 
+  if (base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)) {
+    transports.insert(device::FidoTransportProtocol::kAndroidAccessory);
+  }
+
   return transports;
 }
 
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc
index 4d6d75e..3801a68 100644
--- a/device/fido/make_credential_handler_unittest.cc
+++ b/device/fido/make_credential_handler_unittest.cc
@@ -143,8 +143,12 @@
   scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_;
   std::unique_ptr<MockFidoDevice> pending_mock_platform_device_;
   TestMakeCredentialRequestCallback cb_;
-  base::flat_set<FidoTransportProtocol> supported_transports_ =
-      GetAllTransportProtocols();
+  base::flat_set<FidoTransportProtocol> supported_transports_ = {
+      FidoTransportProtocol::kUsbHumanInterfaceDevice,
+      FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy,
+      FidoTransportProtocol::kNearFieldCommunication,
+      FidoTransportProtocol::kInternal,
+  };
 };
 
 TEST_F(FidoMakeCredentialHandlerTest, TransportAvailabilityInfo) {
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc
index ced52a8e..30c96104 100644
--- a/device/fido/make_credential_request_handler.cc
+++ b/device/fido/make_credential_request_handler.cc
@@ -167,16 +167,22 @@
     case AuthenticatorAttachment::kPlatform:
       return {FidoTransportProtocol::kInternal};
     case AuthenticatorAttachment::kCrossPlatform:
-      return {FidoTransportProtocol::kUsbHumanInterfaceDevice,
-              FidoTransportProtocol::kBluetoothLowEnergy,
-              FidoTransportProtocol::kNearFieldCommunication,
-              FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy};
+      return {
+          FidoTransportProtocol::kUsbHumanInterfaceDevice,
+          FidoTransportProtocol::kBluetoothLowEnergy,
+          FidoTransportProtocol::kNearFieldCommunication,
+          FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy,
+          FidoTransportProtocol::kAndroidAccessory,
+      };
     case AuthenticatorAttachment::kAny:
-      return {FidoTransportProtocol::kInternal,
-              FidoTransportProtocol::kNearFieldCommunication,
-              FidoTransportProtocol::kUsbHumanInterfaceDevice,
-              FidoTransportProtocol::kBluetoothLowEnergy,
-              FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy};
+      return {
+          FidoTransportProtocol::kInternal,
+          FidoTransportProtocol::kNearFieldCommunication,
+          FidoTransportProtocol::kUsbHumanInterfaceDevice,
+          FidoTransportProtocol::kBluetoothLowEnergy,
+          FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy,
+          FidoTransportProtocol::kAndroidAccessory,
+      };
   }
 
   NOTREACHED();
diff --git a/device/fido/virtual_fido_device.cc b/device/fido/virtual_fido_device.cc
index f01e9dc..418e1f5 100644
--- a/device/fido/virtual_fido_device.cc
+++ b/device/fido/virtual_fido_device.cc
@@ -470,6 +470,9 @@
     case FidoTransportProtocol::kInternal:
       transport_bit = 4;
       break;
+    case FidoTransportProtocol::kAndroidAccessory:
+      transport_bit = 1;
+      break;
   }
   const uint8_t kTransportTypesContents[] = {
       3,                            // BIT STRING
diff --git a/device/fido/win/type_conversions.cc b/device/fido/win/type_conversions.cc
index ce01a31..270bdbb 100644
--- a/device/fido/win/type_conversions.cc
+++ b/device/fido/win/type_conversions.cc
@@ -151,6 +151,7 @@
         result |= WEBAUTHN_CTAP_TRANSPORT_BLE;
         break;
       case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
+      case FidoTransportProtocol::kAndroidAccessory:
         // caBLE is unsupported by the Windows API.
         break;
       case FidoTransportProtocol::kInternal:
diff --git a/docs/network_traffic_annotations.md b/docs/network_traffic_annotations.md
index 385f4b7..d7bc89b 100644
--- a/docs/network_traffic_annotations.md
+++ b/docs/network_traffic_annotations.md
@@ -289,7 +289,7 @@
   `tools/traffic_annotation/summary/grouping.xml`. When adding a new annotation,
   it must also be included in `grouping.xml` for reporting purposes (please
   refer to the **Annotations Review**).
-  
+
 
 ### Presubmit tests
 To perform tests prior to submit, one can use the `traffic_annotation_auditor`
@@ -324,7 +324,7 @@
 as specified in presubmit tests. But if it is not possible to do so (e.g., if
 you are changing the code from an unsupported platform or you don’t have a
 compiled build directory), the code can be submitted to the trybot and the test
-on trybot will tell you the required modifications. 
+on trybot will tell you the required modifications.
 
 In order to help make external reports easier, annotation unique ids should be
 mentioned in `tools/traffic_annotation/summary/grouping.xml`. Once a new
diff --git a/extensions/browser/api/clipboard/clipboard_api.cc b/extensions/browser/api/clipboard/clipboard_api.cc
index fa21d056..633d2495 100644
--- a/extensions/browser/api/clipboard/clipboard_api.cc
+++ b/extensions/browser/api/clipboard/clipboard_api.cc
@@ -67,8 +67,10 @@
   ExtensionsAPIClient::Get()->SaveImageDataToClipboard(
       std::vector<char>(params->image_data.begin(), params->image_data.end()),
       params->type, std::move(*params->additional_items),
-      base::Bind(&ClipboardSetImageDataFunction::OnSaveImageDataSuccess, this),
-      base::Bind(&ClipboardSetImageDataFunction::OnSaveImageDataError, this));
+      base::BindOnce(&ClipboardSetImageDataFunction::OnSaveImageDataSuccess,
+                     this),
+      base::BindOnce(&ClipboardSetImageDataFunction::OnSaveImageDataError,
+                     this));
   return RespondLater();
 }
 
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index 18e27f0..091262a 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -166,8 +166,8 @@
     const std::vector<char>& image_data,
     api::clipboard::ImageType type,
     AdditionalDataItemList additional_items,
-    const base::Closure& success_callback,
-    const base::Callback<void(const std::string&)>& error_callback) {}
+    base::OnceClosure success_callback,
+    base::OnceCallback<void(const std::string&)> error_callback) {}
 #endif
 
 AutomationInternalApiDelegate*
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index 67b8c3f..24f646b 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -208,8 +208,8 @@
       const std::vector<char>& image_data,
       api::clipboard::ImageType type,
       AdditionalDataItemList additional_items,
-      const base::Closure& success_callback,
-      const base::Callback<void(const std::string&)>& error_callback);
+      base::OnceClosure success_callback,
+      base::OnceCallback<void(const std::string&)> error_callback);
 #endif
 
   virtual AutomationInternalApiDelegate* GetAutomationInternalApiDelegate();
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index d8b946f07..98c9961 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -211,7 +211,9 @@
       }
       builders {
         name: "chromium/try/android-marshmallow-x86-rel"
-        includable_only: true
+        experiment_percentage: 2
+        location_regexp: ".*"
+        location_regexp_exclude: "infra/config/.+"
       }
       builders {
         name: "chromium/try/android-nougat-arm64-rel"
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index 804b3a8f..fb0c60ae 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -343,6 +343,9 @@
 by CQ. These are often used to test new configurations before they are added
 as required builders.
 
+* [android-marshmallow-x86-rel](https://ci.chromium.org/p/chromium/builders/try/android-marshmallow-x86-rel) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+android-marshmallow-x86-rel)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+android-marshmallow-x86-rel))
+  * Experiment percentage: 2
+
 * [fuchsia-compile-x64-dbg](https://ci.chromium.org/p/chromium/builders/try/fuchsia-compile-x64-dbg) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+fuchsia-compile-x64-dbg)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+fuchsia-compile-x64-dbg))
   * Experiment percentage: 50
 
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index 2183700..8eca8c5d 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -124,6 +124,9 @@
 try_.chromium_android_builder(
     name = "android-marshmallow-x86-rel",
     goma_jobs = goma.jobs.J150,
+    tryjob = try_.job(
+        experiment_percentage = 2,
+    ),
 )
 
 try_.chromium_android_builder(
diff --git a/ios/build/chrome_build.gni b/ios/build/chrome_build.gni
index 25727fd..2ebd9fc 100644
--- a/ios/build/chrome_build.gni
+++ b/ios/build/chrome_build.gni
@@ -70,6 +70,7 @@
 
 chromium_bundle_id = "chrome.ios.herebedragons"
 chromium_handoff_id = "$ios_app_bundle_id_prefix.chrome.handoff"
+ios_move_tab_activity_type = "$ios_app_bundle_id_prefix.chrome.move-tab"
 
 if (is_chrome_branded) {
   chromium_short_name = "Chrome"
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index 7938cc1..32264537 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -377,6 +377,7 @@
     "CHROMIUM_URL_SCHEME_3=$url_x_callback_scheme",
     "CHROMIUM_URL_CHANNEL_SCHEME=$url_channel_scheme",
     "SSOAUTH_URL_SCHEME=$url_ssoauth_scheme",
+    "IOS_MOVE_TAB_ACTIVITY_TYPE=$ios_move_tab_activity_type",
   ]
 
   if (ios_encryption_export_compliance_code != "") {
diff --git a/ios/chrome/app/resources/Info.plist b/ios/chrome/app/resources/Info.plist
index 79426e0..bfce47f 100644
--- a/ios/chrome/app/resources/Info.plist
+++ b/ios/chrome/app/resources/Info.plist
@@ -96,6 +96,7 @@
 		<string>OpenInChromeIntent</string>
 		<string>SearchInChromeIntent</string>
         <string>OpenInChromeIncognitoIntent</string>
+		<string>${IOS_MOVE_TAB_ACTIVITY_TYPE}</string>
 	</array>
 	<key>UIBackgroundModes</key>
 	<array>
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
index 389f779..f98793a 100644
--- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
+++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
@@ -444,8 +444,8 @@
     web_state_.SetBrowserState(enterprise_policy_helper_->GetBrowserState());
 
     policy::PolicyMap policy_map;
-    auto value = std::make_unique<base::Value>(base::Value::Type::LIST);
-    value->Append("itms-apps://*");
+    base::Value value(base::Value::Type::LIST);
+    value.Append("itms-apps://*");
     policy_map.Set(policy::key::kURLBlocklist, policy::POLICY_LEVEL_MANDATORY,
                    policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
                    std::move(value), nullptr);
diff --git a/ios/chrome/browser/policy/policy_app_interface.mm b/ios/chrome/browser/policy/policy_app_interface.mm
index 0c6b100d..f809a72 100644
--- a/ios/chrome/browser/policy/policy_app_interface.mm
+++ b/ios/chrome/browser/policy/policy_app_interface.mm
@@ -4,7 +4,10 @@
 
 #import "ios/chrome/browser/policy/policy_app_interface.h"
 
+#include <memory>
+
 #include "base/json/json_string_value_serializer.h"
+#include "base/optional.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
@@ -44,15 +47,18 @@
 // Takes a JSON-encoded string representing a |base::Value|, and deserializes
 // into a |base::Value| pointer. If nullptr is given, returns a pointer to a
 // |base::Value| of type NONE.
-std::unique_ptr<base::Value> DeserializeValue(NSString* json_value) {
+base::Optional<base::Value> DeserializeValue(NSString* json_value) {
   if (!json_value) {
-    return std::make_unique<base::Value>(base::Value::Type::NONE);
+    return base::Value(base::Value::Type::NONE);
   }
 
   std::string json = base::SysNSStringToUTF8(json_value);
   JSONStringValueDeserializer deserializer(json);
-  return deserializer.Deserialize(/*error_code=*/nullptr,
-                                  /*error_message=*/nullptr);
+  std::unique_ptr<base::Value> value =
+      deserializer.Deserialize(/*error_code=*/nullptr,
+                               /*error_message=*/nullptr);
+  return value ? base::make_optional<base::Value>(std::move(*value))
+               : base::nullopt;
 }
 }
 
@@ -80,7 +86,7 @@
 }
 
 + (void)setPolicyValue:(NSString*)jsonValue forKey:(NSString*)policyKey {
-  std::unique_ptr<base::Value> value = DeserializeValue(jsonValue);
+  base::Optional<base::Value> value = DeserializeValue(jsonValue);
   policy::PolicyMap values;
   values.Set(base::SysNSStringToUTF8(policyKey), policy::POLICY_LEVEL_MANDATORY,
              policy::POLICY_SCOPE_MACHINE, policy::POLICY_SOURCE_PLATFORM,
diff --git a/ios/chrome/browser/translate/BUILD.gn b/ios/chrome/browser/translate/BUILD.gn
index e5e01cfa..003e6fb 100644
--- a/ios/chrome/browser/translate/BUILD.gn
+++ b/ios/chrome/browser/translate/BUILD.gn
@@ -124,6 +124,7 @@
     "//components/translate/core/common:common",
     "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser:chrome_url_constants",
+    "//ios/chrome/browser/ui/infobars:feature_flags",
     "//ios/chrome/browser/ui/popup_menu:constants",
     "//ios/chrome/browser/ui/translate:legacy_translate_constants",
     "//ios/chrome/browser/ui/translate:translate_ui_constants",
diff --git a/ios/chrome/browser/translate/translate_egtest.mm b/ios/chrome/browser/translate/translate_egtest.mm
index 4464517..04a4fa7 100644
--- a/ios/chrome/browser/translate/translate_egtest.mm
+++ b/ios/chrome/browser/translate/translate_egtest.mm
@@ -16,6 +16,7 @@
 #include "components/translate/core/common/translate_constants.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/translate/translate_app_interface.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
 #import "ios/chrome/browser/ui/translate/legacy_translate_infobar_constants.h"
 #import "ios/chrome/browser/ui/translate/translate_infobar_view_constants.h"
@@ -349,6 +350,9 @@
 
 // Tests that different language signals are detected correcty.
 - (void)testLanguageDetection {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   const GURL URL =
       web::test::HttpServer::MakeUrl("http://scenarioLanguageDetection");
   std::map<GURL, std::string> responses;
@@ -367,6 +371,9 @@
 
 // Tests that hidden text is not considered during detection.
 - (void)testLanguageDetectionIgnoreHiddenText {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   const GURL URL = web::test::HttpServer::MakeUrl(
       "http://scenarioLanguageDetectionIgnoreHiddenText");
   std::map<GURL, std::string> responses;
@@ -386,6 +393,9 @@
 // Tests that language detection is not performed when the page specifies that
 // it should not be translated.
 - (void)testLanguageDetectionNoTranslate {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -412,6 +422,9 @@
 
 // Tests that history.pushState triggers a new detection.
 - (void)testLanguageDetectionWithPushState {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   const GURL URL = web::test::HttpServer::MakeUrl(
       "http://scenarioLanguageDetectionPushState");
   std::map<GURL, std::string> responses;
@@ -445,6 +458,9 @@
 
 // Tests that language detection is performed on hash changes.
 - (void)testLanguageDetectionWithHashChange {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Generate a page with French text and a button that changes the text to
   // English and triggers a hash change.
   std::string html = base::StringPrintf(
@@ -480,6 +496,9 @@
 
 // Tests that language in http content is detected.
 - (void)testLanguageDetectionHttpContentLanguage {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -517,6 +536,9 @@
 
 // Tests that language in http content is detected when navigating to a link.
 - (void)testLanguageDetectionHttpContentLanguageBehindLink {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -536,6 +558,9 @@
 // Tests that language detection still happens when a very large quantity of
 // text is present on the page.
 - (void)testLanguageDetectionLargePage {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Generate very large page.
   std::string html = "<html lang='fr'><body>";
   NSUInteger targetSize = 1024 * 1024;  // More than 1 MB of page content.
@@ -560,6 +585,9 @@
 
 // Tests that language detection is not performed when translate is disabled.
 - (void)testLanguageDetectionDisabled {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   const GURL URL = web::test::HttpServer::MakeUrl(
       "http://scenarioLanguageDetectionDisabled");
   std::map<GURL, std::string> responses;
@@ -587,6 +615,9 @@
 // Tests that the infobar hides/shows as the browser enters/exits the fullscreen
 // mode as well as it can be dimissed.
 - (void)testInfobarShowHideDismiss {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -629,6 +660,9 @@
 
 // Tests that the infobar's popup menu can be dimissed.
 - (void)testInfobarDismissPopupMenu {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -662,6 +696,9 @@
 // Tests that the page can be translated and that translation can be reverted
 // using the source and the target language tabs.
 - (void)testInfobarTranslateRevert {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -677,6 +714,9 @@
 // Tests that the page can be translated and that translation can be reverted
 // using the source and the target language tabs in incognito mode.
 - (void)testInfobarTranslateRevertIncognito {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -699,6 +739,9 @@
 
 // Translates the page and reverts the translation using the language tabs.
 - (void)translateThenRevert {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   [self assertTranslateInfobarIsVisible];
 
   // Make sure the page is not translated.
@@ -735,6 +778,9 @@
 // Tests that translation occurs automatically on second navigation to an
 // already translated page.
 - (void)testInfobarAutoTranslate {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -773,6 +819,9 @@
 
 // Tests that the source and the target languages can be changed.
 - (void)testInfobarChangeLanguages {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -869,6 +918,9 @@
 // Tests that the "Always Translate" options can be toggled and the prefs are
 // updated accordingly.
 - (void)testInfobarAlwaysTranslate {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -978,6 +1030,9 @@
 // Tests that "Always Translate" is automatically triggered after a minimum
 // number of translate attempts by the user.
 - (void)testInfobarAutoAlwaysTranslate {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -1028,6 +1083,9 @@
 // Tests that "Always Translate" is automatically triggered only for a maximum
 // number of times if refused by the user.
 - (void)testInfobarAutoAlwaysTranslateMaxTries {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -1084,6 +1142,9 @@
 // Tests that the "Never Translate ..." options dismisses the infobar and
 // updates the prefs accordingly.
 - (void)testInfobarNeverTranslate {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -1157,6 +1218,9 @@
 // Tests that "Never Translate ..." is automatically triggered after a minimum
 // number of translate infobar dismissals by the user.
 - (void)testInfobarAutoNeverTranslate {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -1210,6 +1274,9 @@
 // maximum number of times if refused by the user.
 // TODO(crbug.com/945118): Re-enable when fixed.
 - (void)DISABLED_testInfobarAutoNeverTranslateMaxTries {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -1274,6 +1341,9 @@
 // Tests that the "Never Translate this site" option dismisses the infobar and
 // updates the prefs accordingly.
 - (void)testInfobarNeverTranslateSite {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -1349,6 +1419,9 @@
 // the page when tapped. If the page is already translated the infobar should
 // appear in "after translate" state.
 - (void)testTranslateManualTrigger {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -1430,6 +1503,9 @@
 // Translate infobar even if user has previously selected not to translate the
 // the source language.
 - (void)testTranslateManualTriggerNeverTranslate {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -1481,6 +1557,9 @@
 // Translate infobar even if user has previously selected not to translate the
 // the site.
 - (void)testTranslateManualTriggerNeverTranslateSite {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
@@ -1530,6 +1609,9 @@
 // Tests that the "Translate..." button in the tools menu is disabled if
 // translate is not available.
 - (void)testTranslateManualTriggerNotEnabled {
+  if (IsInfobarUIRebootEnabled()) {
+    EARL_GREY_TEST_DISABLED(@"Legacy Test.");
+  }
   // Start the HTTP server.
   std::unique_ptr<web::DataResponseProvider> provider(new TestResponseProvider);
   web::test::SetUpHttpServer(std::move(provider));
diff --git a/ios/chrome/browser/ui/autofill/BUILD.gn b/ios/chrome/browser/ui/autofill/BUILD.gn
index 5397733a..4cc2f40 100644
--- a/ios/chrome/browser/ui/autofill/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/BUILD.gn
@@ -169,7 +169,9 @@
     "//base/test:test_support",
     "//components/autofill/ios/browser:autofill_test_bundle_data",
     "//components/strings:components_strings_grit",
+    "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser/metrics:eg_test_support+eg2",
+    "//ios/chrome/browser/ui/infobars/banners:public",
     "//ios/chrome/test:eg_test_support+eg2",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/testing/earl_grey:eg_test_support+eg2",
@@ -178,6 +180,7 @@
     "//net:test_support",
     "//services/network/public/cpp",
     "//testing/gtest",
+    "//ui/base",
   ]
   frameworks = [ "UIKit.framework" ]
 }
diff --git a/ios/chrome/browser/ui/autofill/save_card_infobar_egtest.mm b/ios/chrome/browser/ui/autofill/save_card_infobar_egtest.mm
index 6175a56..1d3061b 100644
--- a/ios/chrome/browser/ui/autofill/save_card_infobar_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/save_card_infobar_egtest.mm
@@ -8,14 +8,18 @@
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/metrics/metrics_app_interface.h"
 #import "ios/chrome/browser/ui/autofill/autofill_app_interface.h"
+#import "ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.h"
+#include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/chrome/test/scoped_eg_synchronization_disabler.h"
+#import "ios/testing/earl_grey/app_launch_manager.h"
 #import "ios/testing/earl_grey/earl_grey_test.h"
 #import "ios/web/public/test/http_server/http_server.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util_mac.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -46,15 +50,44 @@
     @"{\"error\":{\"code\":\"FAILED_PRECONDITION\",\"user_error_message\":\"An"
      " unexpected error has occurred. Please try again later.\"}}";
 
-id<GREYMatcher> closeButtonMatcher() {
-  return chrome_test_util::ButtonWithAccessibilityLabelId(IDS_CLOSE);
-}
+NSString* const kSavedCardLabel =
+    @"Mastercard  ‪•⁠ ⁠•⁠ ⁠•⁠ ⁠•⁠ ⁠5454‬";
 
-id<GREYMatcher> saveButtonMatcher() {
+id<GREYMatcher> LocalSaveButtonMatcher() {
   return chrome_test_util::ButtonWithAccessibilityLabelId(
       IDS_AUTOFILL_SAVE_CARD_INFOBAR_ACCEPT);
 }
 
+id<GREYMatcher> UploadBannerSaveButtonMatcher() {
+  return chrome_test_util::ButtonWithAccessibilityLabelId(
+      IDS_IOS_AUTOFILL_SAVE_ELLIPSIS);
+}
+
+id<GREYMatcher> UploadModalSaveButtonMatcher() {
+  return chrome_test_util::ButtonWithAccessibilityLabelId(
+      IDS_IOS_AUTOFILL_SAVE_CARD);
+}
+
+id<GREYMatcher> LocalBannerMatcher() {
+  NSString* bannerLabel =
+      [NSString stringWithFormat:@"%@,%@",
+                                 l10n_util::GetNSString(
+                                     IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL),
+                                 kSavedCardLabel];
+  return grey_allOf(grey_accessibilityID(kInfobarBannerViewIdentifier),
+                    grey_accessibilityLabel(bannerLabel), nil);
+}
+
+id<GREYMatcher> UploadBannerMatcher() {
+  NSString* bannerLabel = [NSString
+      stringWithFormat:@"%@,%@",
+                       l10n_util::GetNSString(
+                           IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD),
+                       kSavedCardLabel];
+  return grey_allOf(grey_accessibilityID(kInfobarBannerViewIdentifier),
+                    grey_accessibilityLabel(bannerLabel), nil);
+}
+
 }  // namepsace
 
 @interface SaveCardInfobarEGTest : ChromeTestCase
@@ -155,9 +188,9 @@
                  @"Event was not triggered");
 
   // Wait until the save card infobar becomes visible.
-  GREYAssert([self waitForUIElementToAppearWithMatcher:
-                       chrome_test_util::AutofillSaveCardLocallyInfobar()],
+  GREYAssert([self waitForUIElementToAppearWithMatcher:LocalBannerMatcher()],
              @"Save card infobar failed to show.");
+
   [AutofillAppInterface resetEventWaiterForEvents:@[
     @(CreditCardSaveManagerObserverEvent::kOnStrikeChangeCompleteCalled)
   ]
@@ -192,8 +225,7 @@
                  @"Event was not triggered");
 
   // Wait until the save card infobar becomes visible.
-  GREYAssert([self waitForUIElementToAppearWithMatcher:
-                       chrome_test_util::AutofillSaveCardLocallyInfobar()],
+  GREYAssert([self waitForUIElementToAppearWithMatcher:LocalBannerMatcher()],
              @"Save card infobar failed to show.");
 
   [AutofillAppInterface resetEventWaiterForEvents:@[
@@ -230,9 +262,9 @@
                  @"Event was not triggered");
 
   // Make sure the save card infobar does not become visible.
-  GREYAssertFalse([self waitForUIElementToAppearWithMatcher:
-                            chrome_test_util::AutofillSaveCardLocallyInfobar()],
-                  @"Save card infobar should not show.");
+  GREYAssertFalse(
+      [self waitForUIElementToAppearWithMatcher:LocalBannerMatcher()],
+      @"Save card infobar should not show.");
 }
 
 // Ensures that submitting the form should query Google Payments; and the
@@ -257,9 +289,9 @@
                  @"Event was not triggered");
 
   // Wait until the save card infobar becomes visible.
-  GREYAssert([self waitForUIElementToAppearWithMatcher:
-                       chrome_test_util::AutofillUploadCardInfobar()],
+  GREYAssert([self waitForUIElementToAppearWithMatcher:UploadBannerMatcher()],
              @"Save card infobar failed to show.");
+
   [AutofillAppInterface resetEventWaiterForEvents:@[
     @(CreditCardSaveManagerObserverEvent::kOnStrikeChangeCompleteCalled)
   ]
@@ -292,8 +324,7 @@
                  @"Event was not triggered");
 
   // Wait until the save card infobar becomes visible.
-  GREYAssert([self waitForUIElementToAppearWithMatcher:
-                       chrome_test_util::AutofillUploadCardInfobar()],
+  GREYAssert([self waitForUIElementToAppearWithMatcher:UploadBannerMatcher()],
              @"Save card infobar failed to show.");
 
   [AutofillAppInterface resetEventWaiterForEvents:@[
@@ -327,23 +358,21 @@
                  @"Event was not triggered");
 
   // Wait until the save card infobar becomes visible.
-  GREYAssert([self waitForUIElementToAppearWithMatcher:
-                       chrome_test_util::AutofillUploadCardInfobar()],
+  GREYAssert([self waitForUIElementToAppearWithMatcher:UploadBannerMatcher()],
              @"Save card infobar failed to show.");
 
   [AutofillAppInterface resetEventWaiterForEvents:@[
     @(CreditCardSaveManagerObserverEvent::kOnStrikeChangeCompleteCalled)
   ]
                                           timeout:kWaitForDownloadTimeout];
-  // Tap the X button.
-  [[EarlGrey selectElementWithMatcher:closeButtonMatcher()]
-      performAction:grey_tap()];
-  GREYAssertTrue([AutofillAppInterface waitForEvents],
-                 @"Event was not triggered");
+  // Dismiss Infobar banner
+  [[EarlGrey selectElementWithMatcher:UploadBannerMatcher()]
+      performAction:grey_swipeFastInDirection(kGREYDirectionUp)];
+
   // Wait until the save card infobar disappears.
-  GREYAssert([self waitForUIElementToDisappearWithMatcher:
-                       chrome_test_util::AutofillUploadCardInfobar()],
-             @"Save card infobar failed to disappear.");
+  GREYAssert(
+      [self waitForUIElementToDisappearWithMatcher:UploadBannerMatcher()],
+      @"Save card infobar failed to disappear.");
 
   // Ensure that UMA was logged correctly.
   NSError* error = [MetricsAppInterface
@@ -383,17 +412,21 @@
                  @"Event was not triggered");
 
   // Wait until the save card infobar becomes visible.
-  GREYAssert([self waitForUIElementToAppearWithMatcher:
-                       chrome_test_util::AutofillUploadCardInfobar()],
+  GREYAssert([self waitForUIElementToAppearWithMatcher:UploadBannerMatcher()],
              @"Save card infobar failed to show.");
 
   [AutofillAppInterface resetEventWaiterForEvents:@[
     @(CreditCardSaveManagerObserverEvent::kOnSentUploadCardRequestCalled)
   ]
                                           timeout:kWaitForDownloadTimeout];
-  // Tap the save button.
-  [[EarlGrey selectElementWithMatcher:saveButtonMatcher()]
+  // Tap the banner save button.
+  [[EarlGrey selectElementWithMatcher:UploadBannerSaveButtonMatcher()]
       performAction:grey_tap()];
+
+  // Tap the modal save button.
+  [[EarlGrey selectElementWithMatcher:UploadModalSaveButtonMatcher()]
+      performAction:grey_tap()];
+
   if (![[AutofillAppInterface paymentsRiskData] length]) {
     // There is no provider for risk data so the request will not be sent.
     // Provide dummy risk data for this test.
@@ -403,9 +436,9 @@
                  @"Event was not triggered");
 
   // Wait until the save card infobar disappears.
-  GREYAssert([self waitForUIElementToDisappearWithMatcher:
-                       chrome_test_util::AutofillUploadCardInfobar()],
-             @"Save card infobar failed to disappear.");
+  GREYAssert(
+      [self waitForUIElementToDisappearWithMatcher:UploadBannerMatcher()],
+      @"Save card infobar failed to disappear.");
 
   // Ensure that UMA was logged correctly.
   NSError* error = [MetricsAppInterface
@@ -445,23 +478,20 @@
                  @"Event was not triggered");
 
   // Wait until the save card infobar becomes visible.
-  GREYAssert([self waitForUIElementToAppearWithMatcher:
-                       chrome_test_util::AutofillSaveCardLocallyInfobar()],
+  GREYAssert([self waitForUIElementToAppearWithMatcher:LocalBannerMatcher()],
              @"Save card infobar failed to show.");
 
   [AutofillAppInterface resetEventWaiterForEvents:@[
     @(CreditCardSaveManagerObserverEvent::kOnStrikeChangeCompleteCalled)
   ]
                                           timeout:kWaitForDownloadTimeout];
-  // Tap the X button.
-  [[EarlGrey selectElementWithMatcher:closeButtonMatcher()]
-      performAction:grey_tap()];
-  GREYAssertTrue([AutofillAppInterface waitForEvents],
-                 @"Event was not triggered");
+  // Dismiss infobar banner.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kInfobarBannerViewIdentifier)]
+      performAction:grey_swipeFastInDirection(kGREYDirectionUp)];
 
   // Wait until the save card infobar disappears.
-  GREYAssert([self waitForUIElementToDisappearWithMatcher:
-                       chrome_test_util::AutofillSaveCardLocallyInfobar()],
+  GREYAssert([self waitForUIElementToDisappearWithMatcher:LocalBannerMatcher()],
              @"Save card infobar failed to disappear.");
 
   // Ensure credit card is not saved locally.
@@ -497,17 +527,15 @@
                  @"Event was not triggered");
 
   // Wait until the save card infobar becomes visible.
-  GREYAssert([self waitForUIElementToAppearWithMatcher:
-                       chrome_test_util::AutofillSaveCardLocallyInfobar()],
+  GREYAssert([self waitForUIElementToAppearWithMatcher:LocalBannerMatcher()],
              @"Save card infobar failed to show.");
 
   // Tap the save button.
-  [[EarlGrey selectElementWithMatcher:saveButtonMatcher()]
+  [[EarlGrey selectElementWithMatcher:LocalSaveButtonMatcher()]
       performAction:grey_tap()];
 
   // Wait until the save card infobar disappears.
-  GREYAssert([self waitForUIElementToDisappearWithMatcher:
-                       chrome_test_util::AutofillSaveCardLocallyInfobar()],
+  GREYAssert([self waitForUIElementToDisappearWithMatcher:LocalBannerMatcher()],
              @"Save card infobar failed to disappear.");
 
   // Ensure credit card is saved locally.
@@ -544,9 +572,9 @@
                  @"Event was not triggered");
 
   // Make sure the save card infobar does not become visible.
-  GREYAssertFalse([self waitForUIElementToAppearWithMatcher:
-                            chrome_test_util::AutofillSaveCardLocallyInfobar()],
-                  @"Save card infobar should not show.");
+  GREYAssertFalse(
+      [self waitForUIElementToAppearWithMatcher:LocalBannerMatcher()],
+      @"Save card infobar should not show.");
 }
 
 @end
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn
index 8052be9..ea48e91 100644
--- a/ios/chrome/browser/ui/browser_view/BUILD.gn
+++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -213,6 +213,7 @@
     "//components/bookmarks/browser",
     "//components/bookmarks/test",
     "//components/omnibox/browser:test_support",
+    "//components/open_from_clipboard:test_support",
     "//components/prefs:test_support",
     "//components/search_engines",
     "//components/sessions",
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
index ee0a344..24c6aff3 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
@@ -11,6 +11,7 @@
 #include <memory>
 
 #include "base/files/scoped_temp_dir.h"
+#include "components/open_from_clipboard/fake_clipboard_recent_content.h"
 #include "components/search_engines/template_url_service.h"
 #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/favicon/favicon_service_factory.h"
@@ -159,6 +160,9 @@
             chrome_browser_state_.get());
     template_url_service->Load();
 
+    ClipboardRecentContent::SetInstance(
+        std::make_unique<FakeClipboardRecentContent>());
+
     container_ = [[BrowserContainerViewController alloc] init];
     bvc_ = [[BrowserViewController alloc] initWithBrowser:browser_.get()
                                         dependencyFactory:factory
diff --git a/ios/chrome/browser/ui/commands/snackbar_commands.h b/ios/chrome/browser/ui/commands/snackbar_commands.h
index 4bcbd87..8a52f2a 100644
--- a/ios/chrome/browser/ui/commands/snackbar_commands.h
+++ b/ios/chrome/browser/ui/commands/snackbar_commands.h
@@ -21,6 +21,17 @@
 - (void)showSnackbarMessage:(MDCSnackbarMessage*)message
                bottomOffset:(CGFloat)offset;
 
+// Shows a snackbar displaying a message with |messageText| and a button with
+// |buttonText| which triggers |messageAction| on tap. |completionAction| will
+// be called when the snackbar finishes presenting, BOOL is YES if the dismissal
+// was caused by a user action and NO if not. It will use the Bottom toolbar
+// height as bottom offset. Use this method if displaying a Snackbar while the
+// Web content is visible. If there's no bottom toolbar offset will be 0.
+- (void)showSnackbarWithMessage:(NSString*)messageText
+                     buttonText:(NSString*)buttonText
+                  messageAction:(void (^)(void))messageAction
+               completionAction:(void (^)(BOOL))completionAction;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_SNACKBAR_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/infobars/infobar_feature.mm b/ios/chrome/browser/ui/infobars/infobar_feature.mm
index 7454f81..808693b 100644
--- a/ios/chrome/browser/ui/infobars/infobar_feature.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_feature.mm
@@ -52,26 +52,7 @@
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 
 bool IsInfobarUIRebootEnabled() {
-  // Enable Messages to 100% in Dev, Canary and Beta.
-  switch (GetChannel()) {
-    case version_info::Channel::BETA:
-    case version_info::Channel::DEV:
-    case version_info::Channel::CANARY:
-      return YES;
-    case version_info::Channel::UNKNOWN:
-    case version_info::Channel::STABLE:
-      break;
-  }
-
-  if (base::FeatureList::IsEnabled(kInfobarUIRebootOnlyiOS13)) {
-    if (@available(iOS 13, *)) {
-      return base::FeatureList::IsEnabled(kIOSInfobarUIReboot);
-    } else {
-      return NO;
-    }
-  } else {
-    return base::FeatureList::IsEnabled(kIOSInfobarUIReboot);
-  }
+  return base::FeatureList::IsEnabled(kIOSInfobarUIReboot);
 }
 
 bool IsInfobarOverlayUIEnabled() {
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 30f799e..185ccaf 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -150,7 +150,7 @@
   // clean up.
   self.viewController.dispatcher =
       static_cast<id<ActivityServiceCommands, BrowserCommands,
-                     ApplicationCommands, LoadQueryCommands>>(
+                     ApplicationCommands, LoadQueryCommands, OmniboxCommands>>(
           self.browser->GetCommandDispatcher());
   self.viewController.voiceSearchEnabled = ios::GetChromeBrowserProvider()
                                                ->GetVoiceSearchProvider()
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h
index 8c54c86..32f36611 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.h
@@ -8,6 +8,7 @@
 #import <UIKit/UIKit.h>
 
 #import "ios/chrome/browser/ui/badges/badge_consumer.h"
+#import "ios/chrome/browser/ui/commands/omnibox_commands.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h"
 #import "ios/chrome/browser/ui/location_bar/location_bar_consumer.h"
 #import "ios/chrome/browser/ui/orchestrator/location_bar_animatee.h"
@@ -53,7 +54,8 @@
                               ApplicationCommands,
                               BrowserCommands,
                               InfobarCommands,
-                              LoadQueryCommands>
+                              LoadQueryCommands,
+                              OmniboxCommands>
     dispatcher;
 
 // Delegate for this location bar view controller.
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
index 2b7ea85..666d8455 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
@@ -71,6 +71,12 @@
 // icon (in iPad multitasking).
 @property(nonatomic, assign) BOOL shareButtonEnabled;
 
+// Stores whether the clipboard currently stores copied content.
+@property(nonatomic, assign) BOOL hasCopiedContent;
+// Stores the current content type in the clipboard. This is only valid if
+// |hasCopiedContent| is YES.
+@property(nonatomic, assign) ClipboardContentType copiedContentType;
+
 // Starts voice search, updating the NamedGuide to be constrained to the
 // trailing button.
 - (void)startVoiceSearch;
@@ -128,7 +134,8 @@
 - (void)setDispatcher:(id<ActivityServiceCommands,
                           BrowserCommands,
                           ApplicationCommands,
-                          LoadQueryCommands>)dispatcher {
+                          LoadQueryCommands,
+                          OmniboxCommands>)dispatcher {
   _dispatcher = dispatcher;
 }
 
@@ -197,6 +204,41 @@
   [self switchToEditing:NO];
 }
 
+- (void)viewWillAppear:(BOOL)animated {
+  [super viewWillAppear:animated];
+
+  [self updateCachedClipboardState];
+
+  [NSNotificationCenter.defaultCenter
+      addObserver:self
+         selector:@selector(pasteboardDidChange:)
+             name:UIPasteboardChangedNotification
+           object:nil];
+
+  // The pasteboard changed notification doesn't fire if the clipboard changes
+  // while the app is in the background, so update the state whenever the app
+  // becomes active.
+  [NSNotificationCenter.defaultCenter
+      addObserver:self
+         selector:@selector(applicationDidBecomeActive:)
+             name:UIApplicationDidBecomeActiveNotification
+           object:nil];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+  [super viewWillDisappear:animated];
+
+  [NSNotificationCenter.defaultCenter
+      removeObserver:self
+                name:UIPasteboardChangedNotification
+              object:nil];
+
+  [NSNotificationCenter.defaultCenter
+      removeObserver:self
+                name:UIApplicationDidBecomeActiveNotification
+              object:nil];
+}
+
 - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
   [self updateTrailingButtonState];
   [super traitCollectionDidChange:previousTraitCollection];
@@ -442,6 +484,40 @@
   RecordAction(UserMetricsAction("MobileToolbarShareMenu"));
 }
 
+- (void)pasteboardDidChange:(NSNotification*)notification {
+  [self updateCachedClipboardState];
+}
+
+- (void)applicationDidBecomeActive:(NSNotification*)notification {
+  [self updateCachedClipboardState];
+}
+
+- (void)updateCachedClipboardState {
+  self.hasCopiedContent = NO;
+  ClipboardRecentContent* clipboardRecentContent =
+      ClipboardRecentContent::GetInstance();
+  std::set<ClipboardContentType> desired_types;
+  desired_types.insert(ClipboardContentType::URL);
+  desired_types.insert(ClipboardContentType::Text);
+  desired_types.insert(ClipboardContentType::Image);
+  __weak __typeof(self) weakSelf = self;
+  clipboardRecentContent->HasRecentContentFromClipboard(
+      desired_types,
+      base::BindOnce(^(std::set<ClipboardContentType> matched_types) {
+        weakSelf.hasCopiedContent = !matched_types.empty();
+        if (weakSelf.searchByImageEnabled &&
+            matched_types.find(ClipboardContentType::Image) !=
+                matched_types.end()) {
+          weakSelf.copiedContentType = ClipboardContentType::Image;
+        } else if (matched_types.find(ClipboardContentType::URL) !=
+                   matched_types.end()) {
+          weakSelf.copiedContentType = ClipboardContentType::URL;
+        } else if (matched_types.find(ClipboardContentType::Text) !=
+                   matched_types.end()) {
+          weakSelf.copiedContentType = ClipboardContentType::Text;
+        }
+      }));
+}
 
 #pragma mark - UIMenu
 
@@ -462,8 +538,9 @@
 
     [menu setTargetRect:self.locationBarSteadyView.frame inView:self.view];
     [menu setMenuVisible:YES animated:YES];
-    // When we present the menu manually, it doesn't get focused by Voiceover.
-    // This notification forces voiceover to select the presented menu.
+    // When the menu is manually presented, it doesn't get focused by
+    // Voiceover. This notification forces voiceover to select the
+    // presented menu.
     UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification,
                                     menu);
   }
@@ -478,16 +555,16 @@
   if (action == @selector(searchCopiedImage:) ||
       action == @selector(visitCopiedLink:) ||
       action == @selector(searchCopiedText:)) {
-    ClipboardRecentContent* clipboardRecentContent =
-        ClipboardRecentContent::GetInstance();
-    if (self.searchByImageEnabled &&
-        clipboardRecentContent->HasRecentImageFromClipboard()) {
+    if (!self.hasCopiedContent) {
+      return NO;
+    }
+    if (self.copiedContentType == ClipboardContentType::Image) {
       return action == @selector(searchCopiedImage:);
     }
-    if (clipboardRecentContent->GetRecentURLFromClipboard().has_value()) {
+    if (self.copiedContentType == ClipboardContentType::URL) {
       return action == @selector(visitCopiedLink:);
     }
-    if (clipboardRecentContent->GetRecentTextFromClipboard().has_value()) {
+    if (self.copiedContentType == ClipboardContentType::Text) {
       return action == @selector(searchCopiedText:);
     }
     return NO;
@@ -502,39 +579,47 @@
 - (void)searchCopiedImage:(id)sender {
   RecordAction(
       UserMetricsAction("Mobile.OmniboxContextMenu.SearchCopiedImage"));
-  if (ClipboardRecentContent::GetInstance()->HasRecentImageFromClipboard()) {
-    ClipboardRecentContent::GetInstance()->GetRecentImageFromClipboard(
-        base::BindOnce(^(base::Optional<gfx::Image> optionalImage) {
-          UIImage* image = optionalImage.value().ToUIImage();
+  ClipboardRecentContent::GetInstance()->GetRecentImageFromClipboard(
+      base::BindOnce(^(base::Optional<gfx::Image> optionalImage) {
+        if (!optionalImage) {
+          return;
+        }
+        UIImage* image = optionalImage.value().ToUIImage();
+        dispatch_async(dispatch_get_main_queue(), ^{
           [self.dispatcher searchByImage:image];
-        }));
-  }
+          [self.dispatcher cancelOmniboxEdit];
+        });
+      }));
 }
 
 - (void)visitCopiedLink:(id)sender {
   RecordAction(UserMetricsAction("Mobile.OmniboxContextMenu.VisitCopiedLink"));
-  [self pasteAndGo:sender];
+  ClipboardRecentContent::GetInstance()->GetRecentURLFromClipboard(
+      base::BindOnce(^(base::Optional<GURL> optionalURL) {
+        NSString* url;
+        if (optionalURL) {
+          url = base::SysUTF8ToNSString(optionalURL.value().spec());
+        }
+        dispatch_async(dispatch_get_main_queue(), ^{
+          [self.dispatcher loadQuery:url immediately:YES];
+          [self.dispatcher cancelOmniboxEdit];
+        });
+      }));
 }
 
 - (void)searchCopiedText:(id)sender {
   RecordAction(UserMetricsAction("Mobile.OmniboxContextMenu.SearchCopiedText"));
-  [self pasteAndGo:sender];
-}
-
-// Both actions are performed the same, but need to be enabled differently,
-// so we need two different selectors.
-- (void)pasteAndGo:(id)sender {
-  NSString* query;
-  ClipboardRecentContent* clipboardRecentContent =
-      ClipboardRecentContent::GetInstance();
-  if (base::Optional<GURL> optionalUrl =
-          clipboardRecentContent->GetRecentURLFromClipboard()) {
-    query = base::SysUTF8ToNSString(optionalUrl.value().spec());
-  } else if (base::Optional<base::string16> optionalText =
-                 clipboardRecentContent->GetRecentTextFromClipboard()) {
-    query = base::SysUTF16ToNSString(optionalText.value());
-  }
-  [self.dispatcher loadQuery:query immediately:YES];
+  ClipboardRecentContent::GetInstance()->GetRecentTextFromClipboard(
+      base::BindOnce(^(base::Optional<base::string16> optionalText) {
+        NSString* query;
+        if (optionalText) {
+          query = base::SysUTF16ToNSString(optionalText.value());
+        }
+        dispatch_async(dispatch_get_main_queue(), ^{
+          [self.dispatcher loadQuery:query immediately:YES];
+          [self.dispatcher cancelOmniboxEdit];
+        });
+      }));
 }
 
 @end
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index b1da3ea..554ead6 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -34,10 +34,10 @@
 #include "ios/chrome/browser/crash_report/crash_keys_helper.h"
 #include "ios/chrome/browser/crash_report/crash_report_helper.h"
 #import "ios/chrome/browser/first_run/first_run.h"
-#include "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/main/browser_list.h"
 #import "ios/chrome/browser/main/browser_list_factory.h"
+#import "ios/chrome/browser/main/browser_util.h"
 #include "ios/chrome/browser/ntp/features.h"
 #import "ios/chrome/browser/ntp_snippets/content_suggestions_scheduler_notifications.h"
 #include "ios/chrome/browser/screenshot/screenshot_delegate.h"
@@ -375,6 +375,10 @@
           [self openOrReuseTabInMode:mode
                    withUrlLoadParams:params
                  tabOpenedCompletion:nil];
+        } else if (ActivityIsTabMove(activity)) {
+          NSString* tabID = GetTabIDFromActivity(activity);
+          MoveTabToBrowser(tabID, self.mainInterface.browser,
+                           /*destination_tab_index=*/0);
         } else if (!activityWithCompletion) {
           // Completion involves user interaction.
           // Only one can be triggered.
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
index 7e49facef..15bed54 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -78,6 +78,12 @@
 // Is YES while fixing display of edit menu (below omnibox).
 @property(nonatomic, assign) BOOL showingEditMenu;
 
+// Stores whether the clipboard currently stores copied content.
+@property(nonatomic, assign) BOOL hasCopiedContent;
+// Stores the current content type in the clipboard. This is only valid if
+// |hasCopiedContent| is YES.
+@property(nonatomic, assign) ClipboardContentType copiedContentType;
+
 @end
 
 @implementation OmniboxViewController
@@ -142,6 +148,27 @@
            object:nil];
 }
 
+- (void)viewWillAppear:(BOOL)animated {
+  [super viewWillAppear:animated];
+
+  [self updateCachedClipboardState];
+
+  [NSNotificationCenter.defaultCenter
+      addObserver:self
+         selector:@selector(pasteboardDidChange:)
+             name:UIPasteboardChangedNotification
+           object:nil];
+
+  // The pasteboard changed notification doesn't fire if the clipboard changes
+  // while the app is in the background, so update the state whenever the app
+  // becomes active.
+  [NSNotificationCenter.defaultCenter
+      addObserver:self
+         selector:@selector(applicationDidBecomeActive:)
+             name:UIApplicationDidBecomeActiveNotification
+           object:nil];
+}
+
 - (void)viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
 
@@ -153,6 +180,19 @@
   self.textField.selectedTextRange =
       [self.textField textRangeFromPosition:self.textField.beginningOfDocument
                                  toPosition:self.textField.beginningOfDocument];
+
+  [NSNotificationCenter.defaultCenter
+      removeObserver:self
+                name:UIPasteboardChangedNotification
+              object:nil];
+
+  // The pasteboard changed notification doesn't fire if the clipboard changes
+  // while the app is in the background, so update the state whenever the app
+  // becomes active.
+  [NSNotificationCenter.defaultCenter
+      removeObserver:self
+                name:UIApplicationDidBecomeActiveNotification
+              object:nil];
 }
 
 #pragma mark - properties
@@ -337,6 +377,33 @@
   [self.delegate omniboxViewControllerTextInputModeDidChange:self];
 }
 
+- (void)updateCachedClipboardState {
+  self.hasCopiedContent = NO;
+  ClipboardRecentContent* clipboardRecentContent =
+      ClipboardRecentContent::GetInstance();
+  std::set<ClipboardContentType> desired_types;
+  desired_types.insert(ClipboardContentType::URL);
+  desired_types.insert(ClipboardContentType::Text);
+  desired_types.insert(ClipboardContentType::Image);
+  __weak __typeof(self) weakSelf = self;
+  clipboardRecentContent->HasRecentContentFromClipboard(
+      desired_types,
+      base::BindOnce(^(std::set<ClipboardContentType> matched_types) {
+        weakSelf.hasCopiedContent = !matched_types.empty();
+        if (weakSelf.searchByImageEnabled &&
+            matched_types.find(ClipboardContentType::Image) !=
+                matched_types.end()) {
+          weakSelf.copiedContentType = ClipboardContentType::Image;
+        } else if (matched_types.find(ClipboardContentType::URL) !=
+                   matched_types.end()) {
+          weakSelf.copiedContentType = ClipboardContentType::URL;
+        } else if (matched_types.find(ClipboardContentType::Text) !=
+                   matched_types.end()) {
+          weakSelf.copiedContentType = ClipboardContentType::Text;
+        }
+      }));
+}
+
 - (void)menuControllerWillShow:(NSNotification*)notification {
   if (self.showingEditMenu || !self.isTextfieldEditing ||
       !self.textField.window.isKeyWindow) {
@@ -357,6 +424,14 @@
   self.showingEditMenu = NO;
 }
 
+- (void)pasteboardDidChange:(NSNotification*)notification {
+  [self updateCachedClipboardState];
+}
+
+- (void)applicationDidBecomeActive:(NSNotification*)notification {
+  [self updateCachedClipboardState];
+}
+
 #pragma mark clear button
 
 // Omnibox uses a custom clear button. It has a custom tint and image, but
@@ -441,16 +516,16 @@
   if (action == @selector(searchCopiedImage:) ||
       action == @selector(visitCopiedLink:) ||
       action == @selector(searchCopiedText:)) {
-    ClipboardRecentContent* clipboardRecentContent =
-        ClipboardRecentContent::GetInstance();
-    if (self.searchByImageEnabled &&
-        clipboardRecentContent->HasRecentImageFromClipboard()) {
+    if (!self.hasCopiedContent) {
+      return NO;
+    }
+    if (self.copiedContentType == ClipboardContentType::Image) {
       return action == @selector(searchCopiedImage:);
     }
-    if (clipboardRecentContent->GetRecentURLFromClipboard().has_value()) {
+    if (self.copiedContentType == ClipboardContentType::URL) {
       return action == @selector(visitCopiedLink:);
     }
-    if (clipboardRecentContent->GetRecentTextFromClipboard().has_value()) {
+    if (self.copiedContentType == ClipboardContentType::Text) {
       return action == @selector(searchCopiedText:);
     }
     return NO;
@@ -462,42 +537,48 @@
   RecordAction(
       UserMetricsAction("Mobile.OmniboxContextMenu.SearchCopiedImage"));
   self.omniboxInteractedWhileFocused = YES;
-  if (ClipboardRecentContent::GetInstance()->HasRecentImageFromClipboard()) {
-    ClipboardRecentContent::GetInstance()->GetRecentImageFromClipboard(
-        base::BindOnce(^(base::Optional<gfx::Image> optionalImage) {
-          UIImage* image = optionalImage.value().ToUIImage();
+  ClipboardRecentContent::GetInstance()->GetRecentImageFromClipboard(
+      base::BindOnce(^(base::Optional<gfx::Image> optionalImage) {
+        if (!optionalImage) {
+          return;
+        }
+        UIImage* image = optionalImage.value().ToUIImage();
+        dispatch_async(dispatch_get_main_queue(), ^{
           [self.dispatcher searchByImage:image];
-          [self.dispatcher cancelOmniboxEdit];
-        }));
-  }
+        });
+      }));
 }
 
 - (void)visitCopiedLink:(id)sender {
   RecordAction(UserMetricsAction("Mobile.OmniboxContextMenu.VisitCopiedLink"));
-  [self pasteAndGo:sender];
+  self.omniboxInteractedWhileFocused = YES;
+  ClipboardRecentContent::GetInstance()->GetRecentURLFromClipboard(
+      base::BindOnce(^(base::Optional<GURL> optionalURL) {
+        NSString* url;
+        if (optionalURL) {
+          url = base::SysUTF8ToNSString(optionalURL.value().spec());
+        }
+        dispatch_async(dispatch_get_main_queue(), ^{
+          [self.dispatcher loadQuery:url immediately:YES];
+          [self.dispatcher cancelOmniboxEdit];
+        });
+      }));
 }
 
 - (void)searchCopiedText:(id)sender {
   RecordAction(UserMetricsAction("Mobile.OmniboxContextMenu.SearchCopiedText"));
-  [self pasteAndGo:sender];
-}
-
-// Both actions are performed the same, but need to be enabled differently,
-// so we need two different selectors.
-- (void)pasteAndGo:(id)sender {
-  NSString* query;
-  ClipboardRecentContent* clipboardRecentContent =
-      ClipboardRecentContent::GetInstance();
-  if (base::Optional<GURL> optionalUrl =
-          clipboardRecentContent->GetRecentURLFromClipboard()) {
-    query = base::SysUTF8ToNSString(optionalUrl.value().spec());
-  } else if (base::Optional<base::string16> optionalText =
-                 clipboardRecentContent->GetRecentTextFromClipboard()) {
-    query = base::SysUTF16ToNSString(optionalText.value());
-  }
   self.omniboxInteractedWhileFocused = YES;
-  [self.dispatcher loadQuery:query immediately:YES];
-  [self.dispatcher cancelOmniboxEdit];
+  ClipboardRecentContent::GetInstance()->GetRecentTextFromClipboard(
+      base::BindOnce(^(base::Optional<base::string16> optionalText) {
+        NSString* query;
+        if (optionalText) {
+          query = base::SysUTF16ToNSString(optionalText.value());
+        }
+        dispatch_async(dispatch_get_main_queue(), ^{
+          [self.dispatcher loadQuery:query immediately:YES];
+          [self.dispatcher cancelOmniboxEdit];
+        });
+      }));
 }
 
 @end
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm
index ff6e9a5..6aed82d 100644
--- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator_unittest.mm
@@ -494,7 +494,7 @@
   policy::PolicyMap map;
   map.Set("test-policy", policy::POLICY_LEVEL_MANDATORY,
           policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_PLATFORM,
-          std::make_unique<base::Value>("hello"), nullptr);
+          base::Value("hello"), nullptr);
   enterprise_policy_helper->GetPolicyProvider()->UpdateChromePolicy(map);
 
   CreateMediatorWithBrowserPolicyConnector(
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_edit_table_view_controller+protected.h b/ios/chrome/browser/ui/settings/autofill/autofill_edit_table_view_controller+protected.h
index e0188e4..4656906c 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_edit_table_view_controller+protected.h
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_edit_table_view_controller+protected.h
@@ -13,6 +13,9 @@
 // Returns the indexPath for the currently focused text field when in edit mode.
 - (NSIndexPath*)indexPathForCurrentTextField;
 
+// Returns whether cell at indexPath is editCell.
+- (BOOL)isItemAtIndexPathTextEditCell:(NSIndexPath*)cellPath;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_EDIT_TABLE_VIEW_CONTROLLER_PROTECTED_H_
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_edit_table_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_edit_table_view_controller.mm
index 5d58685..932d4279 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_edit_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_edit_table_view_controller.mm
@@ -160,13 +160,17 @@
   return [self.tableView indexPathForCell:_currentEditingCell];
 }
 
+- (BOOL)isItemAtIndexPathTextEditCell:(NSIndexPath*)cellPath {
+  return YES;
+}
+
 - (void)moveToAnotherCellWithOffset:(NSInteger)offset {
   NSIndexPath* cellPath = [self indexPathForCurrentTextField];
   DCHECK(cellPath);
   NSIndexPath* nextCellPath = [self indexForCellPathWithOffset:offset
                                                       fromPath:cellPath];
 
-  if (!nextCellPath) {
+  if (!nextCellPath || ![self isItemAtIndexPathTextEditCell:nextCellPath]) {
     [[_currentEditingCell textField] resignFirstResponder];
   } else {
     TableViewTextEditCell* nextCell =
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_view_controller.mm
index bd3e7f7..03e9570f3 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_view_controller.mm
@@ -415,6 +415,19 @@
   [self reloadData];
 }
 
+- (BOOL)isItemAtIndexPathTextEditCell:(NSIndexPath*)cellPath {
+  NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:cellPath];
+  switch (static_cast<ItemType>(itemType)) {
+    case ItemTypePassword:
+      return YES;
+    case ItemTypeWebsite:
+    case ItemTypeUsername:
+    case ItemTypeChangePasswordButton:
+    case ItemTypeChangePasswordRecommendation:
+      return NO;
+  }
+}
+
 #pragma mark - Actions
 
 // Called when the user tapped on the show/hide button near password.
diff --git a/ios/chrome/browser/ui/snackbar/snackbar_coordinator.mm b/ios/chrome/browser/ui/snackbar/snackbar_coordinator.mm
index e4b0825..6295bd4 100644
--- a/ios/chrome/browser/ui/snackbar/snackbar_coordinator.mm
+++ b/ios/chrome/browser/ui/snackbar/snackbar_coordinator.mm
@@ -49,4 +49,25 @@
   [[MDCSnackbarManager defaultManager] showMessage:message];
 }
 
+- (void)showSnackbarWithMessage:(NSString*)messageText
+                     buttonText:(NSString*)buttonText
+                  messageAction:(void (^)(void))messageAction
+               completionAction:(void (^)(BOOL))completionAction {
+  MDCSnackbarMessageAction* action = [[MDCSnackbarMessageAction alloc] init];
+  action.handler = messageAction;
+  action.title = buttonText;
+  action.accessibilityLabel = buttonText;
+  MDCSnackbarMessage* message =
+      [MDCSnackbarMessage messageWithText:messageText];
+  message.action = action;
+  message.completionHandler = completionAction;
+
+  NamedGuide* bottomToolbarGuide =
+      [NamedGuide guideWithName:kSecondaryToolbarGuide
+                           view:self.baseViewController.view];
+  CGRect bottomToolbarFrame = bottomToolbarGuide.constrainedView.frame;
+  [self showSnackbarMessage:message
+               bottomOffset:bottomToolbarFrame.size.height];
+}
+
 @end
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index c04df53..71ba4c5 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -450,6 +450,7 @@
     "//components/version_info:version_info",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser:chrome_url_constants",
+    "//ios/chrome/browser/ui/infobars/banners:public",
     "//ios/chrome/browser/ui/popup_menu:constants",
     "//ios/chrome/browser/ui/util:multiwindow_util",
     "//ios/chrome/test:eg_test_support+eg2",
diff --git a/ios/chrome/browser/web/window_open_by_dom_egtest.mm b/ios/chrome/browser/web/window_open_by_dom_egtest.mm
index 3064ba3..e3f549ae 100644
--- a/ios/chrome/browser/web/window_open_by_dom_egtest.mm
+++ b/ios/chrome/browser/web/window_open_by_dom_egtest.mm
@@ -8,6 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "components/content_settings/core/common/content_settings.h"
+#import "ios/chrome/browser/ui/infobars/banners/infobar_banner_constants.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
@@ -34,9 +35,12 @@
 
 // Returns matcher for Blocked Popup infobar.
 id<GREYMatcher> PopupBlocker() {
-  NSString* blockerText = base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
-      IDS_IOS_POPUPS_BLOCKED_MOBILE, base::UTF8ToUTF16("1")));
-  return grey_accessibilityLabel(blockerText);
+  return grey_allOf(
+      grey_accessibilityID(kInfobarBannerViewIdentifier),
+      grey_accessibilityLabel(
+          base::SysUTF16ToNSString(l10n_util::GetStringFUTF16(
+              IDS_IOS_POPUPS_BLOCKED_MOBILE, base::UTF8ToUTF16("1")))),
+      nil);
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/window_activities/BUILD.gn b/ios/chrome/browser/window_activities/BUILD.gn
index c3aa2d6..0a578a1b 100644
--- a/ios/chrome/browser/window_activities/BUILD.gn
+++ b/ios/chrome/browser/window_activities/BUILD.gn
@@ -2,6 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/buildflag_header.gni")
+import("//ios/build/chrome_build.gni")
+
 source_set("window_activities") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
@@ -9,6 +12,7 @@
     "window_activity_helpers.mm",
   ]
   deps = [
+    ":ios_move_tab_activity_type_buildflags",
     "//base",
     "//ios/chrome/browser:chrome_url_constants",
     "//ios/chrome/browser/url_loading",
@@ -17,3 +21,8 @@
     "//url",
   ]
 }
+
+buildflag_header("ios_move_tab_activity_type_buildflags") {
+  header = "move_tab_activity_type_buildflags.h"
+  flags = [ "IOS_MOVE_TAB_ACTIVITY_TYPE=\"$ios_move_tab_activity_type\"" ]
+}
diff --git a/ios/chrome/browser/window_activities/window_activity_helpers.h b/ios/chrome/browser/window_activities/window_activity_helpers.h
index 2dbe97f..8be3025c5 100644
--- a/ios/chrome/browser/window_activities/window_activity_helpers.h
+++ b/ios/chrome/browser/window_activities/window_activity_helpers.h
@@ -71,4 +71,7 @@
 // Returns the recorded origin for the given activity.
 WindowActivityOrigin OriginOfActivity(NSUserActivity* activity);
 
+// Returns the tab identifier from the given activity.
+NSString* GetTabIDFromActivity(NSUserActivity* activity);
+
 #endif  // IOS_CHROME_BROWSER_WINDOW_ACTIVITIES_WINDOW_ACTIVITY_HELPERS_H_
diff --git a/ios/chrome/browser/window_activities/window_activity_helpers.mm b/ios/chrome/browser/window_activities/window_activity_helpers.mm
index 0c6c748..61ebb354 100644
--- a/ios/chrome/browser/window_activities/window_activity_helpers.mm
+++ b/ios/chrome/browser/window_activities/window_activity_helpers.mm
@@ -9,15 +9,16 @@
 #endif
 
 #include "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/url_loading/url_loading_params.h"
+#include "ios/chrome/browser/window_activities/move_tab_activity_type_buildflags.h"
 #import "ios/web/public/navigation/navigation_manager.h"
 #import "net/base/mac/url_conversions.h"
 
 // Activity types.
 NSString* const kLoadURLActivityType = @"org.chromium.load.url";
 NSString* const kLoadIncognitoURLActivityType = @"org.chromium.load.otr-url";
-NSString* const kMoveTabActivityType = @"org.chromium.move-tab";
 
 // User info keys.
 NSString* const kURLKey = @"LoadParams_URL";
@@ -69,8 +70,10 @@
 }
 
 NSUserActivity* ActivityToMoveTab(NSString* tab_id) {
+  NSString* moveTabActivityType =
+      base::SysUTF8ToNSString(BUILDFLAG(IOS_MOVE_TAB_ACTIVITY_TYPE));
   NSUserActivity* activity =
-      [[NSUserActivity alloc] initWithActivityType:kMoveTabActivityType];
+      [[NSUserActivity alloc] initWithActivityType:moveTabActivityType];
   [activity addUserInfoEntriesFromDictionary:@{kTabIdentifierKey : tab_id}];
   return activity;
 }
@@ -81,7 +84,9 @@
 }
 
 bool ActivityIsTabMove(NSUserActivity* activity) {
-  return [activity.activityType isEqualToString:kMoveTabActivityType];
+  NSString* moveTabActivityType =
+      base::SysUTF8ToNSString(BUILDFLAG(IOS_MOVE_TAB_ACTIVITY_TYPE));
+  return [activity.activityType isEqualToString:moveTabActivityType];
 }
 
 UrlLoadParams LoadParamsFromActivity(NSUserActivity* activity) {
@@ -114,3 +119,9 @@
   return origin ? static_cast<WindowActivityOrigin>(origin.intValue)
                 : WindowActivityUnknownOrigin;
 }
+
+NSString* GetTabIDFromActivity(NSUserActivity* activity) {
+  if (!ActivityIsTabMove(activity))
+    return nil;
+  return activity.userInfo[kTabIdentifierKey];
+}
diff --git a/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni b/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni
index 6a30fcb..4ab51bda 100644
--- a/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni
+++ b/ios/chrome/test/earl_grey2/chrome_ios_eg2_test.gni
@@ -133,6 +133,7 @@
       "SSOAUTH_URL_SCHEME=$url_ssoauth_scheme",
       "CONTENT_WIDGET_EXTENSION_BUNDLE_ID=$chromium_bundle_id.ContentTodayExtension",
       "CHROMIUM_BUNDLE_ID=gtest.$target_name",
+      "IOS_MOVE_TAB_ACTIVITY_TYPE=$ios_move_tab_activity_type",
     ]
   }
 }
diff --git a/media/gpu/mac/vt_config_util_unittest.cc b/media/gpu/mac/vt_config_util_unittest.cc
index 9f728315..751994a 100644
--- a/media/gpu/mac/vt_config_util_unittest.cc
+++ b/media/gpu/mac/vt_config_util_unittest.cc
@@ -268,7 +268,7 @@
   EXPECT_EQ(cs.ToGfxColorSpace(), GetImageBufferColorSpace(image_buffer));
 }
 
-TEST(VTConfigUtil, GetImageBufferColorSpace_BT2020_PQ) {
+TEST(VTConfigUtil, DISABLED_GetImageBufferColorSpace_BT2020_PQ) {
   auto cs = VideoColorSpace(VideoColorSpace::PrimaryID::BT2020,
                             VideoColorSpace::TransferID::SMPTEST2084,
                             VideoColorSpace::MatrixID::BT2020_NCL,
@@ -278,7 +278,7 @@
   EXPECT_EQ(cs.ToGfxColorSpace(), GetImageBufferColorSpace(image_buffer));
 }
 
-TEST(VTConfigUtil, GetImageBufferColorSpace_BT2020_HLG) {
+TEST(VTConfigUtil, DISABLED_GetImageBufferColorSpace_BT2020_HLG) {
   auto cs = VideoColorSpace(VideoColorSpace::PrimaryID::BT2020,
                             VideoColorSpace::TransferID::ARIB_STD_B67,
                             VideoColorSpace::MatrixID::BT2020_NCL,
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc
index e8afbae..608b609 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.cc
+++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -96,6 +96,19 @@
   ClearDecodeTaskQueue(DecodeStatus::ABORTED);
 
   weak_this_factory_.InvalidateWeakPtrs();
+
+  // Destroy explicitly to DCHECK() that |vaapi_wrapper_| references are held
+  // inside the accelerator in |decoder_|, by the |allocated_va_surfaces_| and
+  // of course by this class. To clear |allocated_va_surfaces_| we have to first
+  // DestroyContext().
+  decoder_ = nullptr;
+  if (vaapi_wrapper_) {
+    vaapi_wrapper_->DestroyContext();
+    allocated_va_surfaces_.clear();
+
+    DCHECK(vaapi_wrapper_->HasOneRef());
+    vaapi_wrapper_ = nullptr;
+  }
 }
 
 void VaapiVideoDecoder::Initialize(const VideoDecoderConfig& config,
@@ -123,6 +136,9 @@
     DVLOGF(3) << "Reinitializing decoder";
 
     decoder_ = nullptr;
+    // To clear |allocated_va_surfaces_| we have to first DestroyContext().
+    vaapi_wrapper_->DestroyContext();
+    allocated_va_surfaces_.clear();
     vaapi_wrapper_ = nullptr;
     decoder_delegate_ = nullptr;
     SetState(State::kUninitialized);
@@ -298,22 +314,29 @@
     return nullptr;
   }
 
-  scoped_refptr<gfx::NativePixmap> pixmap =
-      CreateNativePixmapDmaBuf(frame.get());
-  if (!pixmap) {
-    LOG(ERROR) << "Failed to create NativePixmap from VideoFrame";
-    SetState(State::kError);
-    return nullptr;
-  }
+  DCHECK(frame->GetGpuMemoryBuffer());
+  const gfx::GpuMemoryBufferId frame_id = frame->GetGpuMemoryBuffer()->GetId();
+  scoped_refptr<VASurface> va_surface;
 
-  // Create VASurface from the native pixmap.
-  scoped_refptr<VASurface> va_surface =
-      vaapi_wrapper_->CreateVASurfaceForPixmap(std::move(pixmap));
+  if (!base::Contains(allocated_va_surfaces_, frame_id)) {
+    scoped_refptr<gfx::NativePixmap> pixmap =
+        CreateNativePixmapDmaBuf(frame.get());
+    if (!pixmap) {
+      LOG(ERROR) << "Failed to create NativePixmap from VideoFrame";
+      SetState(State::kError);
+      return nullptr;
+    }
 
-  if (!va_surface || va_surface->id() == VA_INVALID_ID) {
-    LOG(ERROR) << "Failed to create VASurface from VideoFrame";
-    SetState(State::kError);
-    return nullptr;
+    va_surface = vaapi_wrapper_->CreateVASurfaceForPixmap(std::move(pixmap));
+    if (!va_surface || va_surface->id() == VA_INVALID_ID) {
+      LOG(ERROR) << "Failed to create VASurface from VideoFrame";
+      SetState(State::kError);
+      return nullptr;
+    }
+
+    allocated_va_surfaces_[frame_id] = va_surface;
+  } else {
+    va_surface = allocated_va_surfaces_[frame_id];
   }
 
   // Store the mapping between surface and video frame, so we know which video
@@ -325,14 +348,12 @@
   output_frames_[surface_id] = frame;
 
   // When the decoder is done using the frame for output or reference, it will
-  // drop its reference to the surface. We can then safely destroy the surface
-  // and remove the associated video frame from |output_frames_|. To be notified
-  // when this happens we wrap the surface in another surface that calls
-  // ReleaseFrame() on destruction. The |va_surface| object is bound to the
-  // destruction callback to keep it alive, since the associated VAAPI surface
-  // will be automatically destroyed when we drop the reference.
-  VASurface::ReleaseCB release_frame_cb = base::BindOnce(
-      &VaapiVideoDecoder::ReleaseFrame, weak_this_, std::move(va_surface));
+  // drop its reference to the surface. We can then safely remove the associated
+  // video frame from |output_frames_|. To be notified when this happens we wrap
+  // the surface in another surface with ReleaseVideoFrame() as destruction
+  // observer.
+  VASurface::ReleaseCB release_frame_cb =
+      base::BindOnce(&VaapiVideoDecoder::ReleaseVideoFrame, weak_this_);
 
   return new VASurface(surface_id, frame->layout().coded_size(),
                        GetVaFormatForVideoCodecProfile(profile_),
@@ -414,7 +435,11 @@
   }
 
   // All pending decode operations will be completed before triggering a
-  // resolution change, so we can safely destroy the context here.
+  // resolution change, so we can safely DestroyContext() here; that, in turn,
+  // allows for clearing the |allocated_va_surfaces_|.
+  vaapi_wrapper_->DestroyContext();
+  allocated_va_surfaces_.clear();
+
   if (profile_ != decoder_->GetProfile()) {
     // When a profile is changed, we need to re-initialize VaapiWrapper.
     profile_ = decoder_->GetProfile();
@@ -427,8 +452,6 @@
     }
     decoder_delegate_->set_vaapi_wrapper(new_vaapi_wrapper.get());
     vaapi_wrapper_ = std::move(new_vaapi_wrapper);
-  } else {
-    vaapi_wrapper_->DestroyContext();
   }
 
   vaapi_wrapper_->CreateContext(pic_size);
@@ -445,10 +468,8 @@
   }
 }
 
-void VaapiVideoDecoder::ReleaseFrame(scoped_refptr<VASurface> va_surface,
-                                     VASurfaceID surface_id) {
+void VaapiVideoDecoder::ReleaseVideoFrame(VASurfaceID surface_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DCHECK_EQ(va_surface->id(), surface_id);
   DVLOGF(4);
 
   // The decoder has finished using the frame associated with |surface_id| for
diff --git a/media/gpu/vaapi/vaapi_video_decoder.h b/media/gpu/vaapi/vaapi_video_decoder.h
index 5d42041..5cdec2d 100644
--- a/media/gpu/vaapi/vaapi_video_decoder.h
+++ b/media/gpu/vaapi/vaapi_video_decoder.h
@@ -15,6 +15,7 @@
 
 #include "base/containers/mru_cache.h"
 #include "base/containers/queue.h"
+#include "base/containers/small_map.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
@@ -29,6 +30,7 @@
 #include "media/video/supported_video_decoder_config.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 
 namespace media {
 
@@ -103,13 +105,11 @@
   void ClearDecodeTaskQueue(DecodeStatus status);
 
   // Releases the local reference to the VideoFrame associated with the
-  // specified |surface_id| on the decoder thread. This is called when the last
-  // reference to the associated VASurface has been released, which happens when
-  // |decoder_| outputted the video frame, or stopped using it as a reference
-  // frame. Note that this doesn't mean the frame can be reused immediately, as
-  // it might still be used by the client.
-  void ReleaseFrame(scoped_refptr<VASurface> va_surface,
-                    VASurfaceID surface_id);
+  // specified |surface_id| on the decoder thread. This is called when
+  // |decoder_| has outputted the VideoFrame and stopped using it as a
+  // reference frame. Note that this doesn't mean the frame can be reused
+  // immediately, as it might still be used by the client.
+  void ReleaseVideoFrame(VASurfaceID surface_id);
   // Callback for |frame_pool_| to notify of available resources.
   void NotifyFrameAvailable();
 
@@ -159,6 +159,15 @@
   // The list of frames currently used as output buffers or reference frames.
   std::map<VASurfaceID, scoped_refptr<VideoFrame>> output_frames_;
 
+  // VASurfaces are created via importing |frame_pool_| resources into libva in
+  // CreateSurface(). The following map keeps those VASurfaces for reuse
+  // according to the expectations of libva vaDestroySurfaces(): "Surfaces can
+  // only be destroyed after all contexts using these surfaces have been
+  // destroyed."
+  // TODO(crbug.com/1040291): remove this keep-alive when using SharedImages.
+  base::small_map<std::map<gfx::GpuMemoryBufferId, scoped_refptr<VASurface>>>
+      allocated_va_surfaces_;
+
   // Platform and codec specific video decoder.
   std::unique_ptr<AcceleratedVideoDecoder> decoder_;
   scoped_refptr<VaapiWrapper> vaapi_wrapper_;
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
index 51fa67296b..e4c5fe66 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -51,6 +51,8 @@
 
 #include "mojo/public/cpp/bindings/mojo_buildflags.h"
 #if BUILDFLAG(MOJO_TRACE_ENABLED)
+#include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_conversion_helper.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
 #endif
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
index ddc0eff..6d2aba81 100644
--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -776,7 +776,8 @@
       yield _AddSingleValue('Integer', cpp_parameter_name)
       return
     if kind in [mojom.UINT32, mojom.INT64, mojom.UINT64]:
-      yield _AddSingleValue('String', 'std::to_string(%s)' % cpp_parameter_name)
+      yield _AddSingleValue('String',
+                            'base::NumberToString(%s)' % cpp_parameter_name)
       return
     if mojom.IsFloatKind(kind) or mojom.IsDoubleKind(kind):
       yield _AddSingleValue('Double', cpp_parameter_name)
@@ -834,8 +835,12 @@
           loop_body=loop_body)):
         yield line
       return
-    yield _AddSingleValue(
-        'String', ' "<value of type %s>"' % self._GetCppWrapperParamType(kind))
+
+    def _TraceEventToString(cpp_parameter_name=cpp_parameter_name, kind=kind):
+      return 'base::trace_event::ValueToString(%s, "<value of type %s>")' % (
+          cpp_parameter_name, self._GetCppWrapperParamType(kind))
+
+    yield _AddSingleValue('String', _TraceEventToString())
 
   def _GetCppWrapperType(self,
                          kind,
diff --git a/net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java b/net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java
index 01a3595..74b513d5 100644
--- a/net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java
+++ b/net/android/java/src/org/chromium/net/RegistrationPolicyApplicationStatus.java
@@ -4,6 +4,7 @@
 
 package org.chromium.net;
 
+import org.chromium.base.ApplicationState;
 import org.chromium.base.ApplicationStatus;
 
 /**
@@ -18,7 +19,7 @@
     protected void init(NetworkChangeNotifierAutoDetect notifier) {
         super.init(notifier);
         ApplicationStatus.registerApplicationStateListener(this);
-        onApplicationStateChange(0 /* unused */);
+        onApplicationStateChange(ApplicationState.UNKNOWN /* unused */);
     }
 
     @Override
diff --git a/net/base/backoff_entry_serializer.cc b/net/base/backoff_entry_serializer.cc
index 90196dd..ce643224 100644
--- a/net/base/backoff_entry_serializer.cc
+++ b/net/base/backoff_entry_serializer.cc
@@ -4,6 +4,7 @@
 
 #include "net/base/backoff_entry_serializer.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/strings/string_number_conversions.h"
@@ -15,6 +16,15 @@
 // Increment this number when changing the serialization format, to avoid old
 // serialized values loaded from disk etc being misinterpreted.
 const int kSerializationFormatVersion = 1;
+
+// This max defines how many times we are willing to call
+// |BackoffEntry::InformOfRequest| in |DeserializeFromValue|.
+//
+// This value is meant to large enough that the computed backoff duration can
+// still be saturated. Given that the duration is an int64 and assuming 1.01 as
+// a conservative lower bound for BackoffEntry::Policy::multiply_factor,
+// ceil(log(2**63-1, 1.01)) = 4389.
+const int kMaxFailureCount = 4389;
 }  // namespace
 
 namespace net {
@@ -57,8 +67,11 @@
   }
 
   int failure_count;
-  if (!serialized_list->GetInteger(1, &failure_count) || failure_count < 0)
+  if (!serialized_list->GetInteger(1, &failure_count) || failure_count < 0) {
     return nullptr;
+  }
+  failure_count = std::min(failure_count, kMaxFailureCount);
+
   double original_backoff_duration_double;
   if (!serialized_list->GetDouble(2, &original_backoff_duration_double))
     return nullptr;
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index cf68e4c..06225c6 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -154,16 +154,22 @@
               NetLogNumberValue(frame->ack_delay_time.ToMicroseconds()));
 
   base::Value missing(base::Value::Type::LIST);
+  quic::QuicPacketNumber smallest_observed;
   if (!frame->packets.Empty()) {
     // V34 and above express acked packets, but only print
     // missing packets, because it's typically a shorter list.
-    for (quic::QuicPacketNumber packet = frame->packets.Min();
+    smallest_observed = frame->packets.Min();
+    for (quic::QuicPacketNumber packet = smallest_observed;
          packet < frame->largest_acked; ++packet) {
       if (!frame->packets.Contains(packet)) {
         missing.Append(NetLogNumberValue(packet.ToUint64()));
       }
     }
+  } else {
+    smallest_observed = frame->largest_acked;
   }
+  dict.SetKey("smallest_observed",
+              NetLogNumberValue(smallest_observed.ToUint64()));
   dict.SetKey("missing_packets", std::move(missing));
 
   base::Value received(base::Value::Type::LIST);
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 18c51ce..80a7132 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -231,9 +231,6 @@
 // Staging for https://review.skia.org/302290
 #define SK_IMAGE_MAKE_COLOR_TYPE_AND_SPACE_USE_SOURCE_CONTEXT
 
-// Staging for https://review.skia.org/304003
-#define SK_IMAGE_MAKE_WITH_FILTER_LEGACY_API
-
 // Staging for https://review.skia.org/305102
 #define SK_IMAGE_MAKE_FROM_TEXTURE_LEGACY_API
 
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 5dd8d810..5126e8ea 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -211,6 +211,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -236,6 +237,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -261,6 +263,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -286,6 +289,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -311,6 +315,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -336,6 +341,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -361,6 +367,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -663,6 +670,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -688,6 +696,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -713,6 +722,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -738,6 +748,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -763,6 +774,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -788,6 +800,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -813,6 +826,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
@@ -838,6 +852,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
diff --git a/testing/buildbot/filters/bfcache.content_unittests.filter b/testing/buildbot/filters/bfcache.content_unittests.filter
index 1d054ea8..2d8f82a 100644
--- a/testing/buildbot/filters/bfcache.content_unittests.filter
+++ b/testing/buildbot/filters/bfcache.content_unittests.filter
@@ -1,5 +1 @@
 # These tests currently fail when run with --enable-features=BackForwardCache
-
-# https://crbug.com/1102630
-# Needs investigation.
--All/RenderFrameHostManagerTest.BeginNavigationIgnoredWhenNotActive/*
diff --git a/testing/test_env.py b/testing/test_env.py
index 7199826..9d60926 100755
--- a/testing/test_env.py
+++ b/testing/test_env.py
@@ -2,7 +2,6 @@
 # Copyright (c) 2012 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.
-# Whitespace change for crbug.com/1112996. TODO: Delete me.
 
 """Sets environment variables needed to run a chromium unit test."""
 
@@ -10,7 +9,6 @@
 import io
 import os
 import signal
-import stat
 import subprocess
 import sys
 import time
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c200eb2..f87d1e7e 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -676,6 +676,27 @@
             ]
         }
     ],
+    "AutofillEnableCardNicknameManagementAndUpstream": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "AutofillEnableCardNicknameManagement",
+                        "AutofillEnableCardNicknameUpstream"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillEnableSurfacingServerCardNickname": [
         {
             "platforms": [
@@ -2242,6 +2263,25 @@
             ]
         }
     ],
+    "DisableLatencyRecoveryDesktop": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "DisabledImplDisabledMain",
+                    "disable_features": [
+                        "ImplLatencyRecovery",
+                        "MainLatencyRecovery"
+                    ]
+                }
+            ]
+        }
+    ],
     "DisableMalwareExtensionsRemotely": [
         {
             "platforms": [
@@ -6122,6 +6162,28 @@
             ]
         }
     ],
+    "SafeBrowsingDelayedWarnings": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "mouse": "true"
+                    },
+                    "enable_features": [
+                        "SafeBrowsingDelayedWarnings"
+                    ]
+                }
+            ]
+        }
+    ],
     "SafeBrowsingPasswordProtectionForSavedPasswords": [
         {
             "platforms": [
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 6aa0a82..0d23cc3 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -91,7 +91,7 @@
 /google_benchmark/src
 /google_toolbox_for_mac/src
 /googlemac
-/grpc/src
+/grpc
 /gvr-android-sdk/common_library.aar
 /gvr-android-sdk/test-libraries/controller_test_api.aar
 /gvr-android-sdk/libgvr_shim_static_*.a
@@ -236,7 +236,7 @@
 /webgl
 /webgl/src
 /webgpu-cts/src
-/webpagereplay/bin
+/webpagereplay
 /webrtc
 /weston/src
 /widevine/cdm/chromeos
diff --git a/third_party/android_platform/development/scripts/PRESUBMIT.py b/third_party/android_platform/development/scripts/PRESUBMIT.py
index c7a35f9..6260f12 100644
--- a/third_party/android_platform/development/scripts/PRESUBMIT.py
+++ b/third_party/android_platform/development/scripts/PRESUBMIT.py
@@ -16,8 +16,8 @@
       input_api,
       output_api,
       input_api.PresubmitLocalPath(),
-      whitelist=[r'.+_test\.py$'],
-      blacklist=[])
+      files_to_check=[r'.+_test\.py$'],
+      files_to_skip=[])
 
   output.extend(input_api.RunTests(py_tests, False))
 
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 8062979..13c78bc 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -251,7 +251,6 @@
     "platform/web_spell_check_panel_host_client.h",
     "platform/web_string.h",
     "platform/web_surface_layer_bridge.h",
-    "platform/web_text_autosizer_page_info.h",
     "platform/web_text_input_info.h",
     "platform/web_text_input_mode.h",
     "platform/web_text_input_type.h",
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 8a7a058..b40bb59 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -7247,6 +7247,8 @@
       boolean attached
       # Opener target Id
       optional TargetID openerId
+      # Whether the opened window has access to the originating window.
+      experimental boolean canAccessOpener
       experimental optional Browser.BrowserContextID browserContextId
 
   experimental type RemoteLocation extends object
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom
index 3a3404f..06f5a2d 100644
--- a/third_party/blink/public/mojom/frame/frame.mojom
+++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -116,7 +116,7 @@
 const uint16 kMaxTitleChars = 4096; // 4 * 1024;
 
 struct TextAutosizerPageInfo {
-  // LocalFrame width in density-independent pixels.
+  // Frame width in density-independent pixels.
   int32 main_frame_width;
 
   // Layout width in CSS pixels.
@@ -906,6 +906,9 @@
 //
 // This interface will only be provided when the RemoteFrame is a main frame.
 interface RemoteMainFrame {
+  // Makes the TextAutosizerPageInfo received from a local main frame available
+  // to remote main frame renderers.
+  UpdateTextAutosizerPageInfo(blink.mojom.TextAutosizerPageInfo page_info);
 };
 
 // Implemented in Browser, this interface defines local-main-frame-specific
diff --git a/third_party/blink/public/mojom/service_worker/service_worker.mojom b/third_party/blink/public/mojom/service_worker/service_worker.mojom
index 4c91844..1790790 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker.mojom
@@ -133,10 +133,11 @@
   DOES_NOT_EXIST,
 };
 
-// The number of seconds for which a 'push' event should be allowed to run.
-// This is not in the spec but for a Chrome-specific timeout. Each
-// event dispatched to service workers has a 5 minute timeout in the Chrome
-// implementation, but this makes the timeout for push events shorter.
+// The number of seconds for which a 'push' and the 'pushsubsciptionchange'
+// event should be allowed to run. This is not in the spec but for a
+// Chrome-specific timeout. Each event dispatched to service workers has a 5
+// minute timeout in the Chrome implementation, but this makes the timeout for
+// push events shorter.
 const int32 kPushEventTimeoutSeconds = 90;
 
 // The default number of seconds for idle timeouts. A service worker requests
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 4ebb83bf..2f55d4c3 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2694,6 +2694,9 @@
   kHtmlClipboardApiRead = 3362,
   kHtmlClipboardApiWrite = 3363,
   kCSSSystemColorComputeToSelf = 3364,
+  kConversionAPIAll = 3365,
+  kImpressionRegistration = 3366,
+  kConversionRegistration = 3367,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_text_autosizer_page_info.h b/third_party/blink/public/platform/web_text_autosizer_page_info.h
deleted file mode 100644
index 3299eca..0000000
--- a/third_party/blink/public/platform/web_text_autosizer_page_info.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_TEXT_AUTOSIZER_PAGE_INFO_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_TEXT_AUTOSIZER_PAGE_INFO_H_
-
-namespace blink {
-
-struct WebTextAutosizerPageInfo {
-  WebTextAutosizerPageInfo() = default;
-
-  int main_frame_width;  // LocalFrame width in density-independent pixels.
-  int main_frame_layout_width;  // Layout width in CSS pixels.
-  float device_scale_adjustment;
-};
-
-inline bool operator==(const WebTextAutosizerPageInfo& lhs,
-                       const WebTextAutosizerPageInfo& rhs) {
-  return lhs.main_frame_width == rhs.main_frame_width &&
-         lhs.main_frame_layout_width == rhs.main_frame_layout_width &&
-         lhs.device_scale_adjustment == rhs.device_scale_adjustment;
-}
-
-inline bool operator!=(const WebTextAutosizerPageInfo& lhs,
-                       const WebTextAutosizerPageInfo& rhs) {
-  return lhs.main_frame_width != rhs.main_frame_width ||
-         lhs.main_frame_layout_width != rhs.main_frame_layout_width ||
-         lhs.device_scale_adjustment != rhs.device_scale_adjustment;
-}
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_TEXT_AUTOSIZER_PAGE_INFO_H_
diff --git a/third_party/blink/public/web/web_view.h b/third_party/blink/public/web/web_view.h
index 2be7d1c..f3c18b7 100644
--- a/third_party/blink/public/web/web_view.h
+++ b/third_party/blink/public/web/web_view.h
@@ -70,7 +70,6 @@
 struct DeviceEmulationParams;
 struct WebRect;
 struct WebSize;
-struct WebTextAutosizerPageInfo;
 struct WebWindowFeatures;
 
 class WebView {
@@ -460,10 +459,6 @@
 
   // Portals --------------------------------------------------------------
 
-  // Use to transfer TextAutosizer state from the local main frame renderer to
-  // remote main frame renderers.
-  virtual void SetTextAutosizerPageInfo(const WebTextAutosizerPageInfo&) {}
-
  protected:
   ~WebView() = default;
 };
diff --git a/third_party/blink/public/web/web_view_client.h b/third_party/blink/public/web/web_view_client.h
index ed009638..cfb57e6f 100644
--- a/third_party/blink/public/web/web_view_client.h
+++ b/third_party/blink/public/web/web_view_client.h
@@ -99,6 +99,8 @@
 
   virtual void OnPageVisibilityChanged(mojom::PageVisibilityState visibility) {}
 
+  virtual void OnPageFrozenChanged(bool frozen) {}
+
   // UI ------------------------------------------------------------------
 
   // Called when hovering over an anchor with the given URL.
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
index 4b93ab7..6fdce97 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
@@ -251,7 +251,7 @@
   return parser->GetWindow();
 }
 
-v8::MaybeLocal<v8::Function> CreateNamedConstructorFunction(
+v8::MaybeLocal<v8::Value> CreateNamedConstructorFunction(
     ScriptState* script_state,
     v8::FunctionCallback callback,
     const char* func_name,
@@ -262,6 +262,10 @@
   V8PerIsolateData* per_isolate_data = V8PerIsolateData::From(isolate);
   const void* callback_key = reinterpret_cast<const void*>(callback);
 
+  if (!script_state->ContextIsValid()) {
+    return v8::Undefined(isolate);
+  }
+
   // Named constructors are not interface objcets (despite that they're
   // pretending so), but we reuse the cache of interface objects, which just
   // works because both are V8 function template.
@@ -286,7 +290,7 @@
   V8PerContextData* per_context_data = V8PerContextData::From(context);
   v8::Local<v8::Function> function;
   if (!function_template->GetFunction(context).ToLocal(&function)) {
-    return v8::MaybeLocal<v8::Function>();
+    return v8::MaybeLocal<v8::Value>();
   }
   v8::Local<v8::Object> prototype_object =
       per_context_data->PrototypeForType(wrapper_type_info);
@@ -297,7 +301,7 @@
                static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum |
                                                   v8::DontDelete))
            .To(&did_define)) {
-    return v8::MaybeLocal<v8::Function>();
+    return v8::MaybeLocal<v8::Value>();
   }
   CHECK(did_define);
   return function;
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
index c7a18376..1960c73 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.h
@@ -168,7 +168,7 @@
 CORE_EXPORT ExecutionContext* ExecutionContextFromV8Wrappable(
     const DOMParser* parser);
 
-CORE_EXPORT v8::MaybeLocal<v8::Function> CreateNamedConstructorFunction(
+CORE_EXPORT v8::MaybeLocal<v8::Value> CreateNamedConstructorFunction(
     ScriptState* script_state,
     v8::FunctionCallback callback,
     const char* func_name,
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index f8d747de..0fa9ea6 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -2068,17 +2068,17 @@
 """
 
     pattern = """\
-v8::Local<v8::Function> v8_function;
+v8::Local<v8::Value> v8_value;
 if (!bindings::CreateNamedConstructorFunction(
          ${script_state},
          {callback},
          "{func_name}",
          {func_length},
          {v8_bridge}::GetWrapperTypeInfo())
-     .ToLocal(&v8_function)) {
+     .ToLocal(&v8_value)) {
   return;
 }
-bindings::V8SetReturnValue(${info}, v8_function);
+bindings::V8SetReturnValue(${info}, v8_value);
 """
     create_named_constructor_function = _format(
         pattern,
@@ -2088,7 +2088,7 @@
         v8_bridge=named_ctor_v8_bridge)
 
     return_value_cache_update_value = """\
-v8_private_named_constructor.Set(${v8_receiver}, v8_function);
+v8_private_named_constructor.Set(${v8_receiver}, v8_value);
 """
 
     body.extend([
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index 47a0542..5b112f9 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -2131,6 +2131,138 @@
 }
 
 TEST_F(DisplayLockContextRenderingTest,
+       PaintDirtyBitsNotPropagatedAcrossBoundary) {
+  SetHtmlInnerHTML(R"HTML(
+    <style>
+    .locked { content-visibility: hidden; }
+    div { contain: paint; }
+    </style>
+    <div id=parent>
+      <div id=lockable>
+        <div id=child>
+          <div id=grandchild></div>
+        </div>
+      </div>
+    </div>
+  )HTML");
+
+  auto* parent = GetDocument().getElementById("parent");
+  auto* lockable = GetDocument().getElementById("lockable");
+  auto* child = GetDocument().getElementById("child");
+  auto* grandchild = GetDocument().getElementById("grandchild");
+
+  auto* parent_box = ToLayoutBoxModelObject(parent->GetLayoutObject());
+  auto* lockable_box = ToLayoutBoxModelObject(lockable->GetLayoutObject());
+  auto* child_box = ToLayoutBoxModelObject(child->GetLayoutObject());
+  auto* grandchild_box = ToLayoutBoxModelObject(grandchild->GetLayoutObject());
+
+  ASSERT_TRUE(parent_box);
+  ASSERT_TRUE(lockable_box);
+  ASSERT_TRUE(child_box);
+  ASSERT_TRUE(grandchild_box);
+
+  ASSERT_TRUE(parent_box->HasSelfPaintingLayer());
+  ASSERT_TRUE(lockable_box->HasSelfPaintingLayer());
+  ASSERT_TRUE(child_box->HasSelfPaintingLayer());
+  ASSERT_TRUE(grandchild_box->HasSelfPaintingLayer());
+
+  auto* parent_layer = parent_box->Layer();
+  auto* lockable_layer = lockable_box->Layer();
+  auto* child_layer = child_box->Layer();
+  auto* grandchild_layer = grandchild_box->Layer();
+
+  EXPECT_FALSE(parent_layer->SelfOrDescendantNeedsRepaint());
+  EXPECT_FALSE(lockable_layer->SelfOrDescendantNeedsRepaint());
+  EXPECT_FALSE(child_layer->SelfOrDescendantNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->SelfOrDescendantNeedsRepaint());
+
+  lockable->classList().Add("locked");
+  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
+
+  // Lockable layer needs repainting after locking.
+  EXPECT_FALSE(parent_layer->SelfNeedsRepaint());
+  EXPECT_TRUE(lockable_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(child_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->SelfNeedsRepaint());
+
+  // Breadcrumbs are set from the lockable layer.
+  EXPECT_TRUE(parent_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(lockable_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(child_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->DescendantNeedsRepaint());
+
+  UpdateAllLifecyclePhasesForTest();
+
+  // Everything is clean.
+  EXPECT_FALSE(parent_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(lockable_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(child_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->SelfNeedsRepaint());
+
+  // Breadcrumbs are clean as well.
+  EXPECT_FALSE(parent_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(lockable_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(child_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->DescendantNeedsRepaint());
+
+  grandchild_layer->SetNeedsRepaint();
+
+  // Grandchild needs repaint, so everything else should be clean.
+  EXPECT_FALSE(parent_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(lockable_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(child_layer->SelfNeedsRepaint());
+  EXPECT_TRUE(grandchild_layer->SelfNeedsRepaint());
+
+  // Breadcrumbs are set from the lockable layer but are stopped at the locked
+  // boundary.
+  EXPECT_FALSE(parent_layer->DescendantNeedsRepaint());
+  EXPECT_TRUE(lockable_layer->DescendantNeedsRepaint());
+  EXPECT_TRUE(child_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->DescendantNeedsRepaint());
+
+  // Updating the lifecycle does not clean the dirty bits.
+  UpdateAllLifecyclePhasesForTest();
+
+  EXPECT_FALSE(parent_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(lockable_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(child_layer->SelfNeedsRepaint());
+  EXPECT_TRUE(grandchild_layer->SelfNeedsRepaint());
+
+  EXPECT_FALSE(parent_layer->DescendantNeedsRepaint());
+  EXPECT_TRUE(lockable_layer->DescendantNeedsRepaint());
+  EXPECT_TRUE(child_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->DescendantNeedsRepaint());
+
+  // Unlocking causes lockable to repaint itself.
+  lockable->classList().Remove("locked");
+  GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
+
+  EXPECT_FALSE(parent_layer->SelfNeedsRepaint());
+  EXPECT_TRUE(lockable_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(child_layer->SelfNeedsRepaint());
+  EXPECT_TRUE(grandchild_layer->SelfNeedsRepaint());
+
+  EXPECT_TRUE(parent_layer->DescendantNeedsRepaint());
+  EXPECT_TRUE(lockable_layer->DescendantNeedsRepaint());
+  EXPECT_TRUE(child_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->DescendantNeedsRepaint());
+
+  UpdateAllLifecyclePhasesForTest();
+
+  // Everything should be clean.
+  EXPECT_FALSE(parent_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(lockable_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(child_layer->SelfNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->SelfNeedsRepaint());
+
+  // Breadcrumbs are clean as well.
+  EXPECT_FALSE(parent_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(lockable_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(child_layer->DescendantNeedsRepaint());
+  EXPECT_FALSE(grandchild_layer->DescendantNeedsRepaint());
+}
+
+TEST_F(DisplayLockContextRenderingTest,
        NestedLockDoesNotInvalidateOnHideOrShow) {
   SetHtmlInnerHTML(R"HTML(
     <style>
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 9ae726b..91703eb 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -47,7 +47,6 @@
 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
 #include "third_party/blink/public/platform/interface_registry.h"
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
-#include "third_party/blink/public/platform/web_text_autosizer_page_info.h"
 #include "third_party/blink/public/platform/web_text_input_info.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/platform/web_vector.h"
@@ -2447,13 +2446,13 @@
     Scheduler()->SetPageBackForwardCached(state->is_in_back_forward_cache);
   }
   if (freezing_page)
-    Scheduler()->SetPageFrozen(true);
+    SetPageFrozen(true);
   if (storing_in_bfcache)
     HookBackForwardCacheEviction(true);
   if (restoring_from_bfcache)
     HookBackForwardCacheEviction(false);
   if (resuming_page)
-    Scheduler()->SetPageFrozen(false);
+    SetPageFrozen(false);
   if (restoring_from_bfcache) {
     DispatchPageshow(navigation_start.value());
     Scheduler()->SetPageBackForwardCached(state->is_in_back_forward_cache);
@@ -2686,17 +2685,6 @@
   UpdateMainFrameLayoutSize();
 }
 
-void WebViewImpl::SetTextAutosizerPageInfo(
-    const WebTextAutosizerPageInfo& page_info) {
-  Frame* root_frame = GetPage()->MainFrame();
-  DCHECK(root_frame->IsRemoteFrame());
-  if (page_info == GetPage()->TextAutosizerPageInfo())
-    return;
-
-  GetPage()->SetTextAutosizerPageInfo(page_info);
-  TextAutosizer::UpdatePageInfoInAllFrames(root_frame);
-}
-
 void WebViewImpl::UpdateMainFrameLayoutSize() {
   if (should_auto_resize_ || !MainFrameImpl())
     return;
@@ -3168,12 +3156,10 @@
 }
 
 void WebViewImpl::TextAutosizerPageInfoChanged(
-    const WebTextAutosizerPageInfo& page_info) {
+    const mojom::blink::TextAutosizerPageInfo& page_info) {
   DCHECK(MainFrameImpl());
   local_main_frame_host_remote_->TextAutosizerPageInfoChanged(
-      mojom::blink::TextAutosizerPageInfo::New(
-          page_info.main_frame_width, page_info.main_frame_layout_width,
-          page_info.device_scale_adjustment));
+      page_info.Clone());
 }
 
 void WebViewImpl::SetBackgroundColorOverride(SkColor color) {
@@ -3456,6 +3442,7 @@
 
 void WebViewImpl::SetPageFrozen(bool frozen) {
   Scheduler()->SetPageFrozen(frozen);
+  AsView().client->OnPageFrozenChanged(frozen);
 }
 
 WebFrameWidget* WebViewImpl::MainFrameWidget() {
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
index 3994f22..53b6ea2 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -94,7 +94,11 @@
 class WebViewClient;
 class WebFrameWidgetBase;
 
-struct WebTextAutosizerPageInfo;
+namespace mojom {
+namespace blink {
+class TextAutosizerPageInfo;
+}
+}  // namespace mojom
 
 using PaintHoldingCommitTrigger = cc::PaintHoldingCommitTrigger;
 
@@ -202,7 +206,6 @@
   WebFrameWidget* MainFrameWidget() override;
   void SetBaseBackgroundColor(SkColor) override;
   void PaintContent(cc::PaintCanvas*, const gfx::Rect&) override;
-  void SetTextAutosizerPageInfo(const WebTextAutosizerPageInfo&) override;
 
   // Overrides the page's background and base background color. You
   // can use this to enforce a transparent background, which is useful if you
@@ -305,7 +308,8 @@
   void DidChangeContentsSize();
   void PageScaleFactorChanged();
   void MainFrameScrollOffsetChanged();
-  void TextAutosizerPageInfoChanged(const WebTextAutosizerPageInfo& page_info);
+  void TextAutosizerPageInfoChanged(
+      const mojom::blink::TextAutosizerPageInfo& page_info);
 
   bool ShouldAutoResize() const { return should_auto_resize_; }
 
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index 5863a1b..56cd1d1 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/text_autosizer.h"
 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
 #include "third_party/blink/renderer/core/loader/frame_loader.h"
 #include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
@@ -720,6 +721,19 @@
   }
 }
 
+void RemoteFrame::UpdateTextAutosizerPageInfo(
+    mojom::blink::TextAutosizerPageInfoPtr mojo_remote_page_info) {
+  // Only propagate the remote page info if our main frame is remote.
+  DCHECK(IsMainFrame());
+  Frame* root_frame = GetPage()->MainFrame();
+  DCHECK(root_frame->IsRemoteFrame());
+  if (*mojo_remote_page_info == GetPage()->TextAutosizerPageInfo())
+    return;
+
+  GetPage()->SetTextAutosizerPageInfo(*mojo_remote_page_info);
+  TextAutosizer::UpdatePageInfoInAllFrames(root_frame);
+}
+
 void RemoteFrame::WasAttachedAsRemoteMainFrame() {
   interface_registry_->AddAssociatedInterface(WTF::BindRepeating(
       &RemoteFrame::BindToMainFrameReceiver, WrapWeakPersistent(this)));
diff --git a/third_party/blink/renderer/core/frame/remote_frame.h b/third_party/blink/renderer/core/frame/remote_frame.h
index 47ad891..636ee4325 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.h
+++ b/third_party/blink/renderer/core/frame/remote_frame.h
@@ -168,6 +168,13 @@
 
   void SetOpener(Frame* opener) override;
 
+  // blink::mojom::RemoteMainFrame overrides:
+  //
+  // Use to transfer TextAutosizer state from the local main frame renderer to
+  // remote main frame renderers.
+  void UpdateTextAutosizerPageInfo(
+      mojom::blink::TextAutosizerPageInfoPtr page_info) override;
+
   // Indicate that this frame was attached as a MainFrame.
   void WasAttachedAsRemoteMainFrame();
 
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc
index 00d9b1c5..b7189a40 100644
--- a/third_party/blink/renderer/core/html/html_anchor_element.cc
+++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -423,6 +423,11 @@
       expiry = base::TimeDelta::FromMilliseconds(expiry_milliseconds);
   }
 
+  UseCounter::Count(GetExecutionContext(),
+                    mojom::blink::WebFeature::kConversionAPIAll);
+  UseCounter::Count(GetExecutionContext(),
+                    mojom::blink::WebFeature::kImpressionRegistration);
+
   return WebImpression{conversion_destination, reporting_origin,
                        impression_data, expiry};
 }
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_cascade.cc b/third_party/blink/renderer/core/inspector/inspector_css_cascade.cc
index cde4e9c..7c41e18 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_cascade.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_css_cascade.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/css/css_value.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
 #include "third_party/blink/renderer/core/dom/pseudo_element.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
@@ -33,6 +34,9 @@
   matched_rules_ = style_resolver.PseudoCSSRulesForElement(
       element_, element_pseudo_id, StyleResolver::kAllCSSRules);
 
+  if (element_pseudo_id)
+    return;
+
   for (PseudoId pseudo_id = kFirstPublicPseudoId;
        pseudo_id < kAfterLastInternalPseudoId;
        pseudo_id = static_cast<PseudoId>(pseudo_id + 1)) {
@@ -56,9 +60,7 @@
   }
 
   // Parent rules.
-  // TODO (alexrudenko): Use the flat-tree parent (FlatTreeTraversal::Parent)
-  // (not ParentOrShadowHostElement).
-  Element* parent_element = element_->ParentOrShadowHostElement();
+  Element* parent_element = FlatTreeTraversal::ParentElement(*element);
   while (parent_element) {
     RuleIndexList* parent_matched_rules = style_resolver.CssRulesForElement(
         parent_element, StyleResolver::kAllCSSRules);
@@ -68,7 +70,7 @@
     match->matched_rules = parent_matched_rules;
     match->pseudo_id = kPseudoIdNone;
     parent_rules_.push_back(match);
-    parent_element = parent_element->ParentOrShadowHostElement();
+    parent_element = FlatTreeTraversal::ParentElement(*parent_element);
   }
 }
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_css_cascade_test.cc b/third_party/blink/renderer/core/inspector/inspector_css_cascade_test.cc
index 340375b..56c7e92c 100644
--- a/third_party/blink/renderer/core/inspector/inspector_css_cascade_test.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_css_cascade_test.cc
@@ -44,10 +44,46 @@
   const CSSValue* value =
       cascade.GetCascadedProperty(CSSPropertyID::kGridTemplateColumns);
   const CSSValueList* value_list = DynamicTo<CSSValueList>(value);
-  EXPECT_EQ((unsigned)3, value_list->length());
+  EXPECT_EQ(3u, value_list->length());
   EXPECT_EQ("100px", value_list->Item(0).CssText());
   EXPECT_EQ("1fr", value_list->Item(1).CssText());
   EXPECT_EQ("20%", value_list->Item(2).CssText());
 }
 
+TEST_F(InspectorCSSCascadeTest, ParentRules) {
+  GetDocument().body()->setInnerHTML(R"HTML(
+    <style>
+      #grid-container {
+        display: inline-grid;
+        grid-gap: 5px;
+        grid-template-columns: 50px 1fr 10%;
+      }
+      #grid {
+        display: grid;
+        grid-gap: 10px;
+        grid-template-columns: 100px 2fr 20%;
+      }
+    </style>
+    <div id="grid-container">
+      <div id="grid"></div>
+    </div>
+  )HTML");
+  Element* grid = GetDocument().getElementById("grid");
+  InspectorCSSCascade cascade(grid, kPseudoIdNone);
+  HeapVector<Member<InspectorCSSMatchedRules>> parent_rules =
+      cascade.ParentRules();
+  Element* grid_container = GetDocument().getElementById("grid-container");
+  // Some rules are coming for UA.
+  EXPECT_EQ(3u, parent_rules.size());
+  // grid_container is the first parent.
+  EXPECT_EQ(grid_container, parent_rules.at(0)->element);
+  // Some rules are coming from UA.
+  EXPECT_EQ(2u, parent_rules.at(0)->matched_rules->size());
+  auto rule = parent_rules.at(0)->matched_rules->at(1);
+  EXPECT_EQ(
+      "#grid-container { display: inline-grid; gap: 5px; "
+      "grid-template-columns: 50px 1fr 10%; }",
+      rule.first->cssText());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
index cd446119..52f62a8 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
@@ -29,7 +29,6 @@
 void NGInlineCursor::SetRoot(const NGFragmentItems& fragment_items,
                              ItemsSpan items) {
   DCHECK(items.data() || !items.size());
-  DCHECK(!HasRoot());
   fragment_items_ = &fragment_items;
   items_ = items;
   DCHECK(fragment_items_->IsSubSpan(items_));
@@ -47,15 +46,31 @@
   current_.paint_fragment_ = root_paint_fragment.FirstChild();
 }
 
+bool NGInlineCursor::TrySetRootFragmentItems() {
+  DCHECK(root_block_flow_);
+  DCHECK(!fragment_items_ || fragment_items_->Equals(items_));
+  for (; fragment_index_ <= max_fragment_index_; ++fragment_index_) {
+    const NGPhysicalBoxFragment* fragment =
+        root_block_flow_->GetPhysicalFragment(fragment_index_);
+    DCHECK(fragment);
+    if (const NGFragmentItems* items = fragment->Items()) {
+      SetRoot(*items);
+      return true;
+    }
+  }
+  return false;
+}
+
 void NGInlineCursor::SetRoot(const LayoutBlockFlow& block_flow) {
   DCHECK(&block_flow);
   DCHECK(!HasRoot());
 
-  if (const NGPhysicalBoxFragment* fragment = block_flow.CurrentFragment()) {
-    if (const NGFragmentItems* items = fragment->Items()) {
-      SetRoot(*items);
+  if (const wtf_size_t fragment_count = block_flow.PhysicalFragmentCount()) {
+    root_block_flow_ = &block_flow;
+    max_fragment_index_ = fragment_count - 1;
+    fragment_index_ = 0;
+    if (TrySetRootFragmentItems())
       return;
-    }
   }
 
   if (const NGPaintFragment* paint_fragment = block_flow.PaintFragment()) {
@@ -964,23 +979,6 @@
   return span_index;
 }
 
-NGInlineCursor::ItemsSpan::iterator NGInlineCursor::SlowFirstItemIteratorFor(
-    const LayoutObject& layout_object,
-    const ItemsSpan& items) {
-  for (ItemsSpan::iterator iter = items.begin(); iter != items.end(); ++iter) {
-    if (iter->GetLayoutObject() == &layout_object)
-      return iter;
-  }
-  return items.end();
-}
-
-wtf_size_t NGInlineCursor::SlowFirstItemIndexFor(
-    const LayoutObject& layout_object,
-    const ItemsSpan& items) {
-  ItemsSpan::iterator iter = SlowFirstItemIteratorFor(layout_object, items);
-  return iter - items.begin();
-}
-
 void NGInlineCursor::MoveTo(const NGFragmentItem& fragment_item) {
   DCHECK(!root_paint_fragment_ && !current_.paint_fragment_);
   MoveTo(*fragment_item.GetLayoutObject());
@@ -1380,6 +1378,55 @@
   NOTREACHED();
 }
 
+void NGInlineCursor::MoveToFirstIncludingFragmentainer() {
+  if (!fragment_index_ || IsPaintFragmentCursor()) {
+    MoveToFirst();
+    return;
+  }
+
+  fragment_index_ = 0;
+  if (!TrySetRootFragmentItems())
+    MakeNull();
+}
+
+void NGInlineCursor::MoveToNextFragmentainer() {
+  DCHECK(CanMoveAcrossFragmentainer());
+  if (fragment_index_ < max_fragment_index_) {
+    ++fragment_index_;
+    if (TrySetRootFragmentItems())
+      return;
+  }
+  MakeNull();
+}
+
+void NGInlineCursor::MoveToNextIncludingFragmentainer() {
+  MoveToNext();
+  if (!Current() && max_fragment_index_ && CanMoveAcrossFragmentainer())
+    MoveToNextFragmentainer();
+}
+
+inline bool NGInlineCursor::CanUseLayoutObjectIndex() const {
+  if (!RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled())
+    return true;
+  return CanMoveAcrossFragmentainer() && max_fragment_index_ == 0;
+}
+
+void NGInlineCursor::SlowMoveToForIfNeeded(const LayoutObject& layout_object) {
+  while (Current() && Current().GetLayoutObject() != &layout_object)
+    MoveToNextIncludingFragmentainer();
+}
+
+void NGInlineCursor::SlowMoveToFirstFor(const LayoutObject& layout_object) {
+  MoveToFirstIncludingFragmentainer();
+  SlowMoveToForIfNeeded(layout_object);
+}
+
+void NGInlineCursor::SlowMoveToNextForSameLayoutObject(
+    const LayoutObject& layout_object) {
+  MoveToNextIncludingFragmentainer();
+  SlowMoveToForIfNeeded(layout_object);
+}
+
 void NGInlineCursor::MoveTo(const LayoutObject& layout_object) {
   DCHECK(layout_object.IsInLayoutNGInlineFormattingContext());
   if (UNLIKELY(layout_object.IsOutOfFlowPositioned())) {
@@ -1429,48 +1476,80 @@
   }
 
   // If this cursor is rootless, find the root of the inline formatting context.
+  bool is_descendants_cursor = false;
   if (!HasRoot()) {
-    const LayoutBlockFlow* root = layout_object.RootInlineFormattingContext();
+    const LayoutBlockFlow* root = layout_object.FragmentItemsContainer();
     DCHECK(root);
-    const NGFragmentItems* fragment_items = root->FragmentItems();
-    if (UNLIKELY(!fragment_items)) {
+    SetRoot(*root);
+    if (UNLIKELY(!HasRoot())) {
       MakeNull();
       return;
     }
-    SetRoot(*fragment_items);
-    DCHECK(HasRoot());
+    DCHECK(!IsDescendantsCursor());
+  } else {
+    is_descendants_cursor = IsDescendantsCursor();
+  }
+
+  // TODO(crbug.com/829028): |FirstInlineFragmentItemIndex| is not setup when
+  // block fragmented. Use the slow codepath.
+  if (UNLIKELY(!CanUseLayoutObjectIndex())) {
+    layout_object_to_slow_move_to_ = &layout_object;
+    SlowMoveToFirstFor(layout_object);
+    return;
   }
 
   wtf_size_t item_index = layout_object.FirstInlineFragmentItemIndex();
   if (UNLIKELY(!item_index)) {
-    DCHECK_EQ(SlowFirstItemIndexFor(layout_object, fragment_items_->Items()),
-              fragment_items_->Size());
+#if DCHECK_IS_ON()
+    const LayoutBlockFlow* root = layout_object.FragmentItemsContainer();
+    NGInlineCursor check_cursor(*root);
+    check_cursor.SlowMoveToFirstFor(layout_object);
+    DCHECK(!check_cursor);
+#endif
     MakeNull();
     return;
   }
-
   // |FirstInlineFragmentItemIndex| is 1-based. Convert to 0-based index.
   --item_index;
-  DCHECK_EQ(SlowFirstItemIndexFor(layout_object, fragment_items_->Items()),
-            item_index);
 
-  // Skip items before |items_|, in case |this| is part of IFC.
-  if (UNLIKELY(!fragment_items_->Equals(items_))) {
-    const wtf_size_t span_begin_item_index = SpanBeginItemIndex();
-    while (UNLIKELY(item_index < span_begin_item_index)) {
-      const NGFragmentItem& item = fragment_items_->Items()[item_index];
-      const wtf_size_t next_delta = item.DeltaToNextForSameLayoutObject();
-      if (!next_delta) {
+  DCHECK_EQ(is_descendants_cursor, IsDescendantsCursor());
+  if (root_block_flow_) {
+    DCHECK(!is_descendants_cursor);
+#if DCHECK_IS_ON()
+    NGInlineCursor check_cursor(*root_block_flow_);
+    check_cursor.SlowMoveToFirstFor(layout_object);
+    DCHECK_EQ(check_cursor.Current().Item(),
+              &fragment_items_->Items()[item_index]);
+#endif
+  } else {
+#if DCHECK_IS_ON()
+    const LayoutBlockFlow* root = layout_object.FragmentItemsContainer();
+    NGInlineCursor check_cursor(*root);
+    check_cursor.SlowMoveToFirstFor(layout_object);
+    while (check_cursor && fragment_items_ != check_cursor.fragment_items_)
+      check_cursor.SlowMoveToNextForSameLayoutObject(layout_object);
+    DCHECK_EQ(check_cursor.Current().Item(),
+              &fragment_items_->Items()[item_index]);
+#endif
+
+    // Skip items before |items_|, in case |this| is part of IFC.
+    if (UNLIKELY(is_descendants_cursor)) {
+      const wtf_size_t span_begin_item_index = SpanBeginItemIndex();
+      while (UNLIKELY(item_index < span_begin_item_index)) {
+        const NGFragmentItem& item = fragment_items_->Items()[item_index];
+        const wtf_size_t next_delta = item.DeltaToNextForSameLayoutObject();
+        if (!next_delta) {
+          MakeNull();
+          return;
+        }
+        item_index += next_delta;
+      }
+      if (UNLIKELY(item_index >= span_begin_item_index + items_.size())) {
         MakeNull();
         return;
       }
-      item_index += next_delta;
+      item_index -= span_begin_item_index;
     }
-    if (UNLIKELY(item_index >= span_begin_item_index + items_.size())) {
-      MakeNull();
-      return;
-    }
-    item_index -= span_begin_item_index;
   }
 
   DCHECK_LT(item_index, items_.size());
@@ -1497,6 +1576,11 @@
     return MakeNull();
   }
   if (current_.item_) {
+    if (UNLIKELY(layout_object_to_slow_move_to_)) {
+      SlowMoveToNextForSameLayoutObject(*layout_object_to_slow_move_to_);
+      return;
+    }
+
     const wtf_size_t delta = current_.item_->DeltaToNextForSameLayoutObject();
     if (delta) {
       // Check the next item is in |items_| because |delta| can be beyond
@@ -1506,7 +1590,7 @@
         MoveToItem(current_.item_iter_ + delta);
         return;
       }
-      DCHECK(!fragment_items_->Equals(items_));
+      DCHECK(IsDescendantsCursor());
     }
     MakeNull();
   }
@@ -1529,43 +1613,47 @@
 
 // Traverse the |LayoutObject| tree in pre-order DFS and find a |LayoutObject|
 // that contributes to the culled inline.
-const LayoutObject* NGInlineCursor::CulledInlineTraversal::SetCurrent(
-    const LayoutObject* child) {
+const LayoutObject* NGInlineCursor::CulledInlineTraversal::Find(
+    const LayoutObject* child) const {
   while (child) {
-    if (UNLIKELY(child->IsFloatingOrOutOfFlowPositioned())) {
+    if (child->IsText())
+      return child;
+
+    if (child->IsBox()) {
+      if (!child->IsFloatingOrOutOfFlowPositioned())
+        return child;
       child = child->NextInPreOrderAfterChildren(layout_inline_);
       continue;
     }
 
-    if (child->HasInlineFragments()) {
-      current_object_ = child;
-      return child;
-    }
-
-    // A culled inline can be computed from its direct children, but when the
-    // child is also culled, traverse its grand children.
     if (const LayoutInline* child_layout_inline = ToLayoutInlineOrNull(child)) {
-      DCHECK(!child_layout_inline->ShouldCreateBoxFragment());
+      if (child_layout_inline->ShouldCreateBoxFragment())
+        return child;
+
+      // A culled inline can be computed from its direct children, but when the
+      // child is also culled, traverse its grand children.
       if (const LayoutObject* grand_child = child_layout_inline->FirstChild()) {
         child = grand_child;
         continue;
       }
     }
+
     child = child->NextInPreOrderAfterChildren(layout_inline_);
   }
-  current_object_ = nullptr;
   return nullptr;
 }
 
 const LayoutObject* NGInlineCursor::CulledInlineTraversal::MoveToFirstFor(
     const LayoutInline& layout_inline) {
   layout_inline_ = &layout_inline;
-  return SetCurrent(layout_inline.FirstChild());
+  current_object_ = Find(layout_inline.FirstChild());
+  return current_object_;
 }
 
 const LayoutObject* NGInlineCursor::CulledInlineTraversal::MoveToNext() {
-  return SetCurrent(
-      current_object_->NextInPreOrderAfterChildren(layout_inline_));
+  current_object_ =
+      Find(current_object_->NextInPreOrderAfterChildren(layout_inline_));
+  return current_object_;
 }
 
 void NGInlineCursor::MoveToFirstForCulledInline(
@@ -1596,10 +1684,6 @@
     MoveTo(*layout_object);
     if (Current())
       return;
-
-    // This |MoveTo| may fail if |this| is a descendant cursor. Try the next
-    // |LayoutObject|.
-    DCHECK(IsDescendantsCursor());
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
index 6f8eef3..0bef2435 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
@@ -414,6 +414,28 @@
   bool TryToMoveToLastChild();
 
   //
+  // Moving across fragmentainers.
+  //
+  // When rooted at |LayoutBlockFlow|, |this| can move the current position
+  // across fragmentainers. Other root objects (e.g. |NGFragmentItems|) can
+  // contain only one fragmentainer that such cursors cannot move to different
+  // fragmentainers. See |CanMoveAcrossFragmentainer()|.
+  //
+  // However, |MoveToNext| etc. does not move the current position across
+  // fragmentainers. Use following functions when moving to different
+  // fragmentainers.
+
+  // Move to the first item of the first fragmentainer.
+  void MoveToFirstIncludingFragmentainer();
+
+  // Move to the next fragmentainer. Valid when |CanMoveAcrossFragmentainer|.
+  void MoveToNextFragmentainer();
+
+  // Same as |MoveToNext|, except this moves to the next fragmentainer if
+  // |Current| is at the end of a fragmentainer.
+  void MoveToNextIncludingFragmentainer();
+
+  //
   // Functions to enumerate fragments for a |LayoutObject|.
   //
 
@@ -451,11 +473,19 @@
       return root_paint_fragment_->Parent();
     return false;
   }
+  bool CanMoveAcrossFragmentainer() const {
+    return root_block_flow_ && IsItemCursor() && !IsDescendantsCursor();
+  }
+  bool CanUseLayoutObjectIndex() const;
 
   // True if the current position is a last line in inline block. It is error
   // to call at end or the current position is not line.
   bool IsLastLineInInlineBlock() const;
 
+  // Index conversions for |IsDescendantsCursor()|.
+  wtf_size_t SpanBeginItemIndex() const;
+  wtf_size_t SpanIndexFromItemIndex(unsigned index) const;
+
   // Make the current position points nothing, e.g. cursor moves over start/end
   // fragment, cursor moves to first/last child to parent has no children.
   void MakeNull() { current_.Clear(); }
@@ -467,6 +497,9 @@
   void SetRoot(const NGFragmentItems& fragment_items, ItemsSpan items);
   void SetRoot(const NGPaintFragment& root_paint_fragment);
   void SetRoot(const LayoutBlockFlow& block_flow);
+  bool SetRoot(const LayoutBlockFlow& block_flow, wtf_size_t fragment_index);
+
+  bool TrySetRootFragmentItems();
 
   void MoveToItem(const ItemsSpan::iterator& iter);
   void MoveToNextItem();
@@ -480,13 +513,9 @@
   void MoveToPreviousPaintFragment();
   void MoveToPreviousSiblingPaintFragment();
 
-  static ItemsSpan::iterator SlowFirstItemIteratorFor(
-      const LayoutObject& layout_object,
-      const ItemsSpan& items);
-  static wtf_size_t SlowFirstItemIndexFor(const LayoutObject& layout_object,
-                                          const ItemsSpan& items);
-  wtf_size_t SpanBeginItemIndex() const;
-  wtf_size_t SpanIndexFromItemIndex(unsigned index) const;
+  void SlowMoveToFirstFor(const LayoutObject& layout_object);
+  void SlowMoveToNextForSameLayoutObject(const LayoutObject& layout_object);
+  void SlowMoveToForIfNeeded(const LayoutObject& layout_object);
 
   // |MoveToNextForSameLayoutObject| that doesn't check |culled_inline_|.
   void MoveToNextForSameLayoutObjectExceptCulledInline();
@@ -507,7 +536,7 @@
     const LayoutObject* MoveToNext();
 
    private:
-    const LayoutObject* SetCurrent(const LayoutObject* child);
+    const LayoutObject* Find(const LayoutObject* child) const;
 
     const LayoutObject* current_object_ = nullptr;
     const LayoutInline* layout_inline_ = nullptr;
@@ -526,6 +555,14 @@
 
   CulledInlineTraversal culled_inline_;
 
+  // Used to traverse multiple |NGFragmentItems| when block fragmented.
+  const LayoutBlockFlow* root_block_flow_ = nullptr;
+  wtf_size_t fragment_index_ = 0;
+  wtf_size_t max_fragment_index_ = 0;
+
+  // Used only when |!CanUseLayoutObjectIndex|.
+  const LayoutObject* layout_object_to_slow_move_to_ = nullptr;
+
   friend class NGInlineBackwardCursor;
 };
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
index a46f98f..9a6e59c 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
@@ -1056,6 +1056,124 @@
               ElementsAre("text3"));
 }
 
+class NGInlineCursorBlockFragmentationTest
+    : public NGLayoutTest,
+      private ScopedLayoutNGBlockFragmentationForTest {
+ public:
+  NGInlineCursorBlockFragmentationTest()
+      : ScopedLayoutNGBlockFragmentationForTest(true) {}
+};
+
+TEST_F(NGInlineCursorBlockFragmentationTest, MoveToLayoutObject) {
+  // This creates 3 columns, 1 line in each column.
+  SetBodyInnerHTML(R"HTML(
+    <style>
+    #container {
+      column-width: 6ch;
+      font-family: monospace;
+      font-size: 10px;
+      height: 1.5em;
+    }
+    </style>
+    <div id="container">
+      <span id="span1">1111 22</span><span id="span2">33 4444</span>
+    </div>
+  )HTML");
+  const LayoutObject* span1 = GetLayoutObjectByElementId("span1");
+  const LayoutObject* text1 = span1->SlowFirstChild();
+  const LayoutObject* span2 = GetLayoutObjectByElementId("span2");
+  const LayoutObject* text2 = span2->SlowFirstChild();
+
+  // Enumerate all fragments for |LayoutText|.
+  {
+    NGInlineCursor cursor;
+    cursor.MoveTo(*text1);
+    EXPECT_THAT(LayoutObjectToDebugStringList(cursor),
+                ElementsAre("1111", "22"));
+  }
+  {
+    NGInlineCursor cursor;
+    cursor.MoveTo(*text2);
+    EXPECT_THAT(LayoutObjectToDebugStringList(cursor),
+                ElementsAre("33", "4444"));
+  }
+  // |MoveTo| can find no fragments for culled inline.
+  {
+    NGInlineCursor cursor;
+    cursor.MoveTo(*span1);
+    EXPECT_FALSE(cursor);
+  }
+  {
+    NGInlineCursor cursor;
+    cursor.MoveTo(*span2);
+    EXPECT_FALSE(cursor);
+  }
+  // But |MoveToIncludingCulledInline| should find its descendants.
+  {
+    NGInlineCursor cursor;
+    cursor.MoveToIncludingCulledInline(*span1);
+    EXPECT_THAT(LayoutObjectToDebugStringList(cursor),
+                ElementsAre("1111", "22"));
+  }
+  {
+    NGInlineCursor cursor;
+    cursor.MoveToIncludingCulledInline(*span2);
+    EXPECT_THAT(LayoutObjectToDebugStringList(cursor),
+                ElementsAre("33", "4444"));
+  }
+
+  // Line-ranged cursors can find fragments only in the line.
+  // The 1st line has "1111", from "text1".
+  NGInlineCursor cursor(*span1->FragmentItemsContainer());
+  EXPECT_TRUE(cursor.Current().IsLineBox());
+  NGInlineCursor line1 = cursor.CursorForDescendants();
+  line1.MoveTo(*text1);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line1), ElementsAre("1111"));
+  line1 = cursor.CursorForDescendants();
+  line1.MoveToIncludingCulledInline(*span1);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line1), ElementsAre("1111"));
+  line1 = cursor.CursorForDescendants();
+  line1.MoveTo(*text2);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line1), ElementsAre());
+  line1 = cursor.CursorForDescendants();
+  line1.MoveToIncludingCulledInline(*span2);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line1), ElementsAre());
+
+  // The 2nd line has "22" from "text1" and "33" from text2.
+  cursor.MoveToNextFragmentainer();
+  EXPECT_TRUE(cursor);
+  EXPECT_TRUE(cursor.Current().IsLineBox());
+  NGInlineCursor line2 = cursor.CursorForDescendants();
+  line2.MoveTo(*text1);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line2), ElementsAre("22"));
+  line2 = cursor.CursorForDescendants();
+  line2.MoveToIncludingCulledInline(*span1);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line2), ElementsAre("22"));
+  line2 = cursor.CursorForDescendants();
+  line2.MoveTo(*text2);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line2), ElementsAre("33"));
+  line2 = cursor.CursorForDescendants();
+  line2.MoveToIncludingCulledInline(*span2);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line2), ElementsAre("33"));
+
+  // The 3rd line has "4444" from text2.
+  cursor.MoveToNextFragmentainer();
+  EXPECT_TRUE(cursor);
+  EXPECT_TRUE(cursor.Current().IsLineBox());
+  NGInlineCursor line3 = cursor.CursorForDescendants();
+  line3.MoveTo(*text1);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line3), ElementsAre());
+  line3 = cursor.CursorForDescendants();
+  line3.MoveToIncludingCulledInline(*span1);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line3), ElementsAre());
+  line3 = cursor.CursorForDescendants();
+  line3.MoveTo(*text2);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line3), ElementsAre("4444"));
+  line3 = cursor.CursorForDescendants();
+  line3.MoveToIncludingCulledInline(*span2);
+  EXPECT_THAT(LayoutObjectToDebugStringList(line3), ElementsAre("4444"));
+}
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.cc b/third_party/blink/renderer/core/layout/text_autosizer.cc
index c9428fd..24e0bc7 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer.cc
+++ b/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -599,7 +599,7 @@
       // called UpdateWebTextAutosizerPageInfoIfNecessary().
       if (frame->IsMainFrame()) {
         const PageInfo& page_info = text_autosizer->page_info_;
-        const WebTextAutosizerPageInfo& old_page_info =
+        const mojom::blink::TextAutosizerPageInfo& old_page_info =
             document->GetPage()->TextAutosizerPageInfo();
         if (page_info.shared_info_ != old_page_info) {
           document->GetPage()->GetChromeClient().DidUpdateTextAutosizerPageInfo(
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.h b/third_party/blink/renderer/core/layout/text_autosizer.h
index 923a6b2a..9112f2d 100644
--- a/third_party/blink/renderer/core/layout/text_autosizer.h
+++ b/third_party/blink/renderer/core/layout/text_autosizer.h
@@ -34,7 +34,7 @@
 #include <unicode/uchar.h>
 #include <memory>
 #include "base/macros.h"
-#include "third_party/blink/public/platform/web_text_autosizer_page_info.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/geometry/layout_unit.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -55,6 +55,18 @@
 class Page;
 class SubtreeLayoutScope;
 
+inline bool operator==(const mojom::blink::TextAutosizerPageInfo& lhs,
+                       const mojom::blink::TextAutosizerPageInfo& rhs) {
+  return lhs.main_frame_width == rhs.main_frame_width &&
+         lhs.main_frame_layout_width == rhs.main_frame_layout_width &&
+         lhs.device_scale_adjustment == rhs.device_scale_adjustment;
+}
+
+inline bool operator!=(const mojom::blink::TextAutosizerPageInfo& lhs,
+                       const mojom::blink::TextAutosizerPageInfo& rhs) {
+  return !(lhs == rhs);
+}
+
 // Single-pass text autosizer. Documentation at:
 // http://tinyurl.com/TextAutosizer
 
@@ -282,7 +294,7 @@
     DISALLOW_NEW();
     PageInfo() = default;
 
-    WebTextAutosizerPageInfo shared_info_;
+    mojom::blink::TextAutosizerPageInfo shared_info_;
     float accessibility_font_scale_factor_;
     bool page_needs_autosizing_;
     bool has_autosized_;
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index e1e5e65f..eb7b053 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -1085,6 +1085,13 @@
   GetFrame()->GetRemoteNavigationAssociatedInterfaces()->GetInterface(
       &conversion_host);
   conversion_host->RegisterConversion(std::move(conversion));
+
+  // Log use counters once we have a conversion.
+  UseCounter::Count(document_->domWindow(),
+                    mojom::blink::WebFeature::kConversionAPIAll);
+  UseCounter::Count(document_->domWindow(),
+                    mojom::blink::WebFeature::kConversionRegistration);
+
   return true;
 }
 
diff --git a/third_party/blink/renderer/core/page/chrome_client.h b/third_party/blink/renderer/core/page/chrome_client.h
index 4125afd..3265f65 100644
--- a/third_party/blink/renderer/core/page/chrome_client.h
+++ b/third_party/blink/renderer/core/page/chrome_client.h
@@ -101,12 +101,17 @@
 
 struct DateTimeChooserParameters;
 struct FrameLoadRequest;
-struct WebTextAutosizerPageInfo;
 struct ViewportDescription;
 struct ScreenInfo;
 struct WebWindowFeatures;
 struct WebRect;
 
+namespace mojom {
+namespace blink {
+class TextAutosizerPageInfo;
+}
+}  // namespace mojom
+
 using CompositorElementId = cc::ElementId;
 
 class CORE_EXPORT ChromeClient : public GarbageCollected<ChromeClient> {
@@ -499,8 +504,8 @@
 
   virtual void Trace(Visitor*) const;
 
-  virtual void DidUpdateTextAutosizerPageInfo(const WebTextAutosizerPageInfo&) {
-  }
+  virtual void DidUpdateTextAutosizerPageInfo(
+      const mojom::blink::TextAutosizerPageInfo&) {}
 
   virtual void DocumentDetached(Document&) {}
 
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc
index 322a7141..5f53cc8 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.cc
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -1224,7 +1224,7 @@
 }
 
 void ChromeClientImpl::DidUpdateTextAutosizerPageInfo(
-    const WebTextAutosizerPageInfo& page_info) {
+    const mojom::blink::TextAutosizerPageInfo& page_info) {
   web_view_->TextAutosizerPageInfoChanged(page_info);
 }
 
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.h b/third_party/blink/renderer/core/page/chrome_client_impl.h
index 7ee0b7fa60..9e1805d 100644
--- a/third_party/blink/renderer/core/page/chrome_client_impl.h
+++ b/third_party/blink/renderer/core/page/chrome_client_impl.h
@@ -282,7 +282,7 @@
                                         bool request) override;
 
   void DidUpdateTextAutosizerPageInfo(
-      const WebTextAutosizerPageInfo& page_info) override;
+      const mojom::blink::TextAutosizerPageInfo& page_info) override;
 
   int GetLayerTreeId(LocalFrame& frame) override;
 
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h
index db26b9ca..4671cf99 100644
--- a/third_party/blink/renderer/core/page/page.h
+++ b/third_party/blink/renderer/core/page/page.h
@@ -27,9 +27,9 @@
 
 #include "base/macros.h"
 #include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
 #include "third_party/blink/public/mojom/page/page_visibility_state.mojom-blink.h"
 #include "third_party/blink/public/platform/scheduler/web_scoped_virtual_time_pauser.h"
-#include "third_party/blink/public/platform/web_text_autosizer_page_info.h"
 #include "third_party/blink/public/web/web_window_features.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/vision_deficiency.h"
@@ -328,10 +328,11 @@
   void SetInsidePortal(bool inside_portal);
   bool InsidePortal() const;
 
-  void SetTextAutosizerPageInfo(const WebTextAutosizerPageInfo& page_info) {
+  void SetTextAutosizerPageInfo(
+      const mojom::blink::TextAutosizerPageInfo& page_info) {
     web_text_autosizer_page_info_ = page_info;
   }
-  const WebTextAutosizerPageInfo& TextAutosizerPageInfo() const {
+  const mojom::blink::TextAutosizerPageInfo& TextAutosizerPageInfo() const {
     return web_text_autosizer_page_info_;
   }
 
@@ -472,7 +473,7 @@
   // Accessed by frames to determine whether to expose the PortalHost object.
   bool inside_portal_ = false;
 
-  WebTextAutosizerPageInfo web_text_autosizer_page_info_;
+  mojom::blink::TextAutosizerPageInfo web_text_autosizer_page_info_;
 
   WebScopedVirtualTimePauser history_navigation_virtual_time_pauser_;
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 0ed180f4..00858ff3 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -3465,7 +3465,6 @@
 }
 
 void PaintLayer::MarkCompositingContainerChainForNeedsRepaint() {
-
   PaintLayer* layer = this;
   while (true) {
     if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
@@ -3499,8 +3498,16 @@
       container = owner->EnclosingLayer();
     }
 
-    if (container->descendant_needs_repaint_)
+    // If the container already needs descendants repaint, break out of the
+    // loop. Also, if the layer doesn't need painting itself (which means we're
+    // propagating a bit from its children) and it blocks child painting via
+    // display lock, then stop propagating the dirty bit.
+    if (container->descendant_needs_repaint_ ||
+        (!layer->SelfNeedsRepaint() &&
+         layer->GetLayoutObject().PaintBlockedByDisplayLock(
+             DisplayLockLifecycleTarget::kChildren))) {
       break;
+    }
 
     container->descendant_needs_repaint_ = true;
     layer = container;
@@ -3508,9 +3515,16 @@
 }
 
 void PaintLayer::ClearNeedsRepaintRecursively() {
+  self_needs_repaint_ = false;
+
+  // Don't clear dirty bits in a display-locked subtree.
+  if (GetLayoutObject().PaintBlockedByDisplayLock(
+          DisplayLockLifecycleTarget::kChildren)) {
+    return;
+  }
+
   for (PaintLayer* child = FirstChild(); child; child = child->NextSibling())
     child->ClearNeedsRepaintRecursively();
-  self_needs_repaint_ = false;
   descendant_needs_repaint_ = false;
 }
 
diff --git a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
index 1841b5d..1936c03 100644
--- a/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
+++ b/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc
@@ -80,7 +80,7 @@
   uint64_t hash = GetHashForFontData(resulting_font_data);
   LocalFontLookupKey key(name, font_description.GetFontSelectionRequest());
   LocalFontLookupResult result{hash, check_type, is_loading_fallback};
-  font_lookups.insert(key, result);
+  font_lookups_.insert(key, result);
 }
 
 void FontMatchingMetrics::ReportFontLookupByFallbackCharacter(
@@ -94,7 +94,7 @@
                          font_description.GetFontSelectionRequest());
   LocalFontLookupResult result{hash, check_type,
                                false /* is_loading_fallback */};
-  font_lookups.insert(key, result);
+  font_lookups_.insert(key, result);
 }
 
 void FontMatchingMetrics::ReportLastResortFallbackFontLookup(
@@ -106,7 +106,7 @@
   LocalFontLookupKey key(font_description.GetFontSelectionRequest());
   LocalFontLookupResult result{hash, check_type,
                                false /* is_loading_fallback */};
-  font_lookups.insert(key, result);
+  font_lookups_.insert(key, result);
 }
 
 void FontMatchingMetrics::ReportFontFamilyLookupByGenericFamily(
@@ -117,11 +117,11 @@
   OnFontLookup();
   GenericFontLookupKey key(generic_font_family_name, script,
                            generic_family_type);
-  generic_font_lookups.insert(key, resulting_font_name);
+  generic_font_lookups_.insert(key, resulting_font_name);
 }
 
 void FontMatchingMetrics::PublishIdentifiabilityMetrics() {
-  for (const auto& entry : font_lookups) {
+  for (const auto& entry : font_lookups_) {
     const LocalFontLookupKey& key = entry.key;
     const LocalFontLookupResult& result = entry.value;
 
@@ -138,9 +138,9 @@
              output_digest)
         .Record(ukm_recorder_);
   }
-  font_lookups.clear();
+  font_lookups_.clear();
 
-  for (const auto& entry : generic_font_lookups) {
+  for (const auto& entry : generic_font_lookups_) {
     const GenericFontLookupKey& key = entry.key;
     const AtomicString& result = entry.value;
 
@@ -157,7 +157,7 @@
              output_digest)
         .Record(ukm_recorder_);
   }
-  generic_font_lookups.clear();
+  generic_font_lookups_.clear();
 }
 
 void FontMatchingMetrics::PublishUkmMetrics() {
@@ -184,15 +184,15 @@
 }
 
 void FontMatchingMetrics::OnFontLookup() {
-  if (!time_of_earliest_unpublished_font_lookup) {
-    time_of_earliest_unpublished_font_lookup = base::Time::Now();
+  if (!time_of_earliest_unpublished_font_lookup_) {
+    time_of_earliest_unpublished_font_lookup_ = base::Time::Now();
     return;
   }
 
-  if (base::Time::Now() - *time_of_earliest_unpublished_font_lookup >=
+  if (base::Time::Now() - *time_of_earliest_unpublished_font_lookup_ >=
       base::TimeDelta::FromMinutes(1)) {
     PublishIdentifiabilityMetrics();
-    time_of_earliest_unpublished_font_lookup = base::Time::Now();
+    time_of_earliest_unpublished_font_lookup_ = base::Time::Now();
   }
 }
 
diff --git a/third_party/blink/renderer/platform/fonts/font_matching_metrics.h b/third_party/blink/renderer/platform/fonts/font_matching_metrics.h
index 55352fff..eab3ae0a 100644
--- a/third_party/blink/renderer/platform/fonts/font_matching_metrics.h
+++ b/third_party/blink/renderer/platform/fonts/font_matching_metrics.h
@@ -271,19 +271,19 @@
           LocalFontLookupResult,
           LocalFontLookupKeyHash,
           LocalFontLookupKeyHashTraits>
-      font_lookups;
+      font_lookups_;
   HashMap<GenericFontLookupKey,
           AtomicString,
           GenericFontLookupKeyHash,
           GenericFontLookupKeyHashTraits>
-      generic_font_lookups;
+      generic_font_lookups_;
 
   ukm::UkmRecorder* const ukm_recorder_;
   const ukm::SourceId source_id_;
 
   // Records when the first font lookup occurred since the last call to
   // PublishIdentifiablityMetrics(), if any.
-  base::Optional<base::Time> time_of_earliest_unpublished_font_lookup;
+  base::Optional<base::Time> time_of_earliest_unpublished_font_lookup_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/heap.cc b/third_party/blink/renderer/platform/heap/heap.cc
index aba11a5c..43c0f24 100644
--- a/third_party/blink/renderer/platform/heap/heap.cc
+++ b/third_party/blink/renderer/platform/heap/heap.cc
@@ -390,6 +390,15 @@
 
       {
         ThreadHeapStatsCollector::EnabledScope inner_scope(
+            stats_collector(),
+            ThreadHeapStatsCollector::kMarkFlushV8References);
+        finished = FlushV8References(deadline);
+        if (!finished)
+          break;
+      }
+
+      {
+        ThreadHeapStatsCollector::EnabledScope inner_scope(
             stats_collector(), ThreadHeapStatsCollector::kMarkBailOutObjects);
         // Items in the bailout worklist are only collection backing stores.
         // These items could take a long time to process, so we should check
@@ -410,15 +419,6 @@
       {
         ThreadHeapStatsCollector::EnabledScope inner_scope(
             stats_collector(),
-            ThreadHeapStatsCollector::kMarkFlushV8References);
-        finished = FlushV8References(deadline);
-        if (!finished)
-          break;
-      }
-
-      {
-        ThreadHeapStatsCollector::EnabledScope inner_scope(
-            stats_collector(),
             ThreadHeapStatsCollector::kMarkProcessNotFullyconstructeddWorklist);
         // Convert |previously_not_fully_constructed_worklist_| to
         // |marking_worklist_|. This merely re-adds items with the proper
diff --git a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h b/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h
index 188c79e..1c5a72f 100644
--- a/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h
+++ b/third_party/blink/renderer/platform/heap/marking_scheduling_oracle.h
@@ -19,7 +19,7 @@
   // Duration of one incremental marking step. Should be short enough that it
   // doesn't cause jank even though it is scheduled as a normal task.
   static constexpr base::TimeDelta kDefaultIncrementalMarkingStepDuration =
-      base::TimeDelta::FromMillisecondsD(0.5);
+      base::TimeDelta::FromMillisecondsD(0.1);
 
   // Minimum number of bytes that should be marked during an incremental
   // marking step.
diff --git a/third_party/blink/tools/blinkpy/third_party/README.chromium b/third_party/blink/tools/blinkpy/third_party/README.chromium
index e9e094e..7fb0a39 100644
--- a/third_party/blink/tools/blinkpy/third_party/README.chromium
+++ b/third_party/blink/tools/blinkpy/third_party/README.chromium
@@ -22,7 +22,7 @@
 Name: web-platform-tests - Test Suites for Web Platform specifications
 Short Name: wpt
 URL: https://github.com/web-platform-tests/wpt/
-Version: 22901727d52297378d44b217af0b4c06d5b0a484
+Version: 6a5c1eb4f386da68adc77c84ac3f6e3fa1cb3033
 License: LICENSES FOR W3C TEST SUITES (https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html)
 License File: wpt/wpt/LICENSE.md
 Security Critical: no
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
index 21065b4..7604e4b8 100755
--- a/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/checkout.sh
@@ -9,7 +9,7 @@
 
 TARGET_DIR=$DIR/wpt
 REMOTE_REPO="https://github.com/web-platform-tests/wpt.git"
-WPT_HEAD=22901727d52297378d44b217af0b4c06d5b0a484
+WPT_HEAD=6a5c1eb4f386da68adc77c84ac3f6e3fa1cb3033
 
 function clone {
   # Remove existing repo if already exists.
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
index 85c8bf3..8a1149c 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/lint.py
@@ -898,7 +898,9 @@
                         help="The WPT directory. Use this "
                         "option if the lint script exists outside the repository")
     parser.add_argument("--ignore-glob", type=ensure_text, action="append",
-                        help="Additional file glob to ignore (repeat to add more)")
+                        help="Additional file glob to ignore (repeat to add more). "
+                        "Globs are matched against paths relative to REPO_ROOT "
+                        "using fnmatch, except that path separators are normalized.")
     parser.add_argument("--all", action="store_true", help="If no paths are passed, try to lint the whole "
                         "working directory, not just files that changed")
     return parser
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/rules.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/rules.py
index cf512f0..1bf78b7b 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/rules.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/lint/rules.py
@@ -420,6 +420,11 @@
     pattern = br"web\-platform\.test"
     name = "WEB-PLATFORM.TEST"
     description = "Internal web-platform.test domain used"
+    to_fix = """
+        use [server-side substitution](https://web-platform-tests.org/writing-tests/server-pipes.html#sub),
+        along with the [`.sub` filename-flag](https://web-platform-tests.org/writing-tests/file-names.html#test-features),
+        to replace web-platform.test with `{{domains[]}}`
+    """
 
 
 class Webidl2Regexp(Regexp):
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
index bde22b4..6abe151 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/browser.py
@@ -558,7 +558,7 @@
         with open(installer_path, "rb") as f:
             unzip(f, dest)
         os.remove(installer_path)
-        return self.find_nightly_binary(dest, channel)
+        return self.find_nightly_binary(dest)
 
     def install_mojojs(self, dest):
         url = self._latest_chromium_snapshot_url() + "mojojs.zip"
@@ -603,10 +603,12 @@
             self._last_change = get(revision_url).text.strip()
         return "https://storage.googleapis.com/chromium-browser-snapshots/%s/%s/" % (architecture, self._last_change)
 
-    def find_nightly_binary(self, dest, channel):
-        binary = "Chromium" if uname[0] == "Darwin" else "chrome"
+    def find_nightly_binary(self, dest):
+        if uname[0] == "Darwin":
+            return find_executable("Chromium",
+                                   os.path.join(dest, self._chromium_package_name(), "Chromium.app", "Contents", "MacOS"))
         # find_executable will add .exe on Windows automatically.
-        return find_executable(binary, os.path.join(dest, self._chromium_package_name()))
+        return find_executable("chrome", os.path.join(dest, self._chromium_package_name()))
 
     def find_binary(self, venv_path=None, channel=None):
         if channel == "nightly":
@@ -680,13 +682,21 @@
             else self._chromium_chromedriver_url(None)
         self.logger.info("Downloading ChromeDriver from %s" % url)
         unzip(get(url).raw, dest)
+
+        # The two sources of ChromeDriver have different zip structures:
+        # * Chromium archives the binary inside a chromedriver_* directory;
+        # * Chrome archives the binary directly.
+        # We want to make sure the binary always ends up directly in bin/.
         chromedriver_dir = os.path.join(
             dest, 'chromedriver_%s' % self._chromedriver_platform_string())
-        unzipped_path = find_executable("chromedriver", chromedriver_dir)
-        assert unzipped_path is not None
-        shutil.move(unzipped_path, dest)
-        rmtree(chromedriver_dir)
-        return find_executable("chromedriver", dest)
+        binary_path = find_executable("chromedriver", chromedriver_dir)
+        if binary_path is not None:
+            shutil.move(binary_path, dest)
+            rmtree(chromedriver_dir)
+
+        binary_path = find_executable("chromedriver", dest)
+        assert binary_path is not None
+        return binary_path
 
     def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         if channel == "nightly":
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/utils.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/utils.py
index 6608af7..6556ff48 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/utils.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wpt/utils.py
@@ -107,7 +107,7 @@
     #    hasn't been fully released (a common issue).
     def handle_remove_readonly(func, path, exc):
         excvalue = exc[1]
-        if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
+        if func in (os.rmdir, os.remove, os.unlink) and excvalue.errno == errno.EACCES:
             os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  # 0777
             func(path)
         else:
diff --git a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/response.py b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/response.py
index 895f174..b7bfcebd 100644
--- a/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/response.py
+++ b/third_party/blink/tools/blinkpy/third_party/wpt/wpt/tools/wptserve/wptserve/response.py
@@ -742,7 +742,7 @@
         if not self._headers_complete:
             self._response.content = data
             self.end_headers()
-        self.write_raw_content(data)
+        return self.write_raw_content(data)
 
     def write_raw_content(self, data):
         """Writes the data 'as is'"""
@@ -750,11 +750,9 @@
             raise ValueError('data cannot be None')
         if isinstance(data, (text_type, binary_type)):
             # Deliberately allows both text and binary types. See `self.encode`.
-            self.write(data)
+            return self.write(data)
         else:
-            self.write_content_file(data)
-        if not self._response.explicit_flush:
-            self.flush()
+            return self.write_content_file(data)
 
     def write(self, data):
         """Write directly to the response, converting unicode to bytes
@@ -771,15 +769,19 @@
         """Write a file-like object directly to the response in chunks.
         Does not flush."""
         self.content_written = True
+        success = True
         while True:
             buf = data.read(self.file_chunk_size)
             if not buf:
+                success = False
                 break
             try:
                 self._wfile.write(buf)
             except socket.error:
+                success = False
                 break
         data.close()
+        return success
 
     def encode(self, data):
         """Convert unicode to bytes according to response.encoding."""
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index f98abce..6147891 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -823,10 +823,6 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-vert-006.xhtml [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-wmvert-001.xhtml [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001.html [ Failure ]
-crbug.com/715718 [ Win ] external/wpt/css/css-flexbox/align-items-004.htm [ Failure Pass ]
-crbug.com/715718 [ Win ] external/wpt/css/css-flexbox/flex-minimum-width-flex-items-001.xht [ Failure Pass ]
-crbug.com/715718 [ Win ] external/wpt/css/css-flexbox/flex-minimum-width-flex-items-003.xht [ Failure Pass ]
-crbug.com/715718 [ Win ] external/wpt/css/css-flexbox/flexbox_flex-natural-mixed-basis-auto.html [ Failure Pass ]
 crbug.com/898186 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-intrinsic-ratio-003v.html [ Pass Failure ]
 
 # [css-lists]
@@ -6858,3 +6854,5 @@
 
 # Sheriff 2020-08-05
 crbug.com/1113050 fast/borders/border-radius-mask-video-ratio.html [ Pass Failure ]
+crbug.com/1113127 fast/canvas/downsample-quality.html [ Pass Failure ]
+crbug.com/1112111 [ Mac ] fast/forms/month/month-picker-appearance-step.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index 84cedfd..a77395a 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -78010,6 +78010,19 @@
        {}
       ]
      ],
+     "paint-function-this-value.https.html": [
+      "216913899a931e8144d8a647eccb8ba01037f737",
+      [
+       null,
+       [
+        [
+         "/css/css-paint-api/parse-input-arguments-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "paint2d-composite.https.html": [
       "d654ba49aad6048f88e6ddb6750554dc22b860fb",
       [
@@ -206802,7 +206815,7 @@
         []
        ],
        "reporting-observer-expected.txt": [
-        "9dadb68281f098f2a90ab44949b27269ee8d7182",
+        "036442d62fd4c61e406e6cc43b083c868614c793",
         []
        ]
       },
@@ -206866,7 +206879,7 @@
         []
        ],
        "dispatcher.py": [
-        "2617361b0b369bd9efd3aedd42a88f8f46906fe3",
+        "e77583e479f9506b3f6a5b53293ae25dc3cae8f1",
         []
        ],
        "executor.html": [
@@ -214638,8 +214651,8 @@
         ],
         "dynamic-import": {
          "alpha": {
-          "base-url-worker.sub-expected.txt": [
-           "d6fa4d1f1ddd7d400080e6375a553663dffbbb9d",
+          "base-url-worker-importScripts-expected.txt": [
+           "8134ddf6e455f6360990c8df4d9a78fe631792a5",
            []
           ],
           "base-url.sub-expected.txt": [
@@ -220896,7 +220909,7 @@
       []
      ],
      "child-frame-script.mjs": [
-      "2c6760a3e3707f06b5f3f904eec5e0aa21ec9586",
+      "783e36092daae6a3998a2701d110add2f55c3a0f",
       []
      ],
      "child-frame-script.mjs.headers": [
@@ -220904,7 +220917,7 @@
       []
      ],
      "helpers.mjs": [
-      "e8425c240b5e5821bc16708044863f73bf5f4697",
+      "73f9406b476bb4afa708d043fb8bb68e6618d946",
       []
      ],
      "helpers.mjs.headers": [
@@ -237882,12 +237895,6 @@
        "0bc5ce3b8dd6612b7af44007276819c9b1276e91",
        []
       ]
-     },
-     "the-periodicwave-interface": {
-      "periodicWave-expected.txt": [
-       "8d26f7ef4bb7d872adf059ec54ca05132487c261",
-       []
-      ]
      }
     }
    },
@@ -296010,6 +296017,13 @@
        {}
       ]
      ],
+     "MutationObserver-callback-arguments.html": [
+      "d64758cb4fa00d25ad3dafe576a0098c902922b7",
+      [
+       null,
+       {}
+      ]
+     ],
      "MutationObserver-characterData.html": [
       "addaef03da1ac64ce9e6a6b1c5d244933b2c7f7b",
       [
@@ -336754,10 +336768,12 @@
         ]
        ],
        "reporting-observer.html": [
-        "4d1eda941ae50ce4482c692dafe749ef9e455ac6",
+        "decad097b6d29acabb6252497f68658002c3478e",
         [
          null,
-         {}
+         {
+          "timeout": "long"
+         }
         ]
        ]
       },
@@ -348094,8 +348110,15 @@
         ],
         "dynamic-import": {
          "alpha": {
+          "base-url-worker-importScripts.html": [
+           "817cf6d5ddfdc186454de0e3a672a865e2ced416",
+           [
+            null,
+            {}
+           ]
+          ],
           "base-url-worker.sub.html": [
-           "ca4b005349e16db3c510ed6774e5d89f53c1a876",
+           "a12204281cc43e64c7f1f4f7cdaf37958567b516",
            [
             null,
             {}
@@ -354939,6 +354962,13 @@
       {}
      ]
     ],
+    "observer-callback-arguments.html": [
+     "6e816969d00641af4da1c86d7b7bafc4a3ffbc3b",
+     [
+      null,
+      {}
+     ]
+    ],
     "observer-exceptions.html": [
      "126790f290d9480dcda7eed6e1b2989ffcc6a70f",
      [
@@ -355492,7 +355522,7 @@
      ]
     ],
     "invisible-images-composited-1.html": [
-     "495645ab41eccb80464a2ceb7de83a2136ecfbf7",
+     "7723d2f2bea5b622395e09ae1bd7fd4bb6cf87bc",
      [
       null,
       {}
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/report-frame-ancestors-with-x-frame-options.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/report-frame-ancestors-with-x-frame-options.sub.html
new file mode 100644
index 0000000..0c58a5e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/report-frame-ancestors-with-x-frame-options.sub.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <title>Reporting works with report-only frame-ancestors even if frame is blocked by X-Frame-Options</title>
+</head>
+<body>
+    <iframe src="./support/not-embeddable-frame.py?reportID={{$id:uuid()}}&reportOnly=true&xFrameOptions=DENY"></iframe>
+    <script async defer src='../support/checkReport.sub.js?reportField=violated-directive&reportValue=frame-ancestors&reportID={{$id}}'></script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/report-frame-ancestors.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/report-frame-ancestors.sub.html
index a5aa166..cd7bbcb 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/report-frame-ancestors.sub.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/report-frame-ancestors.sub.html
@@ -6,7 +6,7 @@
     <title>Reporting works with frame-ancestors</title>
 </head>
 <body>
-    <iframe src="./support/not-embeddable-frame.html?reportID={{$id:uuid()}}"></iframe>
+    <iframe src="./support/not-embeddable-frame.py?reportID={{$id:uuid()}}"></iframe>
     <script async defer src='../support/checkReport.sub.js?reportField=violated-directive&reportValue=frame-ancestors&reportID={{$id}}'></script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/support/not-embeddable-frame.html b/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/support/not-embeddable-frame.html
deleted file mode 100644
index e69de29..0000000
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/support/not-embeddable-frame.html
+++ /dev/null
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/support/not-embeddable-frame.html.sub.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/support/not-embeddable-frame.html.sub.headers
deleted file mode 100644
index beecdb76..0000000
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/support/not-embeddable-frame.html.sub.headers
+++ /dev/null
@@ -1,5 +0,0 @@
-Expires: Mon, 26 Jul 1997 05:00:00 GMT
-Cache-Control: no-store, no-cache, must-revalidate
-Cache-Control: post-check=0, pre-check=0, false
-Pragma: no-cache
-Content-Security-Policy: frame-ancestors 'none'; report-uri ../../support/report.py?op=put&reportID={{GET[reportID]}}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/support/not-embeddable-frame.py b/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/support/not-embeddable-frame.py
new file mode 100644
index 0000000..50f9c83
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/reporting/support/not-embeddable-frame.py
@@ -0,0 +1,10 @@
+def main(request, response):
+    headers = []
+    if request.GET.first(b'xFrameOptions', None):
+        headers.append((b'X-Frame-Options', request.GET[b'xFrameOptions']))
+
+    csp_header = b'Content-Security-Policy-Report-Only' \
+        if request.GET.first(b'reportOnly', None) == 'true' else b'Content-Security-Policy'
+    headers.append((csp_header, b"frame-ancestors 'none'; report-uri ../../support/report.py?op=put&reportID=" + request.GET[b'reportID']))
+
+    return headers, b'{}'
diff --git a/third_party/blink/web_tests/external/wpt/css/css-paint-api/paint-function-this-value.https.html b/third_party/blink/web_tests/external/wpt/css/css-paint-api/paint-function-this-value.https.html
new file mode 100644
index 0000000..2169138
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-paint-api/paint-function-this-value.https.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Paint callback is invoked with `this` value of `paintInstance`</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-paint-api-1/#invoke-a-paint-callback">
+<link rel="match" href="parse-input-arguments-ref.html">
+<style>
+.container {
+  width: 100px;
+  height: 100px;
+}
+
+#canvas-geometry {
+  background-image: paint(geometry);
+}
+</style>
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/worklet-reftest.js"></script>
+<body>
+<div id="canvas-geometry" class="container"></div>
+
+<script id="code" type="text/worklet">
+let paintInstance;
+
+registerPaint('geometry', class {
+    constructor() {
+        paintInstance = this;
+    }
+    paint(ctx, geom) {
+        if (this === paintInstance)
+            ctx.fillStyle = 'green';
+        else
+            ctx.fillStyle = 'red';
+        ctx.fillRect(0, 0, geom.width, geom.height);
+    }
+});
+</script>
+
+<script>
+    importWorkletAndTerminateTestAfterAsyncPaint(CSS.paintWorklet, document.getElementById('code').textContent);
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/MutationObserver-callback-arguments.html b/third_party/blink/web_tests/external/wpt/dom/nodes/MutationObserver-callback-arguments.html
new file mode 100644
index 0000000..d64758c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/MutationObserver-callback-arguments.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>MutationObserver: callback arguments</title>
+<link rel="help" href="https://dom.spec.whatwg.org/#notify-mutation-observers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="mo-target"></div>
+<div id="log"></div>
+<script>
+"use strict";
+
+async_test(t => {
+  const moTarget = document.querySelector("#mo-target");
+  const mo = new MutationObserver(function(records, observer) {
+    t.step(() => {
+      assert_equals(this, mo);
+      assert_equals(arguments.length, 2);
+      assert_true(Array.isArray(records));
+      assert_equals(records.length, 1);
+      assert_true(records[0] instanceof MutationRecord);
+      assert_equals(observer, mo);
+
+      mo.disconnect();
+      t.done();
+    });
+  });
+
+  mo.observe(moTarget, {attributes: true});
+  moTarget.className = "trigger-mutation";
+}, "Callback is invoked with |this| value of MutationObserver and two arguments");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/observer-callback-arguments.html b/third_party/blink/web_tests/external/wpt/intersection-observer/observer-callback-arguments.html
new file mode 100644
index 0000000..6e81696
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/intersection-observer/observer-callback-arguments.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>IntersectionObserver: callback arguments</title>
+<link rel="help" href="https://w3c.github.io/IntersectionObserver/#notify-intersection-observers-algo">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+"use strict";
+
+async_test(t => {
+  const io = new IntersectionObserver(function(entries, observer) {
+    t.step(() => {
+      assert_equals(this, io);
+      assert_equals(arguments.length, 2);
+      assert_true(Array.isArray(entries));
+      assert_equals(entries.length, 1);
+      assert_true(entries[0] instanceof IntersectionObserverEntry);
+      assert_equals(observer, io);
+
+      io.disconnect();
+      t.done();
+    });
+  });
+
+  io.observe(document.body);
+}, "Callback is invoked with |this| value of IntersectionObserver and two arguments");
+</script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/resources/coop.php b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/coop.php
new file mode 100644
index 0000000..2a070e7
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/resources/coop.php
@@ -0,0 +1,3 @@
+<?php
+header('Cross-Origin-Opener-Policy: same-origin');
+echo 'Some content';
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/target/get-target-info-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/target/get-target-info-expected.txt
index 95a750f7..bffea19 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/target/get-target-info-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/target/get-target-info-expected.txt
@@ -2,6 +2,7 @@
 {
     attached : true
     browserContextId : <string>
+    canAccessOpener : false
     targetId : <string>
     title : 127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html
     type : page
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/target/target-setAutoAttach-about-blank-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/target/target-setAutoAttach-about-blank-expected.txt
index 0ff6972..febf93f 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/target/target-setAutoAttach-about-blank-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/target/target-setAutoAttach-about-blank-expected.txt
@@ -7,6 +7,7 @@
         targetInfo : {
             attached : true
             browserContextId : <string>
+            canAccessOpener : false
             targetId : <string>
             title : 
             type : page
@@ -22,6 +23,7 @@
         targetInfo : {
             attached : true
             browserContextId : <string>
+            canAccessOpener : false
             targetId : <string>
             title : about:blank#newpage
             type : page
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/target/target-setAutoAttach-new-page-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/target/target-setAutoAttach-new-page-expected.txt
index 9eb36d9..05c1dc3 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/target/target-setAutoAttach-new-page-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/target/target-setAutoAttach-new-page-expected.txt
@@ -6,6 +6,7 @@
         targetInfo : {
             attached : true
             browserContextId : <string>
+            canAccessOpener : false
             targetId : <string>
             title : 
             type : page
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/window-open-effective-opener-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/window-open-effective-opener-expected.txt
new file mode 100644
index 0000000..2ba4c8c
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/window-open-effective-opener-expected.txt
@@ -0,0 +1,68 @@
+Tests for correct opener in Page.TargetCreated and Page.TargetInfoChanged protocol method.
+
+Opening without new browsing context
+{
+    attached : false
+    browserContextId : <string>
+    canAccessOpener : true
+    openerId : <string>
+    targetId : <string>
+    title : 
+    type : page
+    url : 
+}
+{
+    attached : false
+    browserContextId : <string>
+    canAccessOpener : true
+    openerId : <string>
+    targetId : <string>
+    title : 127.0.0.1:8000/inspector-protocol/resources/resources/test-page.html
+    type : page
+    url : http://127.0.0.1:8000/inspector-protocol/resources/resources/test-page.html
+}
+
+Opening with new browsing context
+{
+    attached : false
+    browserContextId : <string>
+    canAccessOpener : false
+    openerId : <string>
+    targetId : <string>
+    title : 
+    type : page
+    url : 
+}
+{
+    attached : false
+    browserContextId : <string>
+    canAccessOpener : false
+    openerId : <string>
+    targetId : <string>
+    title : 127.0.0.1:8000/inspector-protocol/resources/resources/test-page.html
+    type : page
+    url : http://127.0.0.1:8000/inspector-protocol/resources/resources/test-page.html
+}
+
+Opening with COOP header
+{
+    attached : false
+    browserContextId : <string>
+    canAccessOpener : true
+    openerId : <string>
+    targetId : <string>
+    title : 
+    type : page
+    url : 
+}
+{
+    attached : false
+    browserContextId : <string>
+    canAccessOpener : false
+    openerId : <string>
+    targetId : <string>
+    title : https://127.0.0.1:8443/inspector-protocol/resources/resources/test-page.html
+    type : page
+    url : https://127.0.0.1:8443/inspector-protocol/resources/resources/test-page.html
+}
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/window-open-effective-opener.js b/third_party/blink/web_tests/http/tests/inspector-protocol/window-open-effective-opener.js
new file mode 100644
index 0000000..5e6d675
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/window-open-effective-opener.js
@@ -0,0 +1,29 @@
+(async function(testRunner) {
+    var {page, session, dp} = await testRunner.startBlank('Tests for correct opener in Page.TargetCreated and Page.TargetInfoChanged protocol method.');
+    await dp.Target.setDiscoverTargets({discover: true});
+    await dp.Page.enable();
+
+    testRunner.log(`\nOpening without new browsing context`);
+    session.evaluate(`window.open('./resources/test-page.html', '_blank'); undefined`);
+    var response = await dp.Target.onceTargetCreated();
+    testRunner.log(response.params.targetInfo);
+    response = await dp.Target.onceTargetInfoChanged();
+    testRunner.log(response.params.targetInfo);
+
+    testRunner.log(`\nOpening with new browsing context`);
+    session.evaluate(`window.open('./resources/test-page.html', '_blank', 'noopener'); undefined`);
+    response = await dp.Target.onceTargetCreated();
+    testRunner.log(response.params.targetInfo);
+    response = await dp.Target.onceTargetInfoChanged();
+    testRunner.log(response.params.targetInfo);
+
+    testRunner.log(`\nOpening with COOP header`);
+    await dp.Page.navigate({ url: testRunner.url('https://127.0.0.1:8443/inspector-protocol/resources/coop.php')});
+    session.evaluate(`window.open('./resources/test-page.html', '_blank'); undefined`);
+    response = await dp.Target.onceTargetCreated();
+    testRunner.log(response.params.targetInfo);
+    var response = await dp.Target.onceTargetInfoChanged();
+    testRunner.log(response.params.targetInfo);
+
+    testRunner.completeTest();
+  })
\ No newline at end of file
diff --git a/third_party/blink/web_tests/platform/mac-retina/fast/forms/month/month-picker-appearance-step-expected.png b/third_party/blink/web_tests/platform/mac-retina/fast/forms/month/month-picker-appearance-step-expected.png
deleted file mode 100644
index cc91228..0000000
--- a/third_party/blink/web_tests/platform/mac-retina/fast/forms/month/month-picker-appearance-step-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 04de172..3dd26ca 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-10-2-49-g8b3601324
-Revision: 8b3601324fde1ba49338dd6279057cd366c25919
+Version: VER-2-10-2-51-gf9f6adb62
+Revision: f9f6adb625c48ef15b5d61a3ac1709a068ea95a3
 CPEPrefix: cpe:/a:freetype:freetype:2.10.1
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/sqlite/PRESUBMIT.py b/third_party/sqlite/PRESUBMIT.py
index 950e536e..4f6897a 100644
--- a/third_party/sqlite/PRESUBMIT.py
+++ b/third_party/sqlite/PRESUBMIT.py
@@ -16,7 +16,7 @@
             input_api,
             output_api,
             input_api.os_path.join(this_dir, 'scripts'),
-            whitelist=['.*unittest.py$'],
+            files_to_check=['.*unittest.py$'],
             env=None,
             run_on_python2=False,
             run_on_python3=True))
diff --git a/tools/android/dependency_analysis/PRESUBMIT.py b/tools/android/dependency_analysis/PRESUBMIT.py
index 87ac8ff4..b03773f 100644
--- a/tools/android/dependency_analysis/PRESUBMIT.py
+++ b/tools/android/dependency_analysis/PRESUBMIT.py
@@ -13,8 +13,8 @@
         input_api,
         output_api,
         input_api.PresubmitLocalPath(),
-        whitelist=[r'.+_unittest\.py$'],
-        blacklist=[],
+        files_to_check=[r'.+_unittest\.py$'],
+        files_to_skip=[],
         run_on_python2=False,
         run_on_python3=True)
 
diff --git a/tools/binary_size/PRESUBMIT.py b/tools/binary_size/PRESUBMIT.py
index 75b266a..b7c4a8d 100644
--- a/tools/binary_size/PRESUBMIT.py
+++ b/tools/binary_size/PRESUBMIT.py
@@ -15,8 +15,8 @@
       input_api,
       output_api,
       input_api.PresubmitLocalPath(),
-      whitelist=[r'.+_test\.py$'],
-      blacklist=[],
+      files_to_check=[r'.+_test\.py$'],
+      files_to_skip=[],
       run_on_python2=False,
       run_on_python3=True)
 
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py
index 6d2e85d..ef3b0cb 100755
--- a/tools/clang/scripts/build.py
+++ b/tools/clang/scripts/build.py
@@ -336,6 +336,26 @@
     sys.exit(1)
 
 
+def VerifyZlibSupport():
+  """Check that clang was built with zlib support enabled."""
+  clang = os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')
+  test_file = '/dev/null'
+  if sys.platform == 'win32':
+    clang += '-cl.exe'
+    test_file = 'nul'
+
+  print('Checking for zlib support')
+  clang_out = subprocess.check_output([
+      clang, '--driver-mode=gcc', '-target', 'x86_64-unknown-linux-gnu', '-gz',
+      '-c', '-###', '-x', 'c', test_file ],
+      stderr=subprocess.STDOUT, universal_newlines=True)
+  if (re.search(r'--compress-debug-sections', clang_out)):
+    print('OK')
+  else:
+    print(('Failed to detect zlib support!\n\n(driver output: %s)') % clang_out)
+    sys.exit(1)
+
+
 def CopyLibstdcpp(args, build_dir):
   if not args.gcc_toolchain:
     return
@@ -878,6 +898,7 @@
     RunCommand(['ninja', 'cr-install'], msvc_arch='x64')
 
   VerifyVersionOfBuiltClangMatchesVERSION()
+  VerifyZlibSupport()
 
   if sys.platform == 'win32':
     platform = 'windows'
diff --git a/tools/infra/PRESUBMIT.py b/tools/infra/PRESUBMIT.py
index 77e4c07..3352aa2 100644
--- a/tools/infra/PRESUBMIT.py
+++ b/tools/infra/PRESUBMIT.py
@@ -14,10 +14,13 @@
   results.extend(input_api.canned_checks.RunPylint(input_api, output_api))
 
   commands = []
-  commands.extend(input_api.canned_checks.GetUnitTestsRecursively(
-      input_api, output_api,
-      input_api.os_path.join(input_api.PresubmitLocalPath()),
-      whitelist=[r'.+_unittest\.py$'], blacklist=[]))
+  commands.extend(
+      input_api.canned_checks.GetUnitTestsRecursively(
+          input_api,
+          output_api,
+          input_api.os_path.join(input_api.PresubmitLocalPath()),
+          files_to_check=[r'.+_unittest\.py$'],
+          files_to_skip=[]))
   results.extend(input_api.RunTests(commands))
 
   return results
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 1bb02656..7e6cef7 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -135,7 +135,6 @@
       'linux-chromeos-rel': 'chromeos_with_codecs_release_bot',
       'linux-chromeos-dbg': 'chromeos_with_codecs_debug_bot',
       'linux-lacros-builder-rel': 'lacros_on_linux_release_bot',
-      'linux-lacros-compile-rel': 'lacros_on_linux_release_bot',
       'linux-lacros-tester-rel': 'lacros_on_linux_release_bot',
     },
 
@@ -828,6 +827,7 @@
       'linux-chromeos-rel': 'chromeos_with_codecs_release_trybot_code_coverage',
       'linux-chromeos-compile-dbg': 'chromeos_with_codecs_debug_bot',
       'linux-chromeos-dbg': 'chromeos_with_codecs_debug_bot',
+      'linux-lacros-compile-rel': 'lacros_on_linux_release_bot',
     },
 
     'tryserver.chromium.codesearch': {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 0967d30..b4c4442 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -897,6 +897,7 @@
   <int value="4" label="'Manage all addresses' link"/>
   <int value="5" label="Manual password generation"/>
   <int value="6" label="Save passwords toggle"/>
+  <int value="7" label="'Show other passwords' link"/>
 </enum>
 
 <enum name="AccessoryBarContents">
@@ -28633,6 +28634,9 @@
   <int value="3362" label="HtmlClipboardApiRead"/>
   <int value="3363" label="HtmlClipboardApiWrite"/>
   <int value="3364" label="CSSSystemColorComputeToSelf"/>
+  <int value="3365" label="ConversionAPIAll"/>
+  <int value="3366" label="ImpressionRegistration"/>
+  <int value="3367" label="ConversionRegistration"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
@@ -53403,6 +53407,8 @@
   <int value="1" label="Time change on login screen"/>
   <int value="2" label="Time change user session"/>
   <int value="3" label="Timezone change"/>
+  <int value="4" label="Add user"/>
+  <int value="5" label="Reauthentication"/>
 </enum>
 
 <enum name="ParentFrameKnown">
@@ -63167,6 +63173,7 @@
   <int value="32" label="BACKGROUND_FETCH_SUCCESS"/>
   <int value="33" label="PERIODIC_SYNC"/>
   <int value="34" label="CONTENT_DELETE"/>
+  <int value="35" label="PUSH_SUBSCRIPTION_CHANGE"/>
 </enum>
 
 <enum name="ServiceWorkerOfflineCapability">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b053341..66acb7f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -74546,7 +74546,7 @@
 </histogram>
 
 <histogram name="KeyboardAccessory.AccessoryActionImpression"
-    enum="AccessoryAction" expires_after="2020-12-06">
+    enum="AccessoryAction" expires_after="2021-01-17">
   <owner>fhorschig@chromium.org</owner>
   <summary>
     Android only. Records whenever users faces an action in the accessory bar or
@@ -74555,7 +74555,7 @@
 </histogram>
 
 <histogram name="KeyboardAccessory.AccessoryActionSelected"
-    enum="AccessoryAction" expires_after="2020-12-06">
+    enum="AccessoryAction" expires_after="2021-01-17">
   <owner>fhorschig@chromium.org</owner>
   <summary>
     Android only. Records whenever users select an action in the accessory bar
@@ -74564,7 +74564,7 @@
 </histogram>
 
 <histogram name="KeyboardAccessory.AccessoryBarShown"
-    enum="AccessoryBarContents" expires_after="2021-01-03">
+    enum="AccessoryBarContents" expires_after="2021-01-17">
   <owner>fhorschig@chromium.org</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -74575,7 +74575,7 @@
 </histogram>
 
 <histogram name="KeyboardAccessory.AccessorySheetSuggestionCount" units="count"
-    expires_after="2020-08-30">
+    expires_after="2021-01-17">
   <owner>fhorschig@chromium.org</owner>
   <summary>
     Android only. Records how many suggestions a user faced when opening a
@@ -158975,6 +158975,20 @@
   <summary>Execution time of ServiceWorkerGlobalScope.onpush.</summary>
 </histogram>
 
+<histogram name="ServiceWorker.PushSubscriptionChangeEvent.Time" units="ms"
+    expires_after="M88">
+  <owner>peter@chromium.org</owner>
+  <owner>rayankans@chromium.org</owner>
+  <owner>knollr@chromium.org</owner>
+  <owner>viviy@google.com</owner>
+  <summary>
+    The time taken between dispatching a PushSubscriptionChangeEvent to a
+    Service Worker and receiving a message that it finished handling the event.
+    Includes the time for the waitUntil() promise to settle. The event is
+    dispatched and finishes in PushMessagingRouter::FireSubscriptionChangeEvent.
+  </summary>
+</histogram>
+
 <histogram name="ServiceWorker.RegisteredOriginCount" units="origins"
     expires_after="2021-01-31">
   <owner>falken@chromium.org</owner>
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index dfe0cc9..a8683ca 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -298,6 +298,7 @@
             },
         ],
         'dimension': {
+            'cpu': 'x86',
             'os': 'Ubuntu-16.04',
             'pool': 'chrome.tests',
         },
@@ -352,6 +353,7 @@
             },
         ],
         'dimension': {
+            'cpu': 'x86',
             'os': 'Ubuntu-16.04',
             'pool': 'chrome.tests',
         },
diff --git a/tools/perf/core/perf_json_config_validator.py b/tools/perf/core/perf_json_config_validator.py
index b8c44fc..a42b1eb 100644
--- a/tools/perf/core/perf_json_config_validator.py
+++ b/tools/perf/core/perf_json_config_validator.py
@@ -11,8 +11,9 @@
 
 _VALID_SWARMING_DIMENSIONS = {
     'gpu', 'device_ids', 'os', 'pool', 'perf_tests', 'perf_tests_with_args',
-    'device_os', 'device_type', 'device_os_flavor', 'id',
-    'synthetic_product_name'}
+    'cpu', 'device_os', 'device_type', 'device_os_flavor', 'id',
+    'synthetic_product_name'
+}
 _DEFAULT_VALID_PERF_POOLS = {
     'chrome.tests.perf',
     'chrome.tests.perf-webview',
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index d69c429..d8d6f76 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,16 +1,16 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "d94d3898064c776de447e27514ca76bfdd3aacef",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/23c5b63d1c68730cf0a6bb2a904dbd67f288508c/trace_processor_shell.exe"
+            "hash": "6d781992e6c8844d3253126d7b2d447e6f2790bc",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/f68444a445f793554cc07f71aecaa8d4ed40b5a9/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "d51d9099a4c464ecc614f59d3f9ea33af095a91f",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/23c5b63d1c68730cf0a6bb2a904dbd67f288508c/trace_processor_shell"
+            "hash": "de0e599133740bd0c0c579d2a38e745c7085e112",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/9a43f48ed4cd22ec0f6e1436cd88b829a3b99550/trace_processor_shell"
         },
         "linux": {
             "hash": "3de97a08c91a58eed6aee36f74ae49808f8a3c69",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/23c5b63d1c68730cf0a6bb2a904dbd67f288508c/trace_processor_shell"
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/9a43f48ed4cd22ec0f6e1436cd88b829a3b99550/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/traffic_annotation/scripts/README.md b/tools/traffic_annotation/scripts/README.md
index 9b7ff77..5da7e3b 100644
--- a/tools/traffic_annotation/scripts/README.md
+++ b/tools/traffic_annotation/scripts/README.md
@@ -29,3 +29,25 @@
 
 # extractor_test.py
 Unit tests for extractor.py.
+
+# update_annotations_doc.py
+Updates the Chrome Browser Network Traffic Annotations document that presents
+all network traffic annotations specified within `summary/grouping.xml`.
+  - You can use the `hidden="true"` attribute within a group to suppress the
+    group and its nested senders and annotations from appearing in the document.
+  - You can use the `hidden="true"` attribute within the annotations in
+    `grouping.xml` to suppress them from appearing in the document.
+  - `grouping.xml` needn't be organized in alphabetical order, the script
+    automatically places them in alphabetical order.
+
+# update_annotations_doc_tests.py
+Unit tests for update_annotations_doc.py.
+
+# parser.py
+Parses the `grouping.xml` and `annotations.tsv` files to provide
+`update_annotations_doc.py` with the annotations and their relevant information,
+e.g. unique_id, data, trigger, etc. Also includes methods to parse the json
+object returned by the Google Docs API `get()` method.
+
+# parser_tests.py
+Unit tests for parser.py.
\ No newline at end of file
diff --git a/tools/traffic_annotation/scripts/parser.py b/tools/traffic_annotation/scripts/parser.py
new file mode 100755
index 0000000..bb428bf
--- /dev/null
+++ b/tools/traffic_annotation/scripts/parser.py
@@ -0,0 +1,350 @@
+#!/usr/bin/env vpython
+# 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.
+"""Contains the parsers for .tsv and .xml files, annotations.tsv and
+grouping.xml  respectively. Also includes methods to parse the json object
+returned by the Google Doc API's .get() method.
+
+These parsers are used to populate the duplicated Google Doc template with
+several placeholders, and, to populate the traffic annotations with their
+relevant attributes, e.g. description, policy, etc.
+"""
+
+from __future__ import print_function
+from collections import namedtuple
+from collections import OrderedDict
+import xml.etree.ElementTree
+import enum
+import json
+import csv
+import sys
+import io
+import re
+
+
+TrafficAnnotation = namedtuple(
+    "TrafficAnnotation",
+    ["unique_id", "description", "trigger", "data", "settings", "policy"])
+
+
+class Placeholder(str, enum.Enum):
+  GROUP = "group"
+  SENDER = "sender"
+  ANNOTATION = "annotation"
+  ANNOTATION_BOLD = "annotation_bold"
+
+PLACEHOLDER_STYLES = {
+    Placeholder.GROUP: {
+        "bold": False,
+        "font": "Roboto",
+        "fontSize": 20,
+        "namedStyleType": "HEADING_1"
+    },
+    Placeholder.SENDER: {
+        "bold": True,
+        "font": "Roboto",
+        "fontSize": 14,
+        "namedStyleType": "HEADING_2"
+    },
+    Placeholder.ANNOTATION: {
+        "bold": False,
+        "font": "Roboto",
+        "fontSize": 9
+    },
+    Placeholder.ANNOTATION_BOLD: {
+        "bold": True,
+        "font": "Roboto",
+        "fontSize": 9
+    }
+}
+
+
+def utf_8_encoder(input_file):
+  for line in input_file:
+    yield line.encode("utf-8")
+
+
+def load_tsv_file(file_path, verbose):
+  """ Loads annotations TSV file.
+
+  Args:
+    file_path: str
+      Path to the TSV file.
+    verbose: bool
+      Whether to print messages about ignored rows.
+
+  Returns:
+    list of list Table of loaded annotations.
+  """
+  rows = []
+  with io.open(file_path, mode="r", encoding="utf-8") as csvfile:
+    # CSV library does not support unicode, so encoding to utf-8 and back.
+    reader = csv.reader(utf_8_encoder(csvfile), delimiter="\t")
+    for row in reader:
+      row = [unicode(col, "utf-8") for col in row]
+      # If the last column of the file_row is empty, the row belongs to a
+      # platform different from the one that TSV file is generated on, hence it
+      # should be ignored.
+      if row[-1]:
+        rows.append(row)
+      elif verbose:
+        print("Ignored from other platforms: %s" % row[0])
+  return rows
+
+
+def map_annotations(tsv_contents):
+  """Creates a mapping between the unique_id of a given annotation and its
+  relevant attributes, e.g. description, trigger, data, etc.
+
+  Args:
+    tsv_contents: List[List]
+      Table of loaded annotations.
+
+  Returns:
+    unique_id_rel_attributes_map: <Dict[str, TrafficAnnotation]>
+  """
+  unique_id_rel_attributes_map = {}
+  for annotation_row in tsv_contents:
+    unique_id = annotation_row[0].encode("utf-8")
+    description = annotation_row[3].encode("utf-8")
+    trigger = annotation_row[4].encode("utf-8")
+    data = annotation_row[5].encode("utf-8")
+    settings = annotation_row[9].encode("utf-8")
+    policy = annotation_row[10].encode("utf-8")
+    payload = [unique_id, description, trigger, data, settings, policy]
+
+    unique_id_rel_attributes_map[unique_id] = TrafficAnnotation._make(payload)
+  return unique_id_rel_attributes_map
+
+
+class XMLParser:
+  """Parses grouping.xml with the aim of generating the placeholders list"""
+
+  def __init__(self, file_path, annotations_mapping):
+    """
+    Args:
+      file_path: str
+        The file path to the xml to parse. Ostensibly, grouping.xml located
+        within traffic_annotation/summary.
+      annotations_mapping: Dict[str, dict]
+          The mapping between a given annotation's unique_id and its relevant
+          attributes, e.g. description, policy, data, etc.
+    """
+    self.parsed_xml = {}
+    self.annotations_mapping = annotations_mapping
+
+    self.parse_xml(file_path)
+
+  def parse_xml(self, file_path):
+    """Parses the grouping.xml file and populates self.parsed_xml.
+
+    self.parsed_xml: <{Group1: {sender: [traffic_annotations]}, ...}>
+    """
+    tree = xml.etree.ElementTree.parse(file_path)
+    root = tree.getroot()
+    for group in root.iter("group"):
+      assert group.tag == "group"
+      group_name = group.attrib["name"]
+      # Suppress if hidden="true" in the group block. Will not include any of
+      # the senders and annotations in the block.
+      if group.attrib.get("hidden", "") == "true":
+        continue
+      self.parsed_xml[group_name] = {}
+
+      for sender in group.iter("sender"):
+        sender_name = sender.attrib["name"]
+        # Suppress if hidden="true" (or hidden is even mentioned) in the given
+        # annotation, don't include in traffic_annotations.
+        traffic_annotations = sorted([
+            t_annotation.attrib["unique_id"]
+            for t_annotation in sender.iter("traffic_annotation")
+            if t_annotation.attrib.get("hidden", "") != "true"
+        ])
+        self.parsed_xml[group_name][sender_name] = traffic_annotations
+
+  def _sort_parsed_xml(self):
+    """Sort on the group and sender keys in alphabetical order, note that
+    annotations are already sorted."""
+    self.parsed_xml = {
+        k: OrderedDict(sorted(v.items()))
+        for k, v in self.parsed_xml.items()
+    }
+    self.parsed_xml = OrderedDict(
+        sorted(self.parsed_xml.items(), key=lambda t: t[0]))
+
+  def _add_group_placeholder(self, name):
+    return {"type": Placeholder.GROUP, "name": name}
+
+  def _add_sender_placeholder(self, name):
+    return {"type": Placeholder.SENDER, "name": name}
+
+  def _add_annotation_placeholder(self, unique_id):
+    """
+    Args:
+      unique_id: str
+        The annotation's unique_id.
+    """
+    traffic_annotation = self.annotations_mapping.get(unique_id, None)
+    is_complete = traffic_annotation and all(traffic_annotation)
+    if not is_complete:
+      print(
+          "Warning: {} row is empty in annotations.tsv but is in grouping.xml".
+          format(unique_id))
+      traffic_annotation = TrafficAnnotation(unique_id, "NA", "NA", "NA", "NA",
+                                             "NA")
+
+    return {
+      "type": Placeholder.ANNOTATION, "traffic_annotation": traffic_annotation}
+
+  def build_placeholders(self):
+    """
+    Returns:
+      The placeholders <list> to be added in the order of their appearance.
+      The annotations are the TrafficAnnotation objects with the relevant
+      information.
+    """
+    self._sort_parsed_xml()
+    placeholders = []
+
+    for group, senders in self.parsed_xml.items():
+      placeholders.append(self._add_group_placeholder(group))
+      for sender, annotations in senders.items():
+        placeholders.append(self._add_sender_placeholder(sender))
+        for annotation in annotations:
+          placeholders.append(self._add_annotation_placeholder(annotation))
+    return placeholders
+
+
+def jprint(msg):
+  print(json.dumps(msg, indent=4), file=sys.stderr)
+
+
+def extract_body(document=None, target="body", json_file_path="template.json"):
+  """Google Doc API returns a .json object. Parse this doc object to obtain its
+  body.
+
+  The |template.json| object of the current state of
+  the document can be obtained by running the update_annotations_doc.py script
+  using the --debug flag.
+  """
+  if document:
+    doc = document
+  else:
+    try:
+      with open(json_file_path) as json_file:
+        doc = json.load(json_file)
+    except IOError:
+      print("Couldn't find the .json file.")
+
+  if target == "all":
+    return doc
+  return doc[target]
+
+
+def find_first_index(doc):
+  """Finds the cursor index (location) that comes right after the Introduction
+  section. Namely, the endIndex of the paragraph block the |target_text| belongs
+  to.
+
+  Returns: int
+    The first cursor index (loc) of the template document, right after the
+    Introduction section.
+  """
+  target_text = "The policy, if one exists, to control this type of network"
+  padding = 1  # We pad so as to overwrite cleanly.
+
+  body = extract_body(document=doc)
+  contents = body["content"]
+  for element in contents:
+    if "paragraph" in element:
+      end_index = element["endIndex"]
+      lines = element["paragraph"]["elements"]
+      for text_run in lines:
+        if target_text in text_run["textRun"]["content"]:
+          return end_index + padding
+
+
+def find_last_index(doc):
+  """
+  Returns: int
+    The last cursor index (loc) of the template document.
+  """
+  body = extract_body(document=doc)
+  contents = body["content"]
+  last_index = contents[-1]["endIndex"]
+  return last_index - 1
+
+
+def find_chrome_browser_version(doc):
+  """Finds what the current chrome browser version is in the document.
+
+  We grab the current "Chrome Browser version MAJOR.MINOR.BUILD.PATCH" from the
+  document's header.
+
+  Returns: str
+    The chrome browser version string.
+  """
+  # Only one header.
+  header = extract_body(document=doc, target="headers").values()[0]
+  header_elements = header["content"][0]["paragraph"]["elements"]
+  text = header_elements[0]["textRun"]["content"]
+  current_version = re.search(r"([\d.]+)", text).group()
+  return current_version
+
+
+def find_bold_ranges(doc, debug=False):
+  """Finds parts to bold given the targets of "trigger", "data", etc.
+
+  Returns:
+    The startIndex <int> and endIndex <int> tuple pairs as a list for all
+    occurrences of the targets. <List[Tuple[int, int]]>
+  """
+  bold_ranges = []
+  targets = ["Trigger", "Data", "Settings", "Policy"]
+  content = extract_body(document=doc)["content"]
+
+  for i, element in enumerate(content):
+    element_type = list(element.keys())[-1]
+
+    if element_type != "table":
+      continue
+
+    # Recall that table is 1x2 in Docs, first cell contains unique_id, second
+    # cell has traffic annotation relevant attributes.
+
+    # Unique id column, messy parsing through. You can inspect the json output
+    # with jprint() to confirm/debug if broken.
+    unique_id_col = element["table"]["tableRows"][0]["tableCells"][0][
+        "content"][0]["paragraph"]["elements"][0]
+    if debug:
+      jprint(unique_id_col)
+    assert "textRun" in unique_id_col, "Not the correct unique_id cell"
+
+    start_index = unique_id_col["startIndex"]
+    end_index = unique_id_col["endIndex"]
+    bold_ranges.append((start_index, end_index))
+
+    start_index, end_index = None, None  # Reset
+
+    # The info column, messy parsing through. You can inspect the json output
+    # with jprint() to confirm/debug if broken.
+    info_elements = element["table"]["tableRows"][0]["tableCells"][1]["content"]
+    for i, info_col in enumerate(info_elements):
+      info_col = info_elements[i]
+
+      start_index = info_col["startIndex"]
+      content = info_col["paragraph"]["elements"][0]["textRun"]["content"]
+      # To find the end_index, run through and find something in targets.
+      for target in targets:
+        if content.find("{}:".format(target)) != -1:
+          # Contains the string "|target|:"
+          end_index = start_index + len(target) + 1
+          bold_ranges.append((start_index, end_index))
+          break
+
+      if debug:
+        jprint(info_col)
+        print("#" * 30)
+
+  return bold_ranges
diff --git a/tools/traffic_annotation/scripts/parser_tests.py b/tools/traffic_annotation/scripts/parser_tests.py
new file mode 100755
index 0000000..ccaac71b
--- /dev/null
+++ b/tools/traffic_annotation/scripts/parser_tests.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+# 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.
+
+"""
+Unit tests for parser.py
+"""
+
+import unittest
+import parser
+import os
+
+# Absolute path to chrome/src.
+SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
+SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "../../.."))
+TESTS_DIR = os.path.join(SCRIPT_DIR, "test_data")
+
+class ParserTest(unittest.TestCase):
+  TSV_CONTENTS = [
+    [
+      u"unique_id_A", u"", u"sender_A", u"description_A", u"trigger_A",
+      u"data_A", u"destination_A", u"cookies_allowed_A", u"cookies_store_A",
+      u"settings_A", u"chrome_policy_A", u"", u"source_file_A",
+      u"id_hash_code_A", u"content_hash_code_A"],
+    [
+      u"unique_id_B", u"", u"sender_B", u"description_B", u"trigger_B",
+      u"data_B", u"destination_B", u"cookies_allowed_B", u"cookies_store_B",
+      u"settings_B", u"chrome_policy_B", u"", u"source_file_B",
+      u"id_hash_code_B", u"content_hash_code_B"],
+    [
+      u"unique_id_C", u"", u"sender_C", u"description_C", u"trigger_C",
+      u"data_C", u"destination_C", u"cookies_allowed_C", u"cookies_store_C",
+      u"settings_C", u"chrome_policy_C", u"", u"source_file_C",
+      u"id_hash_code_C", u"content_hash_code_C"]
+  ]
+
+  ANNOTATIONS_MAPPING = {
+    "unique_id_A": parser.TrafficAnnotation(**{
+      "unique_id": "unique_id_A",
+      "description": "description_A",
+      "trigger": "trigger_A",
+      "data": "data_A",
+      "settings": "settings_A",
+      "policy": "chrome_policy_A"}),
+    "unique_id_B": parser.TrafficAnnotation(**{
+      "unique_id": "unique_id_B",
+      "description": "description_B",
+      "trigger": "trigger_B",
+      "data": "data_B",
+      "settings": "settings_B",
+      "policy": "chrome_policy_B"}),
+    "unique_id_C": parser.TrafficAnnotation(**{
+      "unique_id": "unique_id_C",
+      "description": "description_C",
+      "trigger": "trigger_C",
+      "data": "data_C",
+      "settings": "settings_C",
+      "policy": "chrome_policy_C"})
+  }
+
+  PLACEHOLDERS = [
+    {"type": parser.Placeholder.GROUP, "name": "Group A"},
+    {"type": parser.Placeholder.SENDER, "name": "Sender 1"},
+    {
+      "type": parser.Placeholder.ANNOTATION,
+      "traffic_annotation": ANNOTATIONS_MAPPING["unique_id_A"]},
+    {"type": parser.Placeholder.SENDER, "name": "Sender 2"},
+    {
+      "type": parser.Placeholder.ANNOTATION,
+      "traffic_annotation": ANNOTATIONS_MAPPING["unique_id_B"]},
+    {"type": parser.Placeholder.GROUP, "name": "Group C"},
+    {"type": parser.Placeholder.SENDER, "name": "Sender 3"},
+    {
+      "type": parser.Placeholder.ANNOTATION,
+      "traffic_annotation": ANNOTATIONS_MAPPING["unique_id_C"]}
+  ]
+
+  # Document formatted according to fake_grouping.xml
+  DOC_JSON = parser.extract_body(
+    target="all", json_file_path=os.path.join(TESTS_DIR, "fake_doc.json"))
+
+  def test_load_tsv_file(self):
+    self.assertEqual(self.TSV_CONTENTS, parser.load_tsv_file(os.path.join(
+      SRC_DIR,
+      "tools/traffic_annotation/scripts/test_data/fake_annotations.tsv"),
+      False))
+
+  def test_map_annotations(self):
+    self.assertEqual(
+      self.ANNOTATIONS_MAPPING, parser.map_annotations(self.TSV_CONTENTS))
+
+  def test_xml_parser_build_placeholders(self):
+    xml_parser = parser.XMLParser(
+      os.path.join(TESTS_DIR, "fake_grouping.xml"), self.ANNOTATIONS_MAPPING)
+    self.assertEqual(self.PLACEHOLDERS, xml_parser.build_placeholders())
+
+  def test_find_first_index(self):
+    first_index = parser.find_first_index(self.DOC_JSON)
+    self.assertEqual(1822, first_index)
+
+  def test_find_last_index(self):
+    last_index = parser.find_last_index(self.DOC_JSON)
+    self.assertEqual(2066, last_index)
+
+  def test_find_chrome_browser_version(self):
+    current_version = parser.find_chrome_browser_version(self.DOC_JSON)
+    self.assertEqual("86.0.4187.0", current_version)
+
+  def test_find_bold_ranges(self):
+    expected_bold_ranges = [
+      (1843, 1855), (1859, 1867), (1871, 1876), (1880, 1889), (1893, 1900),
+      (1918, 1930), (1934, 1942), (1968, 1975), (1946, 1951), (1955, 1964),
+      (2001, 2013), (2017, 2025), (2029, 2034), (2038, 2047), (2051, 2058)]
+    bold_ranges = parser.find_bold_ranges(self.DOC_JSON)
+    self.assertItemsEqual(expected_bold_ranges, bold_ranges)
+
+
+if __name__ == "__main__":
+  unittest.main()
\ No newline at end of file
diff --git a/tools/traffic_annotation/scripts/test_data/fake_annotations.tsv b/tools/traffic_annotation/scripts/test_data/fake_annotations.tsv
new file mode 100644
index 0000000..8f78798
--- /dev/null
+++ b/tools/traffic_annotation/scripts/test_data/fake_annotations.tsv
@@ -0,0 +1,3 @@
+unique_id_A		sender_A	description_A	trigger_A	data_A	destination_A	cookies_allowed_A	cookies_store_A	settings_A	chrome_policy_A		source_file_A	id_hash_code_A	content_hash_code_A

+unique_id_B		sender_B	description_B	trigger_B	data_B	destination_B	cookies_allowed_B	cookies_store_B	settings_B	chrome_policy_B		source_file_B	id_hash_code_B	content_hash_code_B

+unique_id_C		sender_C	description_C	trigger_C	data_C	destination_C	cookies_allowed_C	cookies_store_C	settings_C	chrome_policy_C		source_file_C	id_hash_code_C	content_hash_code_C

diff --git a/tools/traffic_annotation/scripts/test_data/fake_grouping.xml b/tools/traffic_annotation/scripts/test_data/fake_grouping.xml
new file mode 100644
index 0000000..9196eb5d7
--- /dev/null
+++ b/tools/traffic_annotation/scripts/test_data/fake_grouping.xml
@@ -0,0 +1,15 @@
+<groups>
+  <group name="Group A">
+    <sender name="Sender 1">
+      <traffic_annotation unique_id="unique_id_A"/>
+    </sender>
+    <sender name="Sender 2">
+      <traffic_annotation unique_id="unique_id_B"/>
+    </sender>
+  </group>
+  <group name="Group C">
+    <sender name="Sender 3">
+      <traffic_annotation unique_id="unique_id_C"/>
+    </sender>
+  </group>
+</groups>
\ No newline at end of file
diff --git a/tools/traffic_annotation/scripts/update_annotations_doc.py b/tools/traffic_annotation/scripts/update_annotations_doc.py
new file mode 100755
index 0000000..738d856
--- /dev/null
+++ b/tools/traffic_annotation/scripts/update_annotations_doc.py
@@ -0,0 +1,552 @@
+#!/usr/bin/env vpython
+# 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.
+"""This script updates the Chrome Browser Network Traffic Annotations document.
+To run the script, you should first generate annotations.tsv using
+traffic_annotation_auditor.
+
+To run the script, call: `update_annotations_doc --config-file=[config.json]
+--annotations-file=[path_to_annotations.tsv]`
+
+Run `update_annotations_doc --config-help` for help on the config.json
+configuration file.
+"""
+
+from __future__ import print_function
+import argparse
+import datetime
+import httplib2
+import time
+import json
+import sys
+import os
+
+from apiclient import discovery
+from infra_libs import luci_auth
+from oauth2client import client
+from oauth2client import tools
+from oauth2client.file import Storage
+
+import parser
+from parser import (XMLParser, map_annotations, load_tsv_file, Placeholder,
+  PLACEHOLDER_STYLES)
+
+# Absolute path to chrome/src.
+SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
+SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "../../.."))
+
+
+class NetworkTrafficAnnotationsDoc:
+  SCOPES = "https://www.googleapis.com/auth/documents"
+  APPLICATION_NAME = "Chrome Network Traffic Annotations Document Updater"
+
+  # Colors are given as RGB percentages
+  BLUE = {"red": 0.812, "green": 0.886, "blue": 0.953}
+  WHITE = {"red": 1.0, "green": 1.0, "blue": 1.0}
+
+  def __init__(self,
+               doc_id,
+               doc_name,
+               credentials_file_path,
+               client_token_file_path,
+               verbose,
+               index=None):
+    """
+    Args:
+      doc_id: str
+        ID of the annotations document for clients. This is the destination
+        document where updates are made.
+      doc_name: str
+        Name of the document that contains the annotations for clients.
+      credentials_file_path: str
+        Path relative to src to read user credentials (credentials.json).
+      client_token_file_path: str
+        Path relative to src to read/save user credentials (token.pickle).
+      verbose: bool
+        Flag requesting dump of API status calls.
+      index: int
+        Where to begin adding content to. If index=None, will automatically
+        find the index corresponding to the end of the template file.
+    """
+    self.destination_id = doc_id
+    self.doc_name = doc_name
+    self.index = index
+    self._docs_service = None
+    self._color_bool = True
+    self._credentials_file_path = credentials_file_path
+    self._client_token_file_path = client_token_file_path
+
+    self.verbose = verbose
+
+  def update_doc(self, placeholders):
+    """Updates the chrome version of the destination document and includes all
+    the annotations within the grouping.xml file.
+
+    Args:
+        placeholders:
+          Contains the order of the placeholders to construct template
+    """
+    self._docs_service = self._initialize_service(
+      self._get_credentials(
+        self._credentials_file_path, self._client_token_file_path))
+    doc = self._get_doc_contents(self.destination_id)
+    self._update_chrome_version(doc)
+    self.index = self._clear_destination_contents(doc)
+    self._insert_placeholders(placeholders)
+    self._to_all_bold()
+
+    if self.verbose:
+      self._get_doc_contents(self.destination_id, save=True)
+
+    print("Done, please review the document before sharing it with clients.")
+
+  def _initialize_service(self, credentials):
+    """Initializes the Google Docs API services.
+
+    Args:
+      credentials: OAuth2Credentials user credentials.
+        The path to the user's credentials.
+
+    Returns:
+      googleapiclient.discovery.Resource Doc API service, v1.
+    """
+    http = credentials.authorize(httplib2.Http())
+    return discovery.build("docs", "v1", http=http)
+
+  def _get_credentials(self, credentials_file_path, client_token_file_path):
+    """ Gets valid user credentials from storage. If nothing has been stored, or
+    if the stored credentials are invalid, the OAuth2 flow is completed to
+    obtain the new credentials.
+
+    When running in the buildbot, uses LUCI credentials instead.
+
+    Args:
+      credentials_file_path: str
+        Absolute path to read credentials.json.
+      client_token_file_path: str
+        Absolute path to read/save user secret token.
+
+    Returns:
+      OAuth2Credentials The obtained user credentials.
+    """
+    if luci_auth.available():
+      return luci_auth.LUCICredentials(scopes=[self.SCOPES])
+
+    store = Storage(os.path.join(SRC_DIR, client_token_file_path))
+    credentials = store.get()
+
+    if not credentials or credentials.invalid:
+      flow = client.flow_from_clientsecrets(
+          os.path.join(SRC_DIR, credentials_file_path), self.SCOPES)
+      flow.user_agent = self.APPLICATION_NAME
+      flags = tools.argparser.parse_args([])
+      credentials = tools.run_flow(flow, store, flags)
+      print("Storing credentials to " + credentials_file_path)
+    return credentials
+
+  def _get_doc_contents(self, document_id, save=False):
+    document = self._docs_service.documents().get(
+        documentId=document_id).execute()
+    if save:
+      with open(os.path.join(SRC_DIR,
+      "tools/traffic_annotation/scripts/template.json"), "w") as out_file:
+        json.dump(document, out_file)
+      print("Saved template.json.")
+
+    if self.verbose:
+      print(document)
+    return document
+
+  def _update_chrome_version(self, doc):
+    """Gets the chrome version (MAJOR.MINOR.BUILD.PATCH) from src/chrome/VERSION
+    and updates the doc to reflect the correct version.
+    """
+    version = ""
+    with open(os.path.join(SRC_DIR, "chrome/VERSION"), "r") as version_file:
+      version = ".".join(line.strip().split("=")[1]
+                         for line in version_file.readlines())
+
+    current_version = parser.find_chrome_browser_version(doc)
+    replacement = "Chrome Browser version {}".format(version)
+    target = "Chrome Browser version {}".format(current_version)
+
+    if replacement == target:
+      print("Document chrome version is already up to date.")
+      return
+
+    req = [{
+        "replaceAllText": {
+            "containsText": {
+                "text": target,
+                "matchCase": True
+            },
+            "replaceText": replacement
+        }
+    }]
+    self._perform_requests(req)
+    print("Updated document chrome version {} --> {}".format(
+        current_version, version))
+
+  def _clear_destination_contents(self, doc):
+    """Will clear the contents of the destination document from the end of the
+    "Introduction" section onwards.
+
+    Return: Integer of where to start writing, i.e. the index.
+    """
+    print("Overwriting the destination document.")
+    first_index = parser.find_first_index(doc)
+    last_index = parser.find_last_index(doc)
+
+    if self.verbose:
+      print("First index, last index", first_index, last_index)
+
+    if first_index >= last_index:
+      print("Nothing to overwrite.")
+      return first_index
+
+    req = [{
+        "deleteContentRange": {
+            "range": {
+                "startIndex": first_index,
+                "endIndex": last_index
+            }
+        }
+    }]
+    self._perform_requests(req)
+    return first_index
+
+  def _perform_requests(self, reqs):
+    """Performs the requests |reqs| using batch update.
+    """
+    if not reqs:
+      print("Warning, no requests provided. Returning.")
+      return
+
+    status = self._docs_service.documents().batchUpdate(
+        body={
+            "requests": reqs
+        }, documentId=self.destination_id, fields="").execute()
+    if self.verbose:
+      print("#"*30)
+      print(status)
+      print("#"*30)
+    return status
+
+  def _insert_placeholders(self, placeholders):
+    """Placeholders (e.g. groups, senders, traffic annotations) are inserted in
+    the document in their order of appearance.
+
+    Increment the self.index value to ensure that placeholders are inserted at
+    the correct locations. Because placeholders are sorted in order of
+    appearance, self.index is strictly increasing.
+    """
+    reqs = []
+    for placeholder in placeholders:
+      placeholder_type = placeholder["type"]
+
+      if placeholder_type == Placeholder.ANNOTATION:
+        req, index = self._create_annotation_request(
+            placeholder["traffic_annotation"],
+            self.index,
+            color=self._color_bool)
+        self._color_bool = not self._color_bool
+      else:
+        # is either a group or sender placeholder
+        req, index = self._create_group_or_sender_request(
+            placeholder["name"], self.index, placeholder_type)
+
+      reqs += req
+      self.index += index
+
+    status = self._perform_requests(reqs)
+    print("Added all {} placeholders!\n".format(len(placeholders)))
+
+  def _create_text_request(self, text, index):
+    """
+    Returns:
+      The request to insert raw text without formatting and the length of the
+      text for appropriately incrementing |self.index|.
+    """
+    return {
+        "insertText": {
+          "location": {"index": index},
+          "text": text
+        }
+    }, len(text)
+
+  def _format_text(self, start_index, end_index, placeholder_type):
+    """Format the text in between |start_index| and |end_index| using the styles
+    specified by |parser.PLACEHOLDER_STYLES|.
+
+    Returns: The request to format the text in between |start_index| and
+      |end_index|.
+    """
+    return {
+        "updateTextStyle": {
+            "range": {
+                "startIndex": start_index,
+                "endIndex": end_index
+            },
+            "textStyle": {
+                "bold": PLACEHOLDER_STYLES[placeholder_type]["bold"],
+                "fontSize": {
+                    "magnitude":
+                    PLACEHOLDER_STYLES[placeholder_type]["fontSize"],
+                    "unit": "PT"
+                },
+                "weightedFontFamily": {
+                    "fontFamily": PLACEHOLDER_STYLES[placeholder_type]["font"],
+                    "weight": 400
+                }
+            },
+            "fields": "*"
+        }
+    }
+
+  def _create_group_or_sender_request(self, text, index, placeholder_type):
+    """Returns the request for inserting the group or sender placeholders using
+    the styling of |parser.PLACEHOLDER_STYLES|.
+    """
+    assert placeholder_type in [Placeholder.GROUP, Placeholder.SENDER]
+    text += "\n"
+    req, idx = self._create_text_request(text, index)
+    reqs = [req]
+    reqs.append({
+        "updateParagraphStyle": {
+            "range": {
+                "startIndex": index,
+                "endIndex": index + idx
+            },
+            "paragraphStyle": {
+                "namedStyleType":
+                PLACEHOLDER_STYLES[placeholder_type]["namedStyleType"],
+                "direction": "LEFT_TO_RIGHT",
+                "spacingMode": "NEVER_COLLAPSE",
+                "spaceAbove": {"unit": "PT"}
+            },
+            "fields": "*"
+        }
+    })
+    reqs.append(self._format_text(index, index + idx, placeholder_type))
+    return reqs, idx
+
+  def _create_annotation_request(self, traffic_annotation, index, color=False):
+    """Returns the request (dict) for inserting the annotations table. Refer to
+    the template document for a visual.
+
+    Args:
+      traffic_annotation: parser.TrafficAnnotation
+        The TrafficAnnotation object with all the relevant information, e.g.
+        unique_id, description, etc.
+      index: int
+        Where the annotation should be added in the document.
+      color: bool
+        If True, make the table blue, otherwise white.
+    """
+    # Hardcoded due to intrinsic of tables in Google Docs API.
+    idx = 8
+    offset = 2
+
+    # Create the 1x2 table -- col 1 contains the unique_id placeholder, col 2
+    # contains the remaining placeholders, e.g. trigger, description, etc.
+    padding_req, _ = self._create_text_request("\n", index)
+    reqs = [padding_req]
+    reqs.append({
+        "insertTable": {
+            "rows": 1,
+            "columns": 2,
+            "location": {"index": index}
+        }
+    })
+
+    # Writing the annotation's relevant information directly to the table,
+    # within the left cell |left_text| and the right cell |right_text|.
+    left_text = traffic_annotation.unique_id
+    right_text = "{}\nTrigger: {}\nData: {}\nSettings: {}\nPolicy: {}".format(
+        traffic_annotation.description, traffic_annotation.trigger,
+        traffic_annotation.data, traffic_annotation.settings,
+        traffic_annotation.policy)
+
+    # +4 hardcoded due to intrinsic of tables in Google Docs API.
+    start_index = index + 4
+    left_req, left_increment = self._create_text_request(left_text, start_index)
+    right_req, right_increment = self._create_text_request(
+        right_text, start_index + left_increment + offset)
+
+    reqs.append(left_req)
+    reqs.append(right_req)
+
+    end_index = index + left_increment + right_increment + idx
+
+    # This sizes the table correctly such as making the right cell's width
+    # greater than that of the left cell.
+    col_properties = [{
+        "columnIndices": [0],
+        "width": 153
+    }, {
+        "columnIndices": [1],
+        "width": 534
+    }]
+    for properties in col_properties:
+      reqs.append({
+          "updateTableColumnProperties": {
+              "tableStartLocation": {"index": index + 1},
+              "columnIndices": properties["columnIndices"],
+              "fields": "*",
+              "tableColumnProperties": {
+                  "widthType": "FIXED_WIDTH",
+                  "width": {
+                      "magnitude": properties["width"],
+                      "unit": "PT"
+                  }
+              }
+          }
+      })
+
+    # Changing the table's color and ensuring that the borders are "turned off"
+    # (really they're given the same color as the background).
+    color = self.BLUE if color else self.WHITE
+    color_and_border_req = {
+        "updateTableCellStyle": {
+            "tableStartLocation": {"index": index + 1},
+            "fields": "*",
+            "tableCellStyle": {
+                "rowSpan": 1,
+                "columnSpan": 1,
+                "backgroundColor": {
+                    "color": {
+                        "rgbColor": color
+                    }
+                }
+            }
+        }
+    }
+    # make the table borders 'invisible' and adjust the padding to site text in
+    # the cell correctly.
+    for direction in ["Left", "Right", "Top", "Bottom"]:
+      color_and_border_req["updateTableCellStyle"]["tableCellStyle"][
+          "border" + direction] = {
+              "color": {"color": {"rgbColor": color}},
+              "width": {"unit": "PT"},
+              "dashStyle": "SOLID"
+          }
+      color_and_border_req["updateTableCellStyle"]["tableCellStyle"][
+          "padding" + direction] = {"magnitude": 1.44, "unit": "PT"}
+    reqs.append(color_and_border_req)
+
+    # Text formatting (normal text, linespacing, etc.) adds space below the
+    # lines within a cell.
+    reqs.append({
+        "updateParagraphStyle": {
+            "range": {
+                "startIndex": start_index,
+                "endIndex": end_index - 1
+            },
+            "paragraphStyle": {
+                "namedStyleType": "NORMAL_TEXT",
+                "lineSpacing": 100,
+                "direction": "LEFT_TO_RIGHT",
+                "spacingMode": "NEVER_COLLAPSE",
+                "spaceBelow": {"magnitude": 4, "unit": "PT"},
+                "avoidWidowAndOrphan": False
+            },
+            "fields": "*"
+        }
+    })
+    reqs.append(
+        self._format_text(start_index, end_index - 1, Placeholder.ANNOTATION))
+    return reqs, end_index - index
+
+  def _to_bold(self, start_index, end_index):
+    """Bold the text between start_index and end_index. Uses the same formatting
+    as the annotation bold."""
+    return self._format_text(start_index, end_index,
+                             Placeholder.ANNOTATION_BOLD)
+
+  def _to_all_bold(self):
+    """Bold the unique_id, description, trigger, etc. in the tables to
+    correspond exactly to the template."""
+    # Get recent doc after all the substitutions with the annotations. At this
+    # point, document has all the content.
+    print("Finding everything to bold...")
+    doc = self._get_doc_contents(self.destination_id)
+
+    # the ranges to bold using the updateTextStyle request
+    bold_ranges = parser.find_bold_ranges(doc)
+    reqs = []
+    for i, (start_index, end_index) in enumerate(bold_ranges):
+      if end_index > start_index:
+        reqs.append(self._to_bold(start_index, end_index))
+    self._perform_requests(reqs)
+
+
+def print_config_help():
+  print("The config.json file should have the following items:\n"
+        "doc_id:\n"
+        "  ID of the destination document.\n"
+        "doc_name:\n"
+        "  Name of the document.\n"
+        "credentials_file_path:\n"
+        "  Absolute path of the file that keeps user credentials.\n"
+        "client_token_file_path:\n"
+        "  Absolute path of the token.pickle which keeps the users credentials."
+        "  The file can be created as specified in:\n"
+        "  https://developers.google.com/docs/api/quickstart/python")
+
+
+def main():
+  args_parser = argparse.ArgumentParser(
+      description="Updates 'Chrome Browser Network Traffic Annotations' doc.")
+  args_parser.add_argument("--config-file", help="Configurations file.")
+  args_parser.add_argument("--annotations-file",
+                           help="TSV annotations file exported from auditor.")
+  args_parser.add_argument("--verbose",
+                           action="store_true",
+                           help="Reports all updates. "
+                           " Also creates a scripts/template.json file "
+                           " outlining the document's current structure.")
+  args_parser.add_argument("--config-help",
+                           action="store_true",
+                           help="Shows the configurations help.")
+  args = args_parser.parse_args()
+
+  if args.config_help:
+    print_config_help()
+    return 0
+
+  # Load and parse config file.
+  with open(os.path.join(SRC_DIR, args.config_file)) as config_file:
+    config = json.load(config_file)
+
+  tsv_contents = load_tsv_file(
+    os.path.join(SRC_DIR, args.annotations_file), False)
+  if not tsv_contents:
+    print("Could not read annotations file.")
+    return -1
+
+  xml_parser = XMLParser(
+      os.path.join(SRC_DIR, "tools/traffic_annotation/summary/grouping.xml"),
+      map_annotations(tsv_contents))
+  placeholders = xml_parser.build_placeholders()
+  print("#" * 40)
+  print("There are:", len(placeholders), "placeholders")
+  if args.verbose:
+    print(placeholders)
+  print("#" * 40)
+
+  network_traffic_doc = NetworkTrafficAnnotationsDoc(
+      doc_id=config["doc_id"],
+      doc_name=config["doc_name"],
+      credentials_file_path=config["credentials_file_path"],
+      client_token_file_path=config["client_token_file_path"],
+      verbose=args.verbose)
+
+  if not network_traffic_doc.update_doc(placeholders):
+    return -1
+
+  return 0
+
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/tools/traffic_annotation/scripts/update_annotations_doc.py.vpython b/tools/traffic_annotation/scripts/update_annotations_doc.py.vpython
new file mode 100644
index 0000000..59b3e8e3
--- /dev/null
+++ b/tools/traffic_annotation/scripts/update_annotations_doc.py.vpython
@@ -0,0 +1,61 @@
+python_version: "2.7"
+
+wheel: <
+  name: "infra/python/wheels/google_api_python_client-py2_py3"
+  version: "version:1.6.2"
+>
+
+wheel: <
+  name: "infra/python/wheels/oauth2client-py2_py3"
+  version: "version:4.0.0"
+>
+
+wheel: <
+  name: "infra/python/wheels/uritemplate-py2_py3"
+  version: "version:3.0.0"
+>
+
+wheel: <
+  name: "infra/python/wheels/enum34-py2"
+  version: "version:1.1.6"
+>
+
+wheel: <
+  name: "infra/python/wheels/httplib2-py2_py3"
+  version: "version:0.12.1"
+>
+
+wheel: <
+  name: "infra/python/wheels/rsa-py2_py3"
+  version: "version:3.4.2"
+>
+
+wheel: <
+  name: "infra/python/wheels/pyasn1-py2_py3"
+  version: "version:0.2.3"
+>
+
+wheel: <
+  name: "infra/python/wheels/pyasn1_modules-py2_py3"
+  version: "version:0.0.8"
+>
+
+wheel: <
+  name: "infra/python/wheels/six-py2_py3"
+  version: "version:1.10.0"
+>
+
+wheel: <
+  name: "infra/python/wheels/infra_libs-py2"
+  version: "version:2.0.0"
+>
+
+wheel: <
+  name: "infra/python/wheels/protobuf-py2_py3"
+  version: "version:3.2.0"
+>
+
+wheel: <
+  name: "infra/python/wheels/requests-py2_py3"
+  version: "version:2.13.0"
+>
\ No newline at end of file
diff --git a/tools/traffic_annotation/scripts/update_annotations_doc_tests.py b/tools/traffic_annotation/scripts/update_annotations_doc_tests.py
new file mode 100755
index 0000000..99fa6ae
--- /dev/null
+++ b/tools/traffic_annotation/scripts/update_annotations_doc_tests.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+# 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.
+
+"""
+Unit tests for update_annotations_doc.py
+"""
+
+import os
+import sys
+import unittest
+from mock import MagicMock
+
+# Mock some imports which aren't necessary during testing.
+sys.modules["infra_libs"] = MagicMock()
+import update_annotations_doc
+import parser
+
+# Absolute path to chrome/src.
+SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
+SRC_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "../../.."))
+TESTS_DIR = os.path.join(SCRIPT_DIR, "test_data")
+
+
+class UpdateAnnotationsDocTest(unittest.TestCase):
+  network_doc_obj = update_annotations_doc.NetworkTrafficAnnotationsDoc(
+    "", "", "", "", "")
+
+  def test_create_group_request(self):
+    text = "TestGroup"
+    req, index = self.network_doc_obj._create_group_or_sender_request(
+      text, 0, parser.Placeholder.GROUP)
+
+    self.assertEqual(len(text)+1, index)
+    expected_req = [
+      {"insertText": {"text": "TestGroup\n", "location": {"index": 0}}},
+      {"updateParagraphStyle": {
+        "fields": "*",
+        "range": {"endIndex": 10, "startIndex": 0},
+        "paragraphStyle": {
+          "spacingMode": "NEVER_COLLAPSE",
+          "direction": "LEFT_TO_RIGHT",
+          "namedStyleType": "HEADING_1",
+          "spaceAbove": {"unit": "PT"}
+          }
+        }
+      },
+      {"updateTextStyle": {
+        "textStyle": {
+          "fontSize": {"magnitude": 20, "unit": "PT"},
+          "bold": False,
+          "weightedFontFamily": {
+            "fontFamily": "Roboto",
+            "weight": 400
+          }
+        },
+        "range": {"endIndex": 10, "startIndex": 0}, "fields": "*"}}
+    ]
+    self.assertEqual(expected_req, req)
+
+  def test_create_sender_request(self):
+    text = "TestSender"
+    print(text)
+    req, index = self.network_doc_obj._create_group_or_sender_request(
+        text, 0, parser.Placeholder.SENDER)
+
+    self.assertEqual(len(text)+1, index)
+    expected_req = [
+      {"insertText": {"text": "TestSender\n", "location": {"index": 0}}},
+      {"updateParagraphStyle": {
+        "fields": "*",
+        "range": {"endIndex": 11, "startIndex": 0},
+        "paragraphStyle": {
+          "spacingMode": "NEVER_COLLAPSE",
+          "direction": "LEFT_TO_RIGHT",
+          "namedStyleType": "HEADING_2",
+          "spaceAbove": {"unit": "PT"}
+          }
+        }
+      },
+      {"updateTextStyle": {
+        "textStyle": {"fontSize": {"magnitude": 14, "unit": "PT"},
+        "bold": True,
+        "weightedFontFamily": {"fontFamily": "Roboto", "weight": 400}},
+        "range": {"endIndex": 11, "startIndex": 0}, "fields": "*"}
+        }
+    ]
+    self.assertEqual(expected_req, req)
+
+  def test_create_annotation_request(self):
+    traffic_annotation = parser.TrafficAnnotation(**{
+      "unique_id": "unique_id_A",
+      "description": "description_A",
+      "trigger": "trigger_A",
+      "data": "data_A",
+      "settings": "settings_A",
+      "policy": "chrome_policy_A"})
+
+    req, index = self.network_doc_obj._create_annotation_request(
+      traffic_annotation, 0)
+
+    self.assertEqual(109, index)
+    expected_req = [
+      {'insertText': {'text': '\n', 'location': {'index': 0}}},
+      {'insertTable': {'rows': 1, 'location': {'index': 0}, 'columns': 2}},
+      {'insertText': {'text': 'unique_id_A', 'location': {'index': 4}}},
+      {
+        'insertText': {
+          'text': "description_A\nTrigger: trigger_A\nData: data_A\nSettings: "
+          "settings_A\nPolicy: chrome_policy_A", 'location': {'index': 17}}},
+      {'updateTableColumnProperties': {
+        'columnIndices': [0],
+        'fields': '*',
+        'tableColumnProperties': {
+          'width': {'magnitude': 153, 'unit': 'PT'},
+          'widthType': 'FIXED_WIDTH'},
+          'tableStartLocation': {'index': 1}}},
+      {'updateTableColumnProperties': {
+        'columnIndices': [1],
+        'fields': '*',
+        'tableColumnProperties': {
+          'width': {'magnitude': 534, 'unit': 'PT'},'widthType': 'FIXED_WIDTH'},
+        'tableStartLocation': {'index': 1}}},
+      {'updateTableCellStyle': {
+        'fields': '*',
+        'tableCellStyle': {
+          'rowSpan': 1,
+          'borderBottom': {
+            'color': {
+              'color': {'rgbColor': {'blue': 1.0, 'green': 1.0, 'red': 1.0}}},
+            'width': {'unit': 'PT'}, 'dashStyle': 'SOLID'},
+          'paddingBottom': {'magnitude': 1.44, 'unit': 'PT'},
+          'paddingLeft': {'magnitude': 1.44, 'unit': 'PT'},
+          'paddingTop': {'magnitude': 1.44, 'unit': 'PT'},
+          'borderLeft': {
+            'color': {
+              'color': {'rgbColor': {'blue': 1.0, 'green': 1.0, 'red': 1.0}}},
+            'width': {'unit': 'PT'},
+            'dashStyle': 'SOLID'},
+          'columnSpan': 1,
+          'backgroundColor': {
+            'color': {'rgbColor': {'blue': 1.0, 'green': 1.0, 'red': 1.0}}},
+          'borderRight': {
+            'color': {
+              'color': {'rgbColor': {'blue': 1.0, 'green': 1.0, 'red': 1.0}}},
+            'width': {'unit': 'PT'},
+            'dashStyle': 'SOLID'},
+          'borderTop': {
+            'color': {
+              'color': {'rgbColor': {'blue': 1.0, 'green': 1.0, 'red': 1.0}}},
+              'width': {'unit': 'PT'},
+              'dashStyle': 'SOLID'},
+          'paddingRight': {'magnitude': 1.44, 'unit': 'PT'}},
+          'tableStartLocation': {'index': 1}}},
+        {'updateParagraphStyle': {
+          'fields': '*',
+          'range': {'endIndex': 108, 'startIndex': 4},
+          'paragraphStyle': {
+            'spacingMode': 'NEVER_COLLAPSE',
+            'direction': 'LEFT_TO_RIGHT',
+            'spaceBelow': {'magnitude': 4, 'unit': 'PT'},
+            'lineSpacing': 100,
+            'avoidWidowAndOrphan': False,
+            'namedStyleType': 'NORMAL_TEXT'}}},
+        {'updateTextStyle': {
+          'textStyle': {'fontSize': {'magnitude': 9, 'unit': 'PT'},
+          'bold': False,
+          'weightedFontFamily': {'fontFamily': 'Roboto', 'weight': 400}},
+          'range': {'endIndex': 108, 'startIndex': 4}, 'fields': '*'}}]
+    self.assertEqual(expected_req, req)
+
+
+if __name__ == "__main__":
+  unittest.main()
\ No newline at end of file
diff --git a/tools/traffic_annotation/scripts/update_annotations_sheet.py b/tools/traffic_annotation/scripts/update_annotations_sheet.py
index 0a613b4b..d6b1082 100755
--- a/tools/traffic_annotation/scripts/update_annotations_sheet.py
+++ b/tools/traffic_annotation/scripts/update_annotations_sheet.py
@@ -29,6 +29,7 @@
 from oauth2client import client
 from oauth2client import tools
 from oauth2client.file import Storage
+from parser import load_tsv_file
 
 
 class SheetEditor():
@@ -336,37 +337,6 @@
                 self.insert_count, self.update_count, self.delete_count)
 
 
-def utf_8_encoder(input_file):
-  for line in input_file:
-    yield line.encode("utf-8")
-
-
-def LoadTSVFile(file_path, verbose):
-  """ Loads annotations TSV file.
-
-  Args:
-    file_path: str Path to the TSV file.
-    verbose: bool Whether to print messages about ignored rows.
-
-  Returns:
-    list of list Table of loaded annotations.
-  """
-  rows = []
-  with io.open(file_path, mode="r", encoding="utf-8") as csvfile:
-    # CSV library does not support unicode, so encoding to utf-8 and back.
-    reader = csv.reader(utf_8_encoder(csvfile), delimiter='\t')
-    for row in reader:
-      row = [unicode(col, 'utf-8') for col in row]
-      # If the last column of the file_row is empty, the row belongs to a
-      # platform different from the one that TSV file is generated on, hence it
-      # should be ignored.
-      if row[-1]:
-        rows.append(row)
-      elif verbose:
-        print("Ignored from other platforms: %s" % row[0])
-  return rows
-
-
 def PrintConfigHelp():
   print("The config.json file should have the following items:\n"
         "spreadsheet_id:\n"
@@ -416,7 +386,7 @@
     config = json.load(config_file)
 
   # Load and parse annotations file.
-  file_content = LoadTSVFile(args.annotations_file, args.verbose)
+  file_content = load_tsv_file(args.annotations_file, args.verbose)
   if not file_content:
     print("Could not read annotations file.")
     return -1
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc
index da9314d4..f57aa0b0 100644
--- a/ui/accessibility/ax_event_generator.cc
+++ b/ui/accessibility/ax_event_generator.cc
@@ -47,6 +47,19 @@
   }
 }
 
+// If a node toggled its ignored state, don't also fire children-changed because
+// platforms likely will do that in response to ignored-changed.
+// Suppress name- and description-changed because those can be emitted as a side
+// effect of calculating alternative text values for a newly-displayed object.
+// Ditto for text attributes such as foreground and background colors.
+void RemoveEventsDueToIgnoredChanged(
+    std::set<AXEventGenerator::EventParams>* node_events) {
+  RemoveEvent(node_events, AXEventGenerator::Event::CHILDREN_CHANGED);
+  RemoveEvent(node_events, AXEventGenerator::Event::DESCRIPTION_CHANGED);
+  RemoveEvent(node_events, AXEventGenerator::Event::NAME_CHANGED);
+  RemoveEvent(node_events, AXEventGenerator::Event::TEXT_ATTRIBUTE_CHANGED);
+}
+
 }  // namespace
 
 AXEventGenerator::EventParams::EventParams(
@@ -665,7 +678,51 @@
          data.relative_bounds.bounds.height();
 }
 
+void AXEventGenerator::TrimEventsDueToAncestorIgnoredChanged(
+    AXNode* node,
+    std::map<AXNode*, bool>& ancestor_ignored_changed_map) {
+  DCHECK(node);
+
+  // Recursively compute and cache ancestor ignored changed results in
+  // |ancestor_ignored_changed_map|, if |node|'s ancestors have become ignored
+  // and the ancestor's ignored changed results have not been cached.
+  if (node->parent() &&
+      !base::Contains(ancestor_ignored_changed_map, node->parent())) {
+    TrimEventsDueToAncestorIgnoredChanged(node->parent(),
+                                          ancestor_ignored_changed_map);
+  }
+
+  // If an ancestor of |node| changed to ignored state, update the corresponding
+  // entry in the map for |node| based on the ancestor result (i.e. if an
+  // ancestor changed to ignored state, set the entry in the map to true for the
+  // current node). If |node|'s state changed to ignored as well, we want to
+  // remove its IGNORED_CHANGED event.
+  const auto& map_iter = ancestor_ignored_changed_map.find(node->parent());
+  const auto& events_iter = tree_events_.find(node);
+  if (map_iter != ancestor_ignored_changed_map.end() && map_iter->second) {
+    ancestor_ignored_changed_map.insert(std::make_pair(node, true));
+    if (node->IsIgnored() && events_iter != tree_events_.end()) {
+      RemoveEvent(&(events_iter->second), Event::IGNORED_CHANGED);
+      RemoveEventsDueToIgnoredChanged(&(events_iter->second));
+    }
+    return;
+  }
+
+  // If ignored changed results are not cached, calculate the corresponding
+  // entry for |node| in the map using the ignored states and events of |node|.
+  if (events_iter != tree_events_.end() &&
+      HasEvent(events_iter->second, Event::IGNORED_CHANGED) &&
+      node->IsIgnored()) {
+    ancestor_ignored_changed_map.insert(std::make_pair(node, true));
+    return;
+  }
+
+  ancestor_ignored_changed_map.insert(std::make_pair(node, false));
+}
+
 void AXEventGenerator::PostprocessEvents() {
+  std::map<AXNode*, bool> ancestor_ignored_changed_map;
+
   auto iter = tree_events_.begin();
   while (iter != tree_events_.end()) {
     AXNode* node = iter->first;
@@ -678,17 +735,13 @@
       RemoveEvent(&node_events, Event::LIVE_REGION_CHANGED);
     }
 
-    // If a node toggled its ignored state, don't also fire children-changed
-    // because platforms likely will do that in response to ignored-changed.
-    // Suppress name- and description-changed because those can be emitted
-    // as a side effect of calculating alternative text values for a newly-
-    // displayed object. Ditto for text attributes such as foreground and
-    // background colors.
     if (HasEvent(node_events, Event::IGNORED_CHANGED)) {
-      RemoveEvent(&node_events, Event::CHILDREN_CHANGED);
-      RemoveEvent(&node_events, Event::DESCRIPTION_CHANGED);
-      RemoveEvent(&node_events, Event::NAME_CHANGED);
-      RemoveEvent(&node_events, Event::TEXT_ATTRIBUTE_CHANGED);
+      // If a node toggled its ignored state from show to hide, we only want to
+      // fire IGNORED_CHANGED event on the top most ancestor where this ignored
+      // state change takes place and suppress all the descendants's
+      // IGNORED_CHANGED events.
+      TrimEventsDueToAncestorIgnoredChanged(node, ancestor_ignored_changed_map);
+      RemoveEventsDueToIgnoredChanged(&node_events);
     }
 
     // When the selected option in an expanded select element changes, the
diff --git a/ui/accessibility/ax_event_generator.h b/ui/accessibility/ax_event_generator.h
index 2755932f..b068624 100644
--- a/ui/accessibility/ax_event_generator.h
+++ b/ui/accessibility/ax_event_generator.h
@@ -235,6 +235,18 @@
   void FireActiveDescendantEvents();
   void FireRelationSourceEvents(AXTree* tree, AXNode* target_node);
   bool ShouldFireLoadEvents(AXNode* node);
+  // Remove excessive events for a tree update containing node.
+  // We remove certain events on a node when it changes to IGNORED state and one
+  // of the node's ancestor has also changed to IGNORED in the same tree update.
+  // |ancestor_has_ignored_map| contains if a node's ancestor has changed to
+  // IGNORED state.
+  // Map's key is: an ax node.
+  // Map's value is:
+  // - True if an ancestor of node changed to IGNORED state.
+  // - False if no ancestor of node changed to IGNORED state.
+  void TrimEventsDueToAncestorIgnoredChanged(
+      AXNode* node,
+      std::map<AXNode*, bool>& ancestor_has_ignored_map);
   void PostprocessEvents();
   static void GetRestrictionStates(ax::mojom::Restriction restriction,
                                    bool* is_enabled,
diff --git a/ui/accessibility/ax_event_generator_unittest.cc b/ui/accessibility/ax_event_generator_unittest.cc
index 3f9eb022f..611ce33 100644
--- a/ui/accessibility/ax_event_generator_unittest.cc
+++ b/ui/accessibility/ax_event_generator_unittest.cc
@@ -1152,6 +1152,459 @@
                   HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 2)));
 }
 
+TEST(AXEventGeneratorTest, IgnoredChangedFiredOnAncestorOnly1) {
+  // BEFORE
+  //   1 (IGN)
+  //  / \
+  // 2   3 (IGN)
+  // AFTER
+  //   1 (IGN)
+  //  /      \
+  // 2 (IGN)  3
+  // IGNORED_CHANGED expected on #2, #3
+
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(3);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[0].AddState(ax::mojom::State::kIgnored);
+  initial_state.nodes[0].child_ids = {2, 3};
+
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].role = ax::mojom::Role::kStaticText;
+
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+  update.nodes[1].AddState(ax::mojom::State::kIgnored);
+  update.nodes[2].RemoveState(ax::mojom::State::kIgnored);
+  ASSERT_TRUE(tree.Unserialize(update));
+  EXPECT_THAT(event_generator,
+              UnorderedElementsAre(
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 2),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 3),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 3)));
+}
+
+TEST(AXEventGeneratorTest, IgnoredChangedFiredOnAncestorOnly2) {
+  // BEFORE
+  //   1
+  //   |
+  //   2
+  //  / \
+  // 3   4 (IGN)
+  // AFTER
+  //   1
+  //   |
+  //   2 ___
+  //  /      \
+  // 3 (IGN)  4
+  // IGNORED_CHANGED expected on #3, #4
+
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(4);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[0].child_ids = {2};
+
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[1].child_ids = {3, 4};
+
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kStaticText;
+
+  initial_state.nodes[3].id = 4;
+  initial_state.nodes[3].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[3].AddState(ax::mojom::State::kIgnored);
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+  update.nodes[2].AddState(ax::mojom::State::kIgnored);
+  update.nodes[3].RemoveState(ax::mojom::State::kIgnored);
+  ASSERT_TRUE(tree.Unserialize(update));
+  EXPECT_THAT(event_generator,
+              UnorderedElementsAre(
+                  HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 2),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 3),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 4),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 4)));
+}
+
+TEST(AXEventGeneratorTest, IgnoredChangedFiredOnAncestorOnly3) {
+  // BEFORE
+  //   1
+  //   |
+  //   2 ___
+  //  /      \
+  // 3 (IGN)  4
+  // AFTER
+  //   1 (IGN)
+  //   |
+  //   2
+  //  /  \
+  // 3    4 (IGN)
+  // IGNORED_CHANGED expected on #1, #3
+
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(4);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[0].child_ids = {2};
+
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[1].child_ids = {3, 4};
+
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[3].id = 4;
+  initial_state.nodes[3].role = ax::mojom::Role::kStaticText;
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+  update.nodes[0].AddState(ax::mojom::State::kIgnored);
+  update.nodes[2].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[3].AddState(ax::mojom::State::kIgnored);
+  ASSERT_TRUE(tree.Unserialize(update));
+  EXPECT_THAT(event_generator,
+              UnorderedElementsAre(
+                  HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 2),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 1),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 3),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 3)));
+}
+
+TEST(AXEventGeneratorTest, IgnoredChangedFiredOnAncestorOnly4) {
+  // BEFORE
+  //         1 (IGN)
+  //         |
+  //         2
+  //         |
+  //         3 (IGN)
+  //         |
+  //         4 (IGN)
+  //         |
+  //    ____ 5  _____
+  //  /       |       \
+  // 6 (IGN)  7 (IGN)  8
+  // AFTER
+  //         1 (IGN)
+  //         |
+  //         2
+  //         |
+  //         3 (IGN)
+  //         |
+  //         4 (IGN)
+  //         |
+  //    ____ 5  _____
+  //  /       |       \
+  // 6        7        8 (IGN)
+
+  // IGNORED_CHANGED expected on #6, #7, #8
+
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(8);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[0].child_ids = {2};
+
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[1].child_ids = {3};
+
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[2].child_ids = {4};
+  initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[3].id = 4;
+  initial_state.nodes[3].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[3].child_ids = {5};
+  initial_state.nodes[3].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[4].id = 5;
+  initial_state.nodes[4].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[4].child_ids = {6, 7, 8};
+
+  initial_state.nodes[5].id = 6;
+  initial_state.nodes[5].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[5].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[6].id = 7;
+  initial_state.nodes[6].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[6].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[7].id = 8;
+  initial_state.nodes[7].role = ax::mojom::Role::kStaticText;
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+  update.nodes[5].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[6].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[7].AddState(ax::mojom::State::kIgnored);
+  ASSERT_TRUE(tree.Unserialize(update));
+  EXPECT_THAT(event_generator,
+              UnorderedElementsAre(
+                  HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 5),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 6),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 7),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 6),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 7),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 8)));
+}
+
+TEST(AXEventGeneratorTest, IgnoredChangedFiredOnAncestorOnly5) {
+  // BEFORE
+  //         1
+  //         |
+  //         2
+  //         |
+  //         3 (IGN)
+  //         |
+  //         4 (IGN)
+  //         |
+  //    ____ 5  _____
+  //  /       |       \
+  // 6 (IGN)  7        8
+  // AFTER
+  //         1 (IGN)
+  //         |
+  //         2
+  //         |
+  //         3 (IGN)
+  //         |
+  //         4 (IGN)
+  //         |
+  //    ____ 5  _____
+  //  /       |       \
+  // 6        7 (IGN)  8 (IGN)
+
+  // IGNORED_CHANGED expected on #1, #6
+
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(8);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[0].child_ids = {2};
+
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[1].child_ids = {3};
+
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[2].child_ids = {4};
+  initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[3].id = 4;
+  initial_state.nodes[3].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[3].child_ids = {5};
+  initial_state.nodes[3].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[4].id = 5;
+  initial_state.nodes[4].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[4].child_ids = {6, 7, 8};
+
+  initial_state.nodes[5].id = 6;
+  initial_state.nodes[5].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[5].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[6].id = 7;
+  initial_state.nodes[6].role = ax::mojom::Role::kStaticText;
+
+  initial_state.nodes[7].id = 8;
+  initial_state.nodes[7].role = ax::mojom::Role::kStaticText;
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+  update.nodes[0].AddState(ax::mojom::State::kIgnored);
+  update.nodes[5].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[6].AddState(ax::mojom::State::kIgnored);
+  update.nodes[7].AddState(ax::mojom::State::kIgnored);
+  ASSERT_TRUE(tree.Unserialize(update));
+  EXPECT_THAT(event_generator,
+              UnorderedElementsAre(
+                  HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 5),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 6),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 1),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 6)));
+}
+
+TEST(AXEventGeneratorTest, IgnoredChangedFiredOnAncestorOnly6) {
+  // BEFORE
+  //         1 (IGN)
+  //         |
+  //         2
+  //         |
+  //         3
+  //         |
+  //         4
+  //         |
+  //    ____ 5  _____
+  //  /       |       \
+  // 6 (IGN)  7 (IGN)  8
+  // AFTER
+  //         1
+  //         |
+  //         2
+  //         |
+  //         3
+  //         |
+  //         4
+  //         |
+  //    ____ 5  _____
+  //  /       |       \
+  // 6        7        8 (IGN)
+
+  // IGNORED_CHANGED expected on #1, #6, #7, #8
+
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(8);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[0].child_ids = {2};
+  initial_state.nodes[0].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[1].child_ids = {3};
+
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[2].child_ids = {4};
+
+  initial_state.nodes[3].id = 4;
+  initial_state.nodes[3].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[3].child_ids = {5};
+
+  initial_state.nodes[4].id = 5;
+  initial_state.nodes[4].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[4].child_ids = {6, 7, 8};
+
+  initial_state.nodes[5].id = 6;
+  initial_state.nodes[5].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[5].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[6].id = 7;
+  initial_state.nodes[6].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[6].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[7].id = 8;
+  initial_state.nodes[7].role = ax::mojom::Role::kStaticText;
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+  update.nodes[0].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[5].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[6].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[7].AddState(ax::mojom::State::kIgnored);
+  ASSERT_TRUE(tree.Unserialize(update));
+  EXPECT_THAT(event_generator,
+              UnorderedElementsAre(
+                  HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 5),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 1),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 6),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 7),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 1),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 6),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 7),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 8)));
+}
+
+TEST(AXEventGeneratorTest, IgnoredChangedFiredOnAncestorOnly7) {
+  // BEFORE
+  //       1 (IGN)
+  //       |
+  //       2 (IGN)
+  //       |
+  //       3
+  //       |
+  //    __ 4 ___
+  //  /          \
+  // 5 (IGN)      6 (IGN)
+  // AFTER
+  //       1
+  //       |
+  //       2
+  //       |
+  //       3 (IGN)
+  //       |
+  //    __ 4 (IGN)
+  //  /           \
+  // 5 (IGN)       6 (IGN)
+
+  // IGNORED_CHANGED expected on #1, #2, #3
+
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(6);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[0].child_ids = {2};
+  initial_state.nodes[0].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[1].child_ids = {3};
+  initial_state.nodes[1].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[2].child_ids = {4};
+
+  initial_state.nodes[3].id = 4;
+  initial_state.nodes[3].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[3].child_ids = {5, 6};
+
+  initial_state.nodes[4].id = 5;
+  initial_state.nodes[4].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[4].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[5].id = 6;
+  initial_state.nodes[5].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[5].AddState(ax::mojom::State::kIgnored);
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+  update.nodes[0].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[1].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[2].AddState(ax::mojom::State::kIgnored);
+  update.nodes[3].AddState(ax::mojom::State::kIgnored);
+  ASSERT_TRUE(tree.Unserialize(update));
+  EXPECT_THAT(event_generator,
+              UnorderedElementsAre(
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 1),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 1),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 2),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 3)));
+}
+
 TEST(AXEventGeneratorTest, ActiveDescendantChangeOnDescendant) {
   AXTreeUpdate initial_state;
   initial_state.root_id = 1;
diff --git a/ui/base/ime/win/tsf_text_store.cc b/ui/base/ime/win/tsf_text_store.cc
index b39bc59..acc2d7d 100644
--- a/ui/base/ime/win/tsf_text_store.cc
+++ b/ui/base/ime/win/tsf_text_store.cc
@@ -1392,6 +1392,8 @@
       CompositionText composition_text;
       composition_text.text = new_committed_string;
       composition_text.ime_text_spans = spans;
+      composition_text.selection.set_start(new_committed_string.size());
+      composition_text.selection.set_end(new_committed_string.size());
       text_input_client_->SetCompositionText(composition_text);
     }
     text_input_client_->InsertText(new_committed_string);
diff --git a/ui/base/ime/win/tsf_text_store_unittest.cc b/ui/base/ime/win/tsf_text_store_unittest.cc
index 9344f5b..a4733d3 100644
--- a/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -2561,6 +2561,7 @@
   void SetCompositionText4(const ui::CompositionText& composition) {
     EXPECT_EQ(L"c", composition.text);
     ASSERT_EQ(1u, composition.ime_text_spans.size());
+    ASSERT_EQ(gfx::Range(1, 1), composition.selection);
   }
 
   void InsertText4(const base::string16& text) { EXPECT_EQ(L"c", text); }
diff --git a/ui/gfx/platform_font_mac.mm b/ui/gfx/platform_font_mac.mm
index be3ac0b0..7ade2d4 100644
--- a/ui/gfx/platform_font_mac.mm
+++ b/ui/gfx/platform_font_mac.mm
@@ -91,31 +91,53 @@
   DCHECK(font);
 
   // Map CoreText weights in a manner similar to ct_weight_to_fontstyle() from
-  // SkFontHost_mac.cpp, but adjust for MEDIUM so that the San Francisco's
-  // custom MEDIUM weight can be picked out. San Francisco has weights:
-  // [0.23, 0.23, 0.3, 0.4, 0.56, 0.62, 0.62, ...] (no thin weights).
-  // See PlatformFontMacTest.FontWeightAPIConsistency for details.
-  // Note that the table Skia uses is also determined by experiment.
+  // SkFontHost_mac.cpp, but adjusted for the weights actually used by the
+  // system fonts. See PlatformFontMacTest.FontWeightAPIConsistency for details.
+  // Use ranges for paranoia.
   constexpr struct {
-    CGFloat ct_weight;
+    // A range of CoreText weights.
+    CGFloat weight_lower;
+    CGFloat weight_upper;
     Font::Weight gfx_weight;
   } weight_map[] = {
-      // Missing: Apple "ultralight".
-      {-0.70, Font::Weight::THIN},
-      {-0.50, Font::Weight::EXTRA_LIGHT},
-      {-0.23, Font::Weight::LIGHT},
-      {0.00, Font::Weight::NORMAL},
-      {0.23, Font::Weight::MEDIUM},  // Note: adjusted from 0.20 vs Skia.
-      // Missing: Apple "demibold".
-      {0.30, Font::Weight::SEMIBOLD},
-      {0.40, Font::Weight::BOLD},
-      {0.60, Font::Weight::EXTRA_BOLD},
-      // Missing: Apple "heavyface".
-      // Values will be capped to BLACK (this entry is here for consistency).
-      {0.80, Font::Weight::BLACK},
-      // Missing: Apple "ultrablack".
-      // Missing: Apple "extrablack".
+      // NSFontWeight constants introduced in 10.11:
+      //   NSFontWeightUltraLight: -0.80
+      //   NSFontWeightThin: -0.60
+      //   NSFontWeightLight: -0.40
+      //   NSFontWeightRegular: 0.0
+      //   NSFontWeightMedium: 0.23
+      //   NSFontWeightSemibold: 0.30
+      //   NSFontWeightBold: 0.40
+      //   NSFontWeightHeavy: 0.56
+      //   NSFontWeightBlack: 0.62
+      //
+      // Actual system font weights:
+      //   10.10:
+      //     .HelveticaNeueDeskInterface-Regular: 0.0
+      //     .HelveticaNeueDeskInterface-MediumP4: 0.23
+      //     .HelveticaNeueDeskInterface-Bold: 0.4
+      //     .HelveticaNeueDeskInterface-Heavy: 0.62
+      //   10.11-:
+      //     .AppleSystemUIFontUltraLight: -0.80 (10.12-)
+      //     .AppleSystemUIFontLight: -0.40 (10.12-)
+      //     .AppleSystemUIFont: 0 (10.11-)
+      //     .AppleSystemUIFontMedium: 0.23 (10.12-)
+      //     .AppleSystemUIFontDemi: 0.30 (10.12-)
+      //     .AppleSystemUIFontBold: 0.40 (10.11)
+      //     .AppleSystemUIFontEmphasized: 0.40 (10.12-)
+      //     .AppleSystemUIFontHeavy: 0.56 (10.11-)
+      //     .AppleSystemUIFontBlack: 0.62 (10.11-)
+      {-1000, -0.70, Font::Weight::THIN},         // NSFontWeightUltraLight
+      {-0.70, -0.45, Font::Weight::EXTRA_LIGHT},  // NSFontWeightThin
+      {-0.45, -0.10, Font::Weight::LIGHT},        // NSFontWeightLight
+      {-0.10, 0.10, Font::Weight::NORMAL},        // NSFontWeightRegular
+      {0.10, 0.27, Font::Weight::MEDIUM},         // NSFontWeightMedium
+      {0.27, 0.35, Font::Weight::SEMIBOLD},       // NSFontWeightSemibold
+      {0.35, 0.50, Font::Weight::BOLD},           // NSFontWeightBold
+      {0.50, 0.60, Font::Weight::EXTRA_BOLD},     // NSFontWeightHeavy
+      {0.60, 1000, Font::Weight::BLACK},          // NSFontWeightBlack
   };
+
   base::ScopedCFTypeRef<CFDictionaryRef> traits(
       CTFontCopyTraits(base::mac::NSToCFCast(font)));
   DCHECK(traits);
@@ -125,20 +147,18 @@
   if (!cf_weight)
     return Font::Weight::NORMAL;
 
-  // Documentation is vague about what sized floating point type should be used.
-  // However, numeric_limits::epsilon() for 64-bit types is too small to match
-  // the above table, so use 32-bit float. Do not check for the success of
-  // CFNumberGetValue(). CFNumberGetValue() returns false for *any* loss of
-  // value, and a float is used here deliberately to coarsen the accuracy.
-  // There's no guarantee that any particular value for the kCTFontWeightTrait
-  // will be able to be accurately represented with a float.
-  float weight_value;
-  CFNumberGetValue(cf_weight, kCFNumberFloatType, &weight_value);
+  // The value of kCTFontWeightTrait empirically is a kCFNumberFloat64Type
+  // (double) on all tested versions of macOS. However, that doesn't really
+  // matter as only the first two decimal digits need to be tested. Do not check
+  // for the success of CFNumberGetValue() as it returns false for any loss of
+  // value and all that is needed here is two digits of accuracy.
+  CGFloat weight;
+  CFNumberGetValue(cf_weight, kCFNumberCGFloatType, &weight);
   for (const auto& item : weight_map) {
-    if (weight_value - item.ct_weight <= std::numeric_limits<float>::epsilon())
+    if (item.weight_lower <= weight && weight <= item.weight_upper)
       return item.gfx_weight;
   }
-  return Font::Weight::BLACK;
+  return Font::Weight::INVALID;
 }
 
 // Returns an autoreleased NSFont created with the passed-in specifications.
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index 91c134b..9b0d5c7 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -12,7 +12,6 @@
 /** @const */ var SCREEN_WELCOME = 'connect';
 /** @const */ var SCREEN_OOBE_NETWORK = 'network-selection';
 /** @const */ var SCREEN_OOBE_HID_DETECTION = 'hid-detection';
-/** @const */ var SCREEN_OOBE_EULA = 'eula';
 /** @const */ var SCREEN_OOBE_ENABLE_DEBUGGING = 'debugging';
 /** @const */ var SCREEN_OOBE_UPDATE = 'oobe-update';
 /** @const */ var SCREEN_OOBE_RESET = 'reset';
@@ -94,7 +93,6 @@
    */
   var RESET_AVAILABLE_SCREEN_GROUP = [
     SCREEN_OOBE_NETWORK,
-    SCREEN_OOBE_EULA,
     SCREEN_OOBE_AUTO_ENROLLMENT_CHECK,
     SCREEN_GAIA_SIGNIN,
     SCREEN_ACCOUNT_PICKER,
diff --git a/ui/views/PRESUBMIT.py b/ui/views/PRESUBMIT.py
index 93bfc642..7273cb19 100644
--- a/ui/views/PRESUBMIT.py
+++ b/ui/views/PRESUBMIT.py
@@ -16,8 +16,8 @@
 def CheckChangeLintsClean(input_api, output_api):
   """Makes sure that the change is cpplint clean."""
   sources = lambda x: input_api.FilterSourceFile(
-    x, white_list=INCLUDE_CPP_FILES_ONLY,
-    black_list=input_api.DEFAULT_BLACK_LIST)
+    x, files_to_check=INCLUDE_CPP_FILES_ONLY,
+    files_to_skip=input_api.DEFAULT_FILES_TO_SKIP)
   return input_api.canned_checks.CheckChangeLintsClean(
       input_api, output_api, sources, lint_filters=[], verbose_level=1)
 
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc
index eb3d12b..4f8d33641 100644
--- a/ui/views/window/dialog_delegate.cc
+++ b/ui/views/window/dialog_delegate.cc
@@ -213,16 +213,6 @@
   if (new_callback_present)
     return;
 
-  // Old-style close behavior: if the only button was Ok, call Accept();
-  // otherwise call Cancel(). Note that in this case the window is already going
-  // to close, so the return values of Accept()/Cancel(), which normally say
-  // whether the window should close, are ignored.
-  int buttons = GetDialogButtons();
-  if (buttons == ui::DIALOG_BUTTON_OK)
-    Accept();
-  else
-    Cancel();
-
   // This is set here instead of before the invocations of Accept()/Cancel() so
   // that those methods can DCHECK that !already_started_close_. Otherwise,
   // client code could (eg) call Accept() from inside the cancel callback, which
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h
index 1cffa6b..c4364e1 100644
--- a/ui/views/window/dialog_delegate.h
+++ b/ui/views/window/dialog_delegate.h
@@ -119,19 +119,16 @@
   virtual bool IsDialogButtonEnabled(ui::DialogButton button) const;
 
   // For Dialog boxes, if there is a "Cancel" button or no dialog button at all,
-  // this is called when the user presses the "Cancel" button.
-  // It can also be called on a close action if |Close| has not been
-  // overridden. This function should return true if the window can be closed
-  // after it returns, or false if it must remain open. By default, return true
-  // without doing anything.
+  // this is called when the user presses the "Cancel" button.  This function
+  // should return true if the window can be closed after it returns, or false
+  // if it must remain open. By default, return true without doing anything.
   // DEPRECATED: use |SetCancelCallback| instead.
   virtual bool Cancel();
 
-  // For Dialog boxes, this is called when the user presses the "OK" button,
-  // or the Enter key. It can also be called on a close action if |Close|
-  // has not been overridden. This function should return true if the window
-  // can be closed after it returns, or false if it must remain open. By
-  // default, return true without doing anything.
+  // For Dialog boxes, this is called when the user presses the "OK" button, or
+  // the Enter key. This function should return true if the window can be closed
+  // after it returns, or false if it must remain open. By default, return true
+  // without doing anything.
   // DEPRECATED: use |SetAcceptCallback| instead.
   virtual bool Accept();
 
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py
index c375ef3b7..300806a9 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py
+++ b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/PRESUBMIT.py
@@ -149,7 +149,7 @@
 
 def CheckChangeOnUpload(input_api, output_api):
   filter_lambda = lambda x: input_api.FilterSourceFile(
-      x, white_list=[r'.*\.aidl$' ])
+      x, files_to_check=[r'.*\.aidl$' ])
   aidl_files = []
   for f in input_api.AffectedFiles(include_deletes=False,
                                    file_filter=filter_lambda):