diff --git a/AUTHORS b/AUTHORS
index a2a305f2..6ef7b10 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -262,6 +262,7 @@
 Dillon Sellars <dill.sellars@gmail.com>
 Divya Bansal <divya.bansal@samsung.com>
 Dmitry Shachnev <mitya57@gmail.com>
+Dmitry Sokolov <dimanne@gmail.com>
 Dominic Farolino <domfarolino@gmail.com>
 Dominic Jodoin <dominic.jodoin@gmail.com>
 Dominik Röttsches <dominik.rottsches@intel.com>
diff --git a/DEPS b/DEPS
index fea6c6f..e7fc0abb 100644
--- a/DEPS
+++ b/DEPS
@@ -195,11 +195,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'e96cdd18ac5ff04774b55775bf66f1f3ccbe4d62',
+  'skia_revision': '842805ced156080fd25bfbb6410851dbe6a8b447',
   # 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': '95c0414b1889f2d761e26024a8a040d647f81854',
+  'v8_revision': 'fa4bfe45ff53e2c21b96728ef9132c40969b3159',
   # 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,11 +207,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '2663e6012911a3dc3e978a41f7c52d5c12c48c69',
+  'angle_revision': 'dbb090f41f9b9017a88ba0ae44a09bdebd4b9dda',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '44be0942f9a8b965f877f294f1c2d8fb15f88ec6',
+  'swiftshader_revision': '1075baee443cbfd02714d7d3793d194fd227d476',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -258,7 +258,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '18d69fb4e7b2225974dfc306ca0c11a58fe4e917',
+  'catapult_revision': '0f6ed710764d9858eb9d2ad2a2f92fde89d1634b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # 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': '0d33d0e062db344a70d991abee0e4163d5c66137',
+  'devtools_frontend_revision': '5c1904772b3655454d1da01210b83e6fa5fbceb2',
   # 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.
@@ -302,7 +302,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '4b07d50cd9a0a537ccb28252227f87d36273cf53',
+  'spv_tools_revision': 'c6ca885c0b4af75735944c725be56b642a77b17d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -318,7 +318,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '62139fcca727c3592b65be32c0146ca1a3a195cc',
+  'dawn_revision': 'b2a4e87ad27403bcb0113406ba935477baae4a8c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -901,7 +901,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ead81e2ba233835d7feb4dd6158014a1c3962ecb',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '991ead187c148de57990cbeecb9ad35767987a7c',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1254,7 +1254,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '88c194fccd3bfdcff22b4dfd0987230a433b5e96',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '76404b01d5314c251218a4a34111a1aa8a3803ad',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1332,7 +1332,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'FfxmX7LQ9OID3pVAmcemr6u9lK3xjXzAXxvqzEcclMwC'
+              'version': 'oJeWXQJJ1lVY6P7l39pBV-mrbeWlw0swPZQuNmcix5AC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 2a6c7ac..d5e7790 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -420,6 +420,11 @@
             ::switches::kEnableCrashReporterForTesting)) {
       command_line->AppendSwitch(::switches::kEnableCrashReporterForTesting);
     }
+    // Pass WebView's force little cores flag to renderer process.
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            ::switches::kWebViewForceLittleCores)) {
+      command_line->AppendSwitch(::switches::kWebViewForceLittleCores);
+    }
   }
 }
 
diff --git a/android_webview/common/aw_switches.cc b/android_webview/common/aw_switches.cc
index 8372ebc3..1436c2d 100644
--- a/android_webview/common/aw_switches.cc
+++ b/android_webview/common/aw_switches.cc
@@ -49,4 +49,7 @@
 // variations seed.
 const char kFinchSeedMinUpdatePeriod[] = "finch-seed-min-update-period";
 
+// Force WebView renderer to run in little cores
+const char kWebViewForceLittleCores[] = "webview-force-little-cores";
+
 }  // namespace switches
diff --git a/android_webview/common/aw_switches.h b/android_webview/common/aw_switches.h
index c883e89..c639426 100644
--- a/android_webview/common/aw_switches.h
+++ b/android_webview/common/aw_switches.h
@@ -18,6 +18,7 @@
 extern const char kFinchSeedIgnorePendingDownload[];
 extern const char kFinchSeedMinDownloadPeriod[];
 extern const char kFinchSeedMinUpdatePeriod[];
+extern const char kWebViewForceLittleCores[];
 
 }  // namespace switches
 
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index c27c16ec..1395555 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -88,5 +88,7 @@
                             + "Elements v0, and HTML Imports)."),
             Flag.baseFeature(AwFeatures.WEBVIEW_DISPLAY_CUTOUT,
                     "Enables display cutout (notch) support in WebView for Android P and above."),
+            Flag.commandLine(AwSwitches.WEBVIEW_FORCE_LITTLE_CORES,
+                    "Forces WebView to do rendering work in little cores"),
     };
 }
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index 6007355..e4e5262a 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -28,6 +28,7 @@
 #include "base/check_op.h"
 #include "base/command_line.h"
 #include "base/cpu.h"
+#include "base/cpu_affinity_posix.h"
 #include "base/i18n/icu_util.h"
 #include "base/i18n/rtl.h"
 #include "base/posix/global_descriptors.h"
@@ -298,6 +299,10 @@
 
   if (process_type == switches::kRendererProcess) {
     InitResourceBundleRendererSide();
+    if (command_line.HasSwitch(switches::kWebViewForceLittleCores)) {
+      base::SetProcessCpuAffinityMode(base::GetCurrentProcessHandle(),
+                                      base::CpuAffinityMode::kLittleCoresOnly);
+    }
   }
 
   EnableCrashReporter(process_type);
diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
index 134f978..0f3b83c 100644
--- a/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
+++ b/ash/public/cpp/external_arc/message_center/arc_notification_content_view.cc
@@ -249,7 +249,7 @@
       control_buttons_view_(message_view) {
   DCHECK(message_view);
 
-  // kNotificationWidth must be 360, since this value is separately defiend in
+  // kNotificationWidth must be 360, since this value is separately defined in
   // ArcNotificationWrapperView class in Android side.
   DCHECK_EQ(360, message_center::kNotificationWidth);
 
@@ -348,7 +348,7 @@
     return;
 
   // Add the guard to prevent an infinite loop. Changing visibility may generate
-  // an event and it may call thie method again.
+  // an event and it may call this method again.
   base::AutoReset<bool> reset(&updating_control_buttons_visibility_, true);
 
   if (target_visibility)
@@ -559,7 +559,8 @@
 
   auto mask_painter =
       std::make_unique<message_center::NotificationBackgroundPainter>(
-          top_radius_, bottom_radius_);
+          top_radius_, bottom_radius_,
+          message_center::kNotificationBackgroundColor);
   // Set insets to round visible notification corners. https://crbug.com/866777
   mask_painter->set_insets(new_insets);
 
diff --git a/ash/public/cpp/external_arc/message_center/arc_notification_content_view_unittest.cc b/ash/public/cpp/external_arc/message_center/arc_notification_content_view_unittest.cc
index da7bd1fd..891584e 100644
--- a/ash/public/cpp/external_arc/message_center/arc_notification_content_view_unittest.cc
+++ b/ash/public/cpp/external_arc/message_center/arc_notification_content_view_unittest.cc
@@ -29,6 +29,7 @@
 #include "components/exo/buffer.h"
 #include "components/exo/keyboard.h"
 #include "components/exo/keyboard_delegate.h"
+#include "components/exo/keyboard_modifiers.h"
 #include "components/exo/notification_surface.h"
 #include "components/exo/seat.h"
 #include "components/exo/surface.h"
@@ -40,6 +41,7 @@
 #include "ui/aura/window.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/message_center/public/cpp/notification.h"
 #include "ui/message_center/views/message_view_factory.h"
 #include "ui/message_center/views/notification_control_buttons_view.h"
@@ -75,15 +77,15 @@
               OnKeyboardKey,
               (base::TimeTicks, ui::DomCode, bool),
               (override));
-  MOCK_METHOD(void, OnKeyboardModifiers, (int), (override));
+  MOCK_METHOD(void,
+              OnKeyboardModifiers,
+              (const exo::KeyboardModifiers&),
+              (override));
   MOCK_METHOD(void,
               OnKeyRepeatSettingsChanged,
               (bool, base::TimeDelta, base::TimeDelta),
               (override));
-  MOCK_METHOD(void,
-              OnKeyboardLayoutUpdated,
-              (const std::string& layout_name),
-              (override));
+  MOCK_METHOD(void, OnKeyboardLayoutUpdated, (base::StringPiece), (override));
 };
 
 class FakeNotificationSurface : public exo::NotificationSurface {
diff --git a/build/protoc_java.py b/build/protoc_java.py
index e6147d8b..fe602a9 100755
--- a/build/protoc_java.py
+++ b/build/protoc_java.py
@@ -5,7 +5,7 @@
 
 """Generate java source files from protobuf files.
 
-This is a helper file for the genproto_java action in protoc_java.gypi.
+This is the action script for the proto_java_library template.
 
 It performs the following steps:
 1. Deletes all old sources (ensures deleted classes are not part of new jars).
@@ -17,51 +17,63 @@
 
 from __future__ import print_function
 
+import argparse
 import os
-import optparse
 import shutil
 import subprocess
 import sys
 
-sys.path.append(os.path.join(os.path.dirname(__file__), "android", "gyp"))
+sys.path.append(os.path.join(os.path.dirname(__file__), 'android', 'gyp'))
 from util import build_utils
 
+
+def _HasJavaPackage(proto_lines):
+  return any(line.strip().startswith('option java_package')
+             for line in proto_lines)
+
+
+def _EnforceJavaPackage(proto_srcs):
+  for proto_path in proto_srcs:
+    with open(proto_path) as in_proto:
+      if not _HasJavaPackage(in_proto.readlines()):
+        raise Exception('Proto files for java must contain a "java_package" '
+                        'line: {}'.format(proto_path))
+
+
 def main(argv):
-  parser = optparse.OptionParser()
+  parser = argparse.ArgumentParser()
   build_utils.AddDepfileOption(parser)
-  parser.add_option("--protoc", help="Path to protoc binary.")
-  parser.add_option("--proto-path", help="Path to proto directory.")
-  parser.add_option("--java-out-dir",
-      help="Path to output directory for java files.")
-  parser.add_option("--srcjar", help="Path to output srcjar.")
-  parser.add_option("--stamp", help="File to touch on success.")
-  parser.add_option("--nano",
-      help="Use to generate nano protos.", action='store_true')
-  parser.add_option("--import-dir", action="append", default=[],
-                    help="Extra import directory for protos, can be repeated.")
-  options, args = parser.parse_args(argv)
+  parser.add_argument('--protoc', required=True, help='Path to protoc binary.')
+  parser.add_argument('--proto-path',
+                      required=True,
+                      help='Path to proto directory.')
+  parser.add_argument('--java-out-dir',
+                      help='Path to output directory for java files.')
+  parser.add_argument('--srcjar', help='Path to output srcjar.')
+  parser.add_argument('--stamp', help='File to touch on success.')
+  parser.add_argument(
+      '--import-dir',
+      action='append',
+      default=[],
+      help='Extra import directory for protos, can be repeated.')
+  parser.add_argument('protos', nargs='+', help='proto source files')
+  options = parser.parse_args(argv)
 
-  build_utils.CheckOptions(options, parser, ['protoc', 'proto_path'])
   if not options.java_out_dir and not options.srcjar:
-    print('One of --java-out-dir or --srcjar must be specified.')
-    return 1
+    raise Exception('One of --java-out-dir or --srcjar must be specified.')
 
-  proto_path_args = ['--proto_path', options.proto_path]
-  for path in options.import_dir:
-    proto_path_args += ["--proto_path", path]
+  _EnforceJavaPackage(options.protos)
 
   with build_utils.TempDir() as temp_dir:
-    if options.nano:
-      # Specify arguments to the generator.
-      generator_args = ['optional_field_style=reftypes',
-                        'store_unknown_fields=true']
-      out_arg = '--javanano_out=' + ','.join(generator_args) + ':' + temp_dir
-    else:
-      out_arg = '--java_out=lite:' + temp_dir
+    out_arg = '--java_out=lite:' + temp_dir
+
+    proto_path_args = ['--proto_path', options.proto_path]
+    for path in options.import_dir:
+      proto_path_args += ["--proto_path", path]
 
     # Generate Java files using protoc.
     build_utils.CheckOutput(
-        [options.protoc] + proto_path_args + [out_arg] + args,
+        [options.protoc] + proto_path_args + [out_arg] + options.protos,
         # protoc generates superfluous warnings about LITE_RUNTIME deprecation
         # even though we are using the new non-deprecated method.
         stderr_filter=lambda output: build_utils.FilterLines(
@@ -76,7 +88,7 @@
 
   if options.depfile:
     assert options.srcjar
-    deps = args + [options.protoc]
+    deps = options.protos + [options.protoc]
     build_utils.WriteDepfile(options.depfile, options.srcjar, deps)
 
   if options.stamp:
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index 369a6e4..ee42e6f 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -709,6 +709,7 @@
   "java/res/drawable/ic_signal_cellular_2_bar.xml",
   "java/res/drawable/ic_signal_cellular_3_bar.xml",
   "java/res/drawable/ic_signal_cellular_4_bar.xml",
+  "java/res/drawable/ic_signout_40dp.xml",
   "java/res/drawable/ic_site_timer.xml",
   "java/res/drawable/ic_swap_vert_round.xml",
   "java/res/drawable/ic_sync_badge_error_20dp.xml",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
index ef0672e..d22bd23 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -37,6 +37,7 @@
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver;
 import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
@@ -204,13 +205,6 @@
                 if (newState != BottomSheetController.SheetState.SCROLLING) {
                     maybeShowHeaderChips();
                 }
-
-                if (newState == BottomSheetController.SheetState.HIDDEN) {
-                    AssistantBottomBarDelegate delegate = mModel.getBottomBarDelegate();
-                    if (delegate != null) {
-                        delegate.onBottomSheetDismissed();
-                    }
-                }
             }
 
             @Override
@@ -224,6 +218,14 @@
             public void onSheetOffsetChanged(float heightFraction, float offsetPx) {
                 updateVisualViewportHeight();
             }
+
+            @Override
+            public void onSheetClosed(@StateChangeReason int reason) {
+                AssistantBottomBarDelegate delegate = mModel.getBottomBarDelegate();
+                if (reason == StateChangeReason.SWIPE && delegate != null) {
+                    delegate.onBottomSheetClosedWithSwipe();
+                }
+            }
         };
         controller.addObserver(mBottomSheetObserver);
 
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarDelegate.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarDelegate.java
index 6fb9de1..1486979 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarDelegate.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarDelegate.java
@@ -13,6 +13,9 @@
     // the new bottom sheet state and have the logic to shutdown there. Currently, this would be
     // tricky to do because it would interfere with the existing Controller::SetBottomSheetState
     // method and in particular tab switching.
-    /** The bottom sheet was dismissed. */
-    void onBottomSheetDismissed();
+    /**
+     * The bottom sheet was closed with a swipe gesture. Note that this will be fired both when
+     * going into the PEEK state as well as when dismissing the sheet altogether.
+     */
+    void onBottomSheetClosedWithSwipe();
 }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarNativeDelegate.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarNativeDelegate.java
index 3109e2c..6c75215c 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarNativeDelegate.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarNativeDelegate.java
@@ -32,9 +32,9 @@
     }
 
     @Override
-    public void onBottomSheetDismissed() {
+    public void onBottomSheetClosedWithSwipe() {
         if (mNativeAssistantBottomBarDelegate != 0) {
-            AssistantBottomBarNativeDelegateJni.get().onBottomSheetDismissed(
+            AssistantBottomBarNativeDelegateJni.get().onBottomSheetClosedWithSwipe(
                     mNativeAssistantBottomBarDelegate, AssistantBottomBarNativeDelegate.this);
         }
     }
@@ -48,7 +48,7 @@
     interface Natives {
         boolean onBackButtonClicked(
                 long nativeAssistantBottomBarDelegate, AssistantBottomBarNativeDelegate caller);
-        void onBottomSheetDismissed(
+        void onBottomSheetClosedWithSwipe(
                 long nativeAssistantBottomBarDelegate, AssistantBottomBarNativeDelegate caller);
     }
 }
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 dbb66da..5c37989 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
@@ -111,7 +111,7 @@
                     }
 
                     @Override
-                    public void onBottomSheetDismissed() {}
+                    public void onBottomSheetClosedWithSwipe() {}
                 });
         initContent(callback);
         BottomSheetUtils.showContentAndMaybeExpand(
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
index 78ad982..4619e8d 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -166,7 +166,8 @@
                         dismissSnackbar();
 
                         if (tab == null) {
-                            safeOnTabSwitched(getModel().getBottomSheetState());
+                            safeOnTabSwitched(getModel().getBottomSheetState(),
+                                    /* activityChanged = */ false);
                             // A null tab indicates that there's no selected tab; Most likely, we're
                             // in the process of selecting a new tab. Hide the UI for possible reuse
                             // later.
@@ -183,7 +184,8 @@
                             }
                         } else {
                             //
-                            safeOnTabSwitched(getModel().getBottomSheetState());
+                            safeOnTabSwitched(getModel().getBottomSheetState(),
+                                    /* activityChanged = */ false);
                             // A new tab was selected. If Autofill Assistant is running on it,
                             // attach the UI to that other instance, otherwise destroy the UI.
                             AutofillAssistantClient.fromWebContents(mWebContents)
@@ -205,7 +207,8 @@
                                 return;
                             }
 
-                            safeOnTabSwitched(getModel().getBottomSheetState());
+                            safeOnTabSwitched(
+                                    getModel().getBottomSheetState(), /* activityChanged = */ true);
                             // If we have an open snackbar, execute the callback immediately. This
                             // may shut down the Autofill Assistant.
                             if (mSnackbarController != null) {
@@ -481,10 +484,10 @@
         }
     }
 
-    private void safeOnTabSwitched(@SheetState int state) {
+    private void safeOnTabSwitched(@SheetState int state, boolean activityChanged) {
         if (mNativeUiController != 0) {
-            AutofillAssistantUiControllerJni.get().onTabSwitched(
-                    mNativeUiController, AutofillAssistantUiController.this, state);
+            AutofillAssistantUiControllerJni.get().onTabSwitched(mNativeUiController,
+                    AutofillAssistantUiController.this, state, activityChanged);
         }
     }
 
@@ -514,7 +517,7 @@
         void setVisible(long nativeUiControllerAndroid, AutofillAssistantUiController caller,
                 boolean visible);
         void onTabSwitched(long nativeUiControllerAndroid, AutofillAssistantUiController caller,
-                @SheetState int state);
+                @SheetState int state, boolean activityChanged);
         void onTabSelected(long nativeUiControllerAndroid, AutofillAssistantUiController caller);
     }
 }
diff --git a/chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java b/chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
index 4089881f..e38652f2 100644
--- a/chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
+++ b/chrome/android/features/start_surface/public/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
@@ -6,6 +6,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.Log;
 import org.chromium.base.SysUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.flags.BooleanCachedFieldTrialParameter;
@@ -25,6 +26,7 @@
  * which variation should be used.
  */
 public class StartSurfaceConfiguration {
+    private static final String TAG = "StartSurfaceConfig";
     public static final StringCachedFieldTrialParameter START_SURFACE_VARIATION =
             new StringCachedFieldTrialParameter(
                     ChromeFeatureList.START_SURFACE_ANDROID, "start_surface_variation", "");
@@ -144,7 +146,7 @@
      */
     public static void recordHistogram(String name, long timeDurationMs, boolean isInstantStart) {
         if (timeDurationMs < 0) return;
-
+        Log.i(TAG, "Recorded %s = %d ms", getHistogramName(name, isInstantStart), timeDurationMs);
         RecordHistogram.recordTimesHistogram(
                 getHistogramName(name, isInstantStart), timeDurationMs);
     }
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedDataInjectRule.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedDataInjectRule.java
index 6a5e29d..e7d316a 100644
--- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedDataInjectRule.java
+++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/FeedDataInjectRule.java
@@ -41,8 +41,7 @@
  *     public FeedDataInjectRule mDataInjector = new FeedDataInjectRule();
  *
  *     @Rule
- *     public ChromeActivityTestRule<ChromeTabbedActivity> mActivityTestRule =
- *         new ChromeActivityTestRule(ChromeTabbedActivity.class);
+ *     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
  *
  *     @Test
  *     @Feature({"FeedNewTabPage"})
@@ -58,13 +57,8 @@
  * }
  * }
  * </pre>
- *
- * Note when using this test rule, do not also use ChromeTabbedActivityTestRule.
- * ChromeTabbedActivityTestRule also try to set a default feed response file and
- * it could results to strange behaviors in test, such as always see the same
- * set of cards in each test case.
  */
-final class FeedDataInjectRule extends TestWatcher {
+public final class FeedDataInjectRule extends TestWatcher {
     private static final String TAG = "FeedDataInjectRule";
     private static final int FIRST_CARD_BASE_POSITION = 2;
 
diff --git a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/tooltip/FeedTooltipTest.java b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/tooltip/FeedTooltipTest.java
index 26c8799..046f84e4 100644
--- a/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/tooltip/FeedTooltipTest.java
+++ b/chrome/android/feed/core/javatests/src/org/chromium/chrome/browser/feed/tooltip/FeedTooltipTest.java
@@ -21,7 +21,6 @@
 import androidx.test.espresso.matcher.RootMatchers;
 import androidx.test.filters.MediumTest;
 
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -31,7 +30,8 @@
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.feed.FeedProcessScopeFactory;
+import org.chromium.chrome.browser.feed.DataFilePath;
+import org.chromium.chrome.browser.feed.FeedDataInjectRule;
 import org.chromium.chrome.browser.feed.shared.stream.Stream;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -64,8 +64,10 @@
     private static final int FIRST_CARD_POSITION = 3;
 
     @Rule
-    public ChromeTabbedActivityTestRule mActivityTestRule =
-            new ChromeTabbedActivityTestRule(FEED_TEST_RESPONSE_FILE_PATH);
+    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+
+    @Rule
+    public FeedDataInjectRule mFeedDataInjector = new FeedDataInjectRule(false);
 
     @Rule
     public SuggestionsDependenciesRule mSuggestionsDeps = new SuggestionsDependenciesRule();
@@ -105,14 +107,10 @@
         mStream.addOnContentChangedListener(mTestObserver);
     }
 
-    @After
-    public void tearDown() {
-        FeedProcessScopeFactory.setTestNetworkClient(null);
-    }
-
     @Test
     @MediumTest
     @Feature({"FeedNewTabPage"})
+    @DataFilePath(FEED_TEST_RESPONSE_FILE_PATH)
     public void testShowTooltip() throws Exception {
         int callCount = mTestObserver.firstCardShownCallback.getCallCount();
         TestThreadUtils.runOnUiThreadBlocking(() -> mStream.triggerRefresh());
diff --git a/chrome/android/java/res/drawable/ic_signout_40dp.xml b/chrome/android/java/res/drawable/ic_signout_40dp.xml
new file mode 100644
index 0000000..30ad189
--- /dev/null
+++ b/chrome/android/java/res/drawable/ic_signout_40dp.xml
@@ -0,0 +1,18 @@
+<?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. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:width="40dp"
+    android:height="40dp"
+    android:viewportWidth="40"
+    android:viewportHeight="40"
+    tools:targetApi="21">
+
+  <path
+      android:pathData="M24.166 15.833l-1.175 1.175 2.15 2.159h-8.474v1.666h8.474l-2.15 2.15 1.175 1.184L28.334 20l-4.166-4.167zm-10.833-1.666H20V12.5h-6.667c-0.917 0-1.667 0.75-1.667 1.667v11.666c0 0.917 0.75 1.667 1.667 1.667H20v-1.667h-6.667V14.167z"
+      android:fillColor="@color/default_icon_color_secondary"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
index 8f958b6..752c7f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
@@ -197,6 +197,10 @@
             getPreferenceScreen().removePreference(signOutPreference);
             getPreferenceScreen().removePreference(findPreference(PREF_SIGN_OUT_DIVIDER));
         } else {
+            if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)) {
+                signOutPreference.setLayoutResource(R.layout.account_management_account_row);
+                signOutPreference.setIcon(R.drawable.ic_signout_40dp);
+            }
             signOutPreference.setTitle(getSignOutPreferenceText());
             signOutPreference.setEnabled(getSignOutAllowedPreferenceValue());
             signOutPreference.setOnPreferenceClickListener(preference -> {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
index 9dbed005..95671c3 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java
@@ -12,20 +12,18 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.MockitoAnnotations.initMocks;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 import org.mockito.stubbing.Answer;
 import org.robolectric.annotation.Config;
 
@@ -54,65 +52,66 @@
     @Rule
     public final JniMocker mocker = new JniMocker();
 
-    @Mock
-    SigninManager.Natives mNativeMock;
+    private static final AccountInfo ACCOUNT_INFO = new AccountInfo(
+            new CoreAccountId("gaia-id-user"), "user@domain.com", "gaia-id-user", null);
 
-    private AccountTrackerService mAccountTrackerService;
+    private final SigninManager.Natives mNativeMock = mock(SigninManager.Natives.class);
+    private final AccountTrackerService mAccountTrackerService = mock(AccountTrackerService.class);
+    private final IdentityMutator mIdentityMutator = mock(IdentityMutator.class);
+    private final AndroidSyncSettings mAndroidSyncSettings = mock(AndroidSyncSettings.class);
+    private final ExternalAuthUtils mExternalAuthUtils = mock(ExternalAuthUtils.class);
     private IdentityManager mIdentityManager;
-    private IdentityMutator mIdentityMutator;
+
     private SigninManager mSigninManager;
-    private CoreAccountInfo mAccount;
-    private AndroidSyncSettings mAndroidSyncSettings;
 
     @Before
     public void setUp() {
-        initMocks(this);
-
         mocker.mock(SigninManagerJni.TEST_HOOKS, mNativeMock);
 
         doReturn(true).when(mNativeMock).isSigninAllowedByPolicy(anyLong());
-
-        mAccountTrackerService = mock(AccountTrackerService.class);
-
-        mIdentityMutator = mock(IdentityMutator.class);
+        // Pretend Google Play services are available as it is required for the sign-in
+        doReturn(false).when(mExternalAuthUtils).isGooglePlayServicesMissing(any());
 
         mIdentityManager = spy(
                 new IdentityManager(0 /* nativeIdentityManager */, null /* OAuth2TokenService */));
-
-        mAndroidSyncSettings = mock(AndroidSyncSettings.class);
-
-        ExternalAuthUtils externalAuthUtils = mock(ExternalAuthUtils.class);
-        // Pretend Google Play services are available as it is required for the sign-in
-        doReturn(false).when(externalAuthUtils).isGooglePlayServicesMissing(any());
-
         doReturn(null).when(mIdentityManager).getPrimaryAccountInfo(anyInt());
+    }
+
+    @After
+    public void tearDown() {
+        if (mSigninManager != null) {
+            mSigninManager.destroy();
+            mSigninManager = null;
+        }
+    }
+
+    private void createSigninManager() {
         mSigninManager = new SigninManager(0 /* nativeSigninManagerAndroid */,
                 mAccountTrackerService, mIdentityManager, mIdentityMutator, mAndroidSyncSettings,
-                externalAuthUtils);
-
-        mAccount = new AccountInfo(
-                new CoreAccountId("gaia-id-user"), "user@domain.com", "gaia-id-user", null);
+                mExternalAuthUtils);
     }
 
     @Test
     public void signinAndTurnSyncOn() {
         doReturn(true).when(mAccountTrackerService).checkAndSeedSystemAccounts();
-        doReturn(mAccount)
+        doReturn(ACCOUNT_INFO)
                 .when(mIdentityManager)
                 .findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress(
-                        eq(mAccount.getEmail()));
+                        eq(ACCOUNT_INFO.getEmail()));
         doReturn(true).when(mIdentityMutator).setPrimaryAccount(any(), anyInt());
 
+        createSigninManager();
         mSigninManager.onFirstRunCheckDone();
 
         SigninManager.SignInCallback callback = mock(SigninManager.SignInCallback.class);
-        mSigninManager.signinAndEnableSync(SigninAccessPoint.START_PAGE, mAccount, callback);
+        mSigninManager.signinAndEnableSync(SigninAccessPoint.START_PAGE, ACCOUNT_INFO, callback);
 
-        verify(mNativeMock).fetchAndApplyCloudPolicy(anyLong(), eq(mAccount), any());
+        verify(mNativeMock).fetchAndApplyCloudPolicy(anyLong(), eq(ACCOUNT_INFO), any());
 
         mSigninManager.finishSignInAfterPolicyEnforced();
-        verify(mIdentityMutator).setPrimaryAccount(mAccount.getId(), ConsentLevel.SYNC);
-        verify(mAndroidSyncSettings).updateAccount(CoreAccountInfo.getAndroidAccountFrom(mAccount));
+        verify(mIdentityMutator).setPrimaryAccount(ACCOUNT_INFO.getId(), ConsentLevel.SYNC);
+        verify(mAndroidSyncSettings)
+                .updateAccount(CoreAccountInfo.getAndroidAccountFrom(ACCOUNT_INFO));
         verify(mAndroidSyncSettings).enableChromeSync();
         // Signin should be complete and callback should be invoked.
         verify(callback).onSignInComplete();
@@ -122,21 +121,22 @@
     @Test
     public void signinNoTurnSyncOn() {
         doReturn(true).when(mAccountTrackerService).checkAndSeedSystemAccounts();
-        doReturn(mAccount)
+        doReturn(ACCOUNT_INFO)
                 .when(mIdentityManager)
                 .findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress(
-                        eq(mAccount.getEmail()));
+                        eq(ACCOUNT_INFO.getEmail()));
         doReturn(true).when(mIdentityMutator).setPrimaryAccount(any(), anyInt());
 
+        createSigninManager();
         mSigninManager.onFirstRunCheckDone();
 
         SigninManager.SignInCallback callback = mock(SigninManager.SignInCallback.class);
-        mSigninManager.signin(mAccount, callback);
+        mSigninManager.signin(ACCOUNT_INFO, callback);
 
         // Signin without turning on sync shouldn't apply policies.
         verify(mNativeMock, never()).fetchAndApplyCloudPolicy(anyLong(), any(), any());
 
-        verify(mIdentityMutator).setPrimaryAccount(mAccount.getId(), ConsentLevel.NOT_REQUIRED);
+        verify(mIdentityMutator).setPrimaryAccount(ACCOUNT_INFO.getId(), ConsentLevel.NOT_REQUIRED);
 
         verify(mAndroidSyncSettings, never()).updateAccount(any());
         verify(mAndroidSyncSettings, never()).enableChromeSync();
@@ -147,14 +147,10 @@
 
     @Test
     public void signOutFromJavaWithManagedDomain() {
-        // Stub out various native calls. Some of these are verified as never called
-        // and those stubs simply allow that verification to catch any issues.
-        doNothing().when(mNativeMock).wipeProfileData(anyLong(), any());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(anyLong(), any());
-
         // See verification of nativeWipeProfileData below.
         doReturn("TestDomain").when(mNativeMock).getManagementDomain(anyLong());
 
+        createSigninManager();
         // Trigger the sign out flow!
         mSigninManager.signOut(SignoutReason.SIGNOUT_TEST);
 
@@ -164,7 +160,7 @@
         verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(anyLong(), any());
 
         // Simulate native callback to trigger clearing of account data.
-        mIdentityManager.onPrimaryAccountCleared(mAccount);
+        mIdentityManager.onPrimaryAccountCleared(ACCOUNT_INFO);
 
         // Sign-out should only clear the profile when the user is managed.
         verify(mNativeMock, times(1)).wipeProfileData(anyLong(), any());
@@ -173,15 +169,10 @@
 
     @Test
     public void signOutFromJavaWithNullDomain() {
-        // Stub out various native calls. Some of these are verified as never called
-        // and those stubs simply allow that verification to catch any issues.
-        doNothing().when(mNativeMock).wipeProfileData(anyLong(), any());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(anyLong(), any());
-
-        // See verification of nativeWipeGoogleServiceWorkerCaches below.
+        // Simulate sign-out with non-managed account.
         doReturn(null).when(mNativeMock).getManagementDomain(anyLong());
 
-        // Trigger the sign out flow!
+        createSigninManager();
         mSigninManager.signOut(SignoutReason.SIGNOUT_TEST);
 
         // PrimaryAccountCleared should be called *before* clearing any account data.
@@ -190,7 +181,7 @@
         verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(anyLong(), any());
 
         // Simulate native callback to trigger clearing of account data.
-        mIdentityManager.onPrimaryAccountCleared(mAccount);
+        mIdentityManager.onPrimaryAccountCleared(ACCOUNT_INFO);
 
         // Sign-out should only clear the service worker cache when the user is not managed.
         verify(mNativeMock, never()).wipeProfileData(anyLong(), any());
@@ -199,15 +190,10 @@
 
     @Test
     public void signOutFromJavaWithNullDomainAndForceWipe() {
-        // Stub out various native calls. Some of these are verified as never called
-        // and those stubs simply allow that verification to catch any issues.
-        doNothing().when(mNativeMock).wipeProfileData(anyLong(), any());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(anyLong(), any());
-
         // See verification of nativeWipeGoogleServiceWorkerCaches below.
         doReturn(null).when(mNativeMock).getManagementDomain(anyLong());
 
-        // Trigger the sign out flow
+        createSigninManager();
         mSigninManager.signOut(SignoutReason.SIGNOUT_TEST, null, true);
 
         // PrimaryAccountCleared should be called *before* clearing any account data.
@@ -216,7 +202,7 @@
         verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(anyLong(), any());
 
         // Simulate native callback to trigger clearing of account data.
-        mIdentityManager.onPrimaryAccountCleared(mAccount);
+        mIdentityManager.onPrimaryAccountCleared(ACCOUNT_INFO);
 
         // Sign-out should only clear the service worker cache when the user is not managed.
         verify(mNativeMock, times(1)).wipeProfileData(anyLong(), any());
@@ -225,13 +211,9 @@
 
     @Test
     public void signOutFromNative() {
-        // Stub out various native calls. Some of these are verified as never called
-        // and those stubs simply allow that verification to catch any issues.
-        doNothing().when(mNativeMock).wipeProfileData(anyLong(), any());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(anyLong(), any());
-
-        // Trigger the sign out flow!
-        mIdentityManager.onPrimaryAccountCleared(mAccount);
+        createSigninManager();
+        // Simulate native initiating the sign-out.
+        mIdentityManager.onPrimaryAccountCleared(ACCOUNT_INFO);
 
         // Sign-out should only clear the profile when the user is managed.
         verify(mNativeMock, times(1)).wipeProfileData(anyLong(), any());
@@ -240,10 +222,8 @@
 
     @Test
     public void clearingAccountCookiesTriggersSignout() {
-        // Stub out various native calls. Some of these are verified as never called
-        // and those stubs simply allow that verification to catch any issues.
-        doNothing().when(mNativeMock).wipeProfileData(anyLong(), any());
-        doNothing().when(mNativeMock).wipeGoogleServiceWorkerCaches(anyLong(), any());
+        // Create SigninManager so it adds an observer for onAccountsCookieDeletedByUserAction.
+        createSigninManager();
 
         // Clearing cookies shouldn't do anything when there's no primary account.
         doReturn(null).when(mIdentityManager).getPrimaryAccountInfo(anyInt());
@@ -251,12 +231,14 @@
         verify(mIdentityMutator, never()).clearPrimaryAccount(anyInt(), anyInt(), anyInt());
 
         // Clearing cookies shouldn't do anything when there's sync account.
-        doReturn(mAccount).when(mIdentityManager).getPrimaryAccountInfo(anyInt());
+        doReturn(ACCOUNT_INFO).when(mIdentityManager).getPrimaryAccountInfo(anyInt());
         mIdentityManager.onAccountsCookieDeletedByUserAction();
         verify(mIdentityMutator, never()).clearPrimaryAccount(anyInt(), anyInt(), anyInt());
 
         // Clearing cookies when there's only an unconsented account should trigger sign-out.
-        doReturn(mAccount).when(mIdentityManager).getPrimaryAccountInfo(ConsentLevel.NOT_REQUIRED);
+        doReturn(ACCOUNT_INFO)
+                .when(mIdentityManager)
+                .getPrimaryAccountInfo(ConsentLevel.NOT_REQUIRED);
         doReturn(null).when(mIdentityManager).getPrimaryAccountInfo(ConsentLevel.SYNC);
         mIdentityManager.onAccountsCookieDeletedByUserAction();
         verify(mIdentityMutator)
@@ -270,6 +252,7 @@
 
     @Test
     public void callbackNotifiedWhenNoOperationIsInProgress() {
+        createSigninManager();
         assertFalse(mSigninManager.isOperationInProgress());
 
         AtomicInteger callCount = new AtomicInteger(0);
@@ -280,12 +263,13 @@
     @Test
     public void callbackNotifiedOnSignout() {
         doAnswer(invocation -> {
-            mIdentityManager.onPrimaryAccountCleared(mAccount);
+            mIdentityManager.onPrimaryAccountCleared(ACCOUNT_INFO);
             return null;
         })
                 .when(mIdentityMutator)
                 .clearPrimaryAccount(anyInt(), anyInt(), anyInt());
 
+        createSigninManager();
         mSigninManager.signOut(SignoutReason.SIGNOUT_TEST);
         assertTrue(mSigninManager.isOperationInProgress());
         AtomicInteger callCount = new AtomicInteger(0);
@@ -304,9 +288,6 @@
 
         // No need to seed accounts to the native code.
         doReturn(true).when(mAccountTrackerService).checkAndSeedSystemAccounts();
-        // Request that policy is loaded. It will pause sign-in until onPolicyCheckedBeforeSignIn is
-        // invoked.
-        doNothing().when(mNativeMock).fetchAndApplyCloudPolicy(anyLong(), any(), any());
 
         doReturn(account)
                 .when(mIdentityManager)
@@ -320,8 +301,8 @@
         doAnswer(setPrimaryAccountAnswer)
                 .when(mIdentityMutator)
                 .setPrimaryAccount(account.getId(), ConsentLevel.SYNC);
-        doNothing().when(mIdentityMutator).reloadAllAccountsFromSystemWithPrimaryAccount(any());
 
+        createSigninManager();
         mSigninManager.onFirstRunCheckDone(); // Allow sign-in.
 
         mSigninManager.signinAndEnableSync(SigninAccessPoint.UNKNOWN, account, null);
@@ -342,15 +323,13 @@
 
         // No need to seed accounts to the native code.
         doReturn(true).when(mAccountTrackerService).checkAndSeedSystemAccounts();
-        // Request that policy is loaded. It will pause sign-in until onPolicyCheckedBeforeSignIn is
-        // invoked.
-        doNothing().when(mNativeMock).fetchAndApplyCloudPolicy(anyLong(), any(), any());
 
         doReturn(account)
                 .when(mIdentityManager)
                 .findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress(any());
         doReturn(true).when(mIdentityManager).hasPrimaryAccount();
 
+        createSigninManager();
         mSigninManager.onFirstRunCheckDone(); // Allow sign-in.
 
         mSigninManager.signinAndEnableSync(SigninAccessPoint.UNKNOWN, account, null);
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index b03cce9..185a959a 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -2597,6 +2597,27 @@
   <message name="IDS_ENTERPRISE_LOGIN_ERROR_ALLOWLIST" desc="Couldn't sign in because user is not authorized by the administrator.">
     You are not authorized to use this device. Please contact the administrator for sign-in permission.
   </message>
+  <message name="IDS_LOCK_SCREEN_VERIFY_ACCOUNT" desc="Title of online account verification on the lock screen">
+    Verify account
+  </message>
+  <message name="IDS_LOCK_SCREEN_VERIFY_BUTTON" desc="Next button for online account verification on the lock screen">
+    Verify
+  </message>
+  <message name="IDS_LOCK_SCREEN_VERIFY_AGAIN_BUTTON" desc="Next button for 2nd online account verification on the lock screen">
+    Verify again
+  </message>
+  <message name="IDS_LOCK_SCREEN_CANCEL_BUTTON" desc="Cancel button for online account verification on the lock screen">
+    Cancel
+  </message>
+  <message name="IDS_LOCK_SCREEN_VERIFICATION_FAILED" desc="Title of incorrect user online reauthentication on the lock screen">
+    Verification was not successful
+  </message>
+  <message name="IDS_LOCK_SCREEN_WRONG_USER" desc="User that was not logged in tries to unlock the device">
+    The account you verified is not authorized to access this device. Please make sure you are verifying <ph name="ACCOUNT">$1<ex>test@example.com</ex></ph> to unlock the session.
+  </message>
+  <message name="IDS_LOCK_SCREEN_REAUTH_SUBTITLE" desc="Subtitle for lock screen user re-auth dialog">
+    Sign in to <ph name="ACCOUNT">$1<ex>test@example.com</ex></ph> again to verify this account
+  </message>
   <message name="IDS_LOGIN_ERROR_GOOGLE_ACCOUNT_NOT_ALLOWED" desc="Couldn't sign into Google account on the Active Directory managed device.">
     Sorry, Google accounts are not allowed on this device.
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_CANCEL_BUTTON.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_CANCEL_BUTTON.png.sha1
new file mode 100644
index 0000000..617ed8a
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_CANCEL_BUTTON.png.sha1
@@ -0,0 +1 @@
+078b283c6e11478112e9461ae86bf07a0f9aceb7
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_REAUTH_SUBTITLE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_REAUTH_SUBTITLE.png.sha1
new file mode 100644
index 0000000..617ed8a
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_REAUTH_SUBTITLE.png.sha1
@@ -0,0 +1 @@
+078b283c6e11478112e9461ae86bf07a0f9aceb7
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFICATION_FAILED.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFICATION_FAILED.png.sha1
new file mode 100644
index 0000000..5f4e4a5
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFICATION_FAILED.png.sha1
@@ -0,0 +1 @@
+9ae3a4fddbcc6f3f1533b1f366ff444fe6da91cb
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFY_ACCOUNT.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFY_ACCOUNT.png.sha1
new file mode 100644
index 0000000..617ed8a
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFY_ACCOUNT.png.sha1
@@ -0,0 +1 @@
+078b283c6e11478112e9461ae86bf07a0f9aceb7
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFY_AGAIN_BUTTON.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFY_AGAIN_BUTTON.png.sha1
new file mode 100644
index 0000000..5f4e4a5
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFY_AGAIN_BUTTON.png.sha1
@@ -0,0 +1 @@
+9ae3a4fddbcc6f3f1533b1f366ff444fe6da91cb
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFY_BUTTON.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFY_BUTTON.png.sha1
new file mode 100644
index 0000000..617ed8a
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_VERIFY_BUTTON.png.sha1
@@ -0,0 +1 @@
+078b283c6e11478112e9461ae86bf07a0f9aceb7
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_WRONG_USER.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_WRONG_USER.png.sha1
new file mode 100644
index 0000000..5f4e4a5
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_LOCK_SCREEN_WRONG_USER.png.sha1
@@ -0,0 +1 @@
+9ae3a4fddbcc6f3f1533b1f366ff444fe6da91cb
\ No newline at end of file
diff --git a/chrome/browser/android/autofill_assistant/assistant_bottom_bar_delegate.cc b/chrome/browser/android/autofill_assistant/assistant_bottom_bar_delegate.cc
index a76bc60f..76ea8b8 100644
--- a/chrome/browser/android/autofill_assistant/assistant_bottom_bar_delegate.cc
+++ b/chrome/browser/android/autofill_assistant/assistant_bottom_bar_delegate.cc
@@ -30,10 +30,10 @@
   return ui_controller_->OnBackButtonClicked();
 }
 
-void AssistantBottomBarDelegate::OnBottomSheetDismissed(
+void AssistantBottomBarDelegate::OnBottomSheetClosedWithSwipe(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller) {
-  ui_controller_->OnBottomSheetDismissed();
+  ui_controller_->OnBottomSheetClosedWithSwipe();
 }
 
 base::android::ScopedJavaGlobalRef<jobject>
diff --git a/chrome/browser/android/autofill_assistant/assistant_bottom_bar_delegate.h b/chrome/browser/android/autofill_assistant/assistant_bottom_bar_delegate.h
index 92d77d6..7665d32b 100644
--- a/chrome/browser/android/autofill_assistant/assistant_bottom_bar_delegate.h
+++ b/chrome/browser/android/autofill_assistant/assistant_bottom_bar_delegate.h
@@ -19,7 +19,7 @@
   bool OnBackButtonClicked(JNIEnv* env,
                            const base::android::JavaParamRef<jobject>& jcaller);
 
-  void OnBottomSheetDismissed(
+  void OnBottomSheetClosedWithSwipe(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jcaller);
 
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index e29ca397..fd1f484 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -696,11 +696,21 @@
 void UiControllerAndroid::OnTabSwitched(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller,
-    jint state) {
+    jint state,
+    jboolean activity_changed) {
   if (ui_delegate_ == nullptr) {
     return;
   }
 
+  // TODO(b/167947210) Allow lite scripts to transition from CCT to regular
+  // scripts.
+  if (activity_changed && ui_delegate_->IsRunningLiteScript()) {
+    // Destroying UI here because Shutdown does not do so in all cases.
+    DestroySelf();
+    Shutdown(Metrics::DropOutReason::CUSTOM_TAB_CLOSED);
+    return;
+  }
+
   ui_delegate_->SetBottomSheetState(
       ui_controller_android_utils::ToNativeBottomSheetState(state));
   ui_delegate_->SetTabSelected(false);
@@ -922,7 +932,7 @@
   return true;
 }
 
-void UiControllerAndroid::OnBottomSheetDismissed() {
+void UiControllerAndroid::OnBottomSheetClosedWithSwipe() {
   if (ui_delegate_->IsTabSelected() && ui_delegate_->IsRunningLiteScript()) {
     // Destroying UI here because Shutdown does not do so in all cases.
     DestroySelf();
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index eed8efa..9439169 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -168,7 +168,7 @@
 
   // Called by AssistantBottomBarNativeDelegate:
   bool OnBackButtonClicked();
-  void OnBottomSheetDismissed();
+  void OnBottomSheetClosedWithSwipe();
 
   // Called by Java.
   void SnackbarResult(JNIEnv* env,
@@ -203,7 +203,8 @@
                   jboolean visible);
   void OnTabSwitched(JNIEnv* env,
                      const base::android::JavaParamRef<jobject>& jcaller,
-                     jint state);
+                     jint state,
+                     jboolean activity_changed);
   void OnTabSelected(JNIEnv* env,
                      const base::android::JavaParamRef<jobject>& jcaller);
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 694349ed..8145d5e 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -267,7 +267,10 @@
         <include name="IDR_CONFIRM_PASSWORD_CHANGE_JS" file="resources\chromeos\password_change\confirm_password_change.js" type="chrome_html" />
         <include name="IDR_URGENT_PASSWORD_EXPIRY_NOTIFICATION_HTML" file="resources\chromeos\password_change\urgent_password_expiry_notification.html" flattenhtml="true" allowexternalscript="true" type="chrome_html" />
         <include name="IDR_URGENT_PASSWORD_EXPIRY_NOTIFICATION_JS" file="resources\chromeos\password_change\urgent_password_expiry_notification.js" type="chrome_html" />
-
+        <include name="IDR_GAIA_AUTH_AUTHENTICATOR_JS" file="resources\gaia_auth_host\authenticator.js" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_LOCK_SCREEN_REAUTH_HTML" file="resources\chromeos\password_change\lock_screen_reauth.html" flattenhtml="true" type="BINDATA" />
+        <include name="IDR_LOCK_SCREEN_REAUTH_JS" file="resources\chromeos\password_change\lock_screen_reauth.js" type="BINDATA" />
+      
         <include name="IDR_CROSTINI_INSTALLER_INDEX_HTML" file="resources\chromeos\crostini_installer\index.html" type="BINDATA" />
         <include name="IDR_CROSTINI_INSTALLER_APP_JS" file="${root_gen_dir}\chrome\browser\resources\chromeos\crostini_installer\app.js" type="BINDATA" use_base_dir="false" />
         <include name="IDR_CROSTINI_INSTALLER_BROWSER_PROXY_JS" file="resources\chromeos\crostini_installer\browser_proxy.js" type="BINDATA" />
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 0e31872..983b342 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -959,6 +959,8 @@
     "crosapi/browser_manager.h",
     "crosapi/browser_util.cc",
     "crosapi/browser_util.h",
+    "crosapi/environment_provider.cc",
+    "crosapi/environment_provider.h",
     "crosapi/feedback_ash.cc",
     "crosapi/feedback_ash.h",
     "crosapi/keystore_service_ash.cc",
@@ -3018,6 +3020,8 @@
     "login/test/test_condition_waiter.h",
     "login/test/test_predicate_waiter.cc",
     "login/test/test_predicate_waiter.h",
+    "login/test/wizard_controller_screen_exit_waiter.cc",
+    "login/test/wizard_controller_screen_exit_waiter.h",
     "login/version_updater/mock_version_updater_delegate.cc",
     "login/version_updater/mock_version_updater_delegate.h",
     "platform_keys/key_permissions/mock_key_permissions_service.cc",
diff --git a/chrome/browser/chromeos/attestation/tpm_challenge_key_subtle.cc b/chrome/browser/chromeos/attestation/tpm_challenge_key_subtle.cc
index c8697d0b..8a73400 100644
--- a/chrome/browser/chromeos/attestation/tpm_challenge_key_subtle.cc
+++ b/chrome/browser/chromeos/attestation/tpm_challenge_key_subtle.cc
@@ -248,8 +248,7 @@
   DCHECK(profile_);
 
   PrefService* prefs = profile_->GetPrefs();
-  // TODO(crbug.com/1000589): Check it's mandatory after fixing corp policy.
-  if (prefs) {
+  if (prefs && prefs->IsManagedPreference(prefs::kAttestationEnabled)) {
     return prefs->GetBoolean(prefs::kAttestationEnabled);
   }
   return false;
diff --git a/chrome/browser/chromeos/crosapi/browser_manager.cc b/chrome/browser/chromeos/crosapi/browser_manager.cc
index 5d5094a..83764de5 100644
--- a/chrome/browser/chromeos/crosapi/browser_manager.cc
+++ b/chrome/browser/chromeos/crosapi/browser_manager.cc
@@ -7,6 +7,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
@@ -30,6 +31,7 @@
 #include "chrome/browser/chromeos/crosapi/ash_chrome_service_impl.h"
 #include "chrome/browser/chromeos/crosapi/browser_loader.h"
 #include "chrome/browser/chromeos/crosapi/browser_util.h"
+#include "chrome/browser/chromeos/crosapi/environment_provider.h"
 #include "chrome/browser/chromeos/crosapi/test_mojo_connection_manager.h"
 #include "chrome/browser/component_updater/cros_component_manager.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -139,7 +141,8 @@
 
 BrowserManager::BrowserManager(
     scoped_refptr<component_updater::CrOSComponentManager> manager)
-    : component_manager_(manager) {
+    : component_manager_(manager),
+      environment_provider_(std::make_unique<EnvironmentProvider>()) {
   DCHECK(!g_instance);
   g_instance = this;
 
@@ -296,7 +299,7 @@
 
   // TODO(crbug.com/1124490): Support multiple mojo connections from lacros.
   lacros_chrome_service_ = browser_util::SendMojoInvitationToLacrosChrome(
-      channel.TakeLocalEndpoint(),
+      environment_provider_.get(), channel.TakeLocalEndpoint(),
       base::BindOnce(&BrowserManager::OnMojoDisconnected,
                      weak_factory_.GetWeakPtr()),
       base::BindOnce(&BrowserManager::OnAshChromeServiceReceiverReceived,
diff --git a/chrome/browser/chromeos/crosapi/browser_manager.h b/chrome/browser/chromeos/crosapi/browser_manager.h
index de94b53..fb2318aa 100644
--- a/chrome/browser/chromeos/crosapi/browser_manager.h
+++ b/chrome/browser/chromeos/crosapi/browser_manager.h
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/process/process.h"
+#include "chrome/browser/chromeos/crosapi/environment_provider.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
 #include "components/session_manager/core/session_manager_observer.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -166,6 +167,9 @@
   // '--lacros-mojo-socket-for-testing' is present in the command line.
   std::unique_ptr<TestMojoConnectionManager> test_mojo_connection_manager_;
 
+  // Used to pass ash-chrome specific flags/configurations to lacros-chrome.
+  std::unique_ptr<EnvironmentProvider> environment_provider_;
+
   base::WeakPtrFactory<BrowserManager> weak_factory_{this};
 };
 
diff --git a/chrome/browser/chromeos/crosapi/browser_util.cc b/chrome/browser/chromeos/crosapi/browser_util.cc
index b451bce..f930270 100644
--- a/chrome/browser/chromeos/crosapi/browser_util.cc
+++ b/chrome/browser/chromeos/crosapi/browser_util.cc
@@ -54,13 +54,16 @@
   }
 }
 
-mojom::LacrosInitParamsPtr GetLacrosInitParams() {
+mojom::LacrosInitParamsPtr GetLacrosInitParams(
+    EnvironmentProvider* environment_provider) {
   auto params = mojom::LacrosInitParams::New();
   params->ash_chrome_service_version =
       crosapi::mojom::AshChromeService::Version_;
   params->ash_metrics_enabled_has_value = true;
   params->ash_metrics_enabled = g_browser_process->local_state()->GetBoolean(
       metrics::prefs::kMetricsReportingEnabled);
+
+  params->session_type = environment_provider->GetSessionType();
   return params;
 }
 
@@ -120,6 +123,7 @@
 
 mojo::Remote<crosapi::mojom::LacrosChromeService>
 SendMojoInvitationToLacrosChrome(
+    EnvironmentProvider* environment_provider,
     mojo::PlatformChannelEndpoint local_endpoint,
     base::OnceClosure mojo_disconnected_callback,
     base::OnceCallback<
@@ -132,7 +136,7 @@
           invitation.AttachMessagePipe(0 /* token */), /*version=*/0));
   lacros_chrome_service.set_disconnect_handler(
       std::move(mojo_disconnected_callback));
-  lacros_chrome_service->Init(GetLacrosInitParams());
+  lacros_chrome_service->Init(GetLacrosInitParams(environment_provider));
   lacros_chrome_service->RequestAshChromeServiceReceiver(
       std::move(ash_chrome_service_callback));
   mojo::OutgoingInvitation::Send(std::move(invitation),
diff --git a/chrome/browser/chromeos/crosapi/browser_util.h b/chrome/browser/chromeos/crosapi/browser_util.h
index 1930eeb8..a0ced50 100644
--- a/chrome/browser/chromeos/crosapi/browser_util.h
+++ b/chrome/browser/chromeos/crosapi/browser_util.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_CROSAPI_BROWSER_UTIL_H_
 
 #include "base/callback_forward.h"
+#include "chrome/browser/chromeos/crosapi/environment_provider.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -57,6 +58,7 @@
 // available already when lacros-chrome accepts the invitation.
 mojo::Remote<crosapi::mojom::LacrosChromeService>
 SendMojoInvitationToLacrosChrome(
+    ::crosapi::EnvironmentProvider* environment_provider,
     mojo::PlatformChannelEndpoint local_endpoint,
     base::OnceClosure mojo_disconnected_callback,
     base::OnceCallback<
diff --git a/chrome/browser/chromeos/crosapi/environment_provider.cc b/chrome/browser/chromeos/crosapi/environment_provider.cc
new file mode 100644
index 0000000..1f1370c
--- /dev/null
+++ b/chrome/browser/chromeos/crosapi/environment_provider.cc
@@ -0,0 +1,27 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/crosapi/environment_provider.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profiles_state.h"
+#include "components/user_manager/user.h"
+#include "components/user_manager/user_manager.h"
+
+crosapi::EnvironmentProvider::EnvironmentProvider() = default;
+crosapi::EnvironmentProvider::~EnvironmentProvider() = default;
+
+crosapi::mojom::SessionType crosapi::EnvironmentProvider::GetSessionType() {
+  const user_manager::User* const user =
+      user_manager::UserManager::Get()->GetActiveUser();
+  const Profile* const profile =
+      chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+  if (profile->IsGuestSession()) {
+    return crosapi::mojom::SessionType::kGuestSession;
+  }
+  if (profiles::IsPublicSession()) {
+    return crosapi::mojom::SessionType::kPublicSession;
+  }
+  return crosapi::mojom::SessionType::kRegularSession;
+}
diff --git a/chrome/browser/chromeos/crosapi/environment_provider.h b/chrome/browser/chromeos/crosapi/environment_provider.h
new file mode 100644
index 0000000..8c02e4a86
--- /dev/null
+++ b/chrome/browser/chromeos/crosapi/environment_provider.h
@@ -0,0 +1,26 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CROSAPI_ENVIRONMENT_PROVIDER_H_
+#define CHROME_BROWSER_CHROMEOS_CROSAPI_ENVIRONMENT_PROVIDER_H_
+
+#include "chromeos/crosapi/mojom/crosapi.mojom.h"
+
+namespace crosapi {
+
+// Provides ash-chrome specific flags/configurations (like session type).
+class EnvironmentProvider {
+ public:
+  EnvironmentProvider();
+  EnvironmentProvider(const EnvironmentProvider&) = delete;
+  EnvironmentProvider& operator=(const EnvironmentProvider&) = delete;
+  virtual ~EnvironmentProvider();
+
+  // Virtual for tests.
+  virtual crosapi::mojom::SessionType GetSessionType();
+};
+
+}  // namespace crosapi
+
+#endif  // CHROME_BROWSER_CHROMEOS_CROSAPI_ENVIRONMENT_PROVIDER_H_
diff --git a/chrome/browser/chromeos/crosapi/test_mojo_connection_manager.cc b/chrome/browser/chromeos/crosapi/test_mojo_connection_manager.cc
index 3e00073..5799249 100644
--- a/chrome/browser/chromeos/crosapi/test_mojo_connection_manager.cc
+++ b/chrome/browser/chromeos/crosapi/test_mojo_connection_manager.cc
@@ -24,6 +24,12 @@
 
 namespace {
 
+class FakeEnvironmentProvider : public EnvironmentProvider {
+  crosapi::mojom::SessionType GetSessionType() override {
+    return crosapi::mojom::SessionType::kRegularSession;
+  }
+};
+
 // TODO(crbug.com/1124494): Refactor the code to share with ARC.
 base::ScopedFD CreateSocketForTesting(const base::FilePath& socket_path) {
   auto endpoint = mojo::NamedPlatformChannel({socket_path.value()});
@@ -45,7 +51,8 @@
 }  // namespace
 
 TestMojoConnectionManager::TestMojoConnectionManager(
-    const base::FilePath& socket_path) {
+    const base::FilePath& socket_path)
+    : environment_provider_(std::make_unique<FakeEnvironmentProvider>()) {
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::MayBlock()},
       base::BindOnce(&CreateSocketForTesting, socket_path),
@@ -79,7 +86,7 @@
   // TODO(crbug.com/1124490): Support multiple mojo connections from lacros.
   mojo::PlatformChannel channel;
   lacros_chrome_service_ = browser_util::SendMojoInvitationToLacrosChrome(
-      channel.TakeLocalEndpoint(),
+      environment_provider_.get(), channel.TakeLocalEndpoint(),
       base::BindOnce(&TestMojoConnectionManager::OnMojoDisconnected,
                      weak_factory_.GetWeakPtr()),
       base::BindOnce(
diff --git a/chrome/browser/chromeos/crosapi/test_mojo_connection_manager.h b/chrome/browser/chromeos/crosapi/test_mojo_connection_manager.h
index f52bf516..9e5999ce 100644
--- a/chrome/browser/chromeos/crosapi/test_mojo_connection_manager.h
+++ b/chrome/browser/chromeos/crosapi/test_mojo_connection_manager.h
@@ -13,6 +13,7 @@
 #include "base/files/file_path.h"
 #include "base/files/scoped_file.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/crosapi/environment_provider.h"
 #include "chromeos/crosapi/mojom/crosapi.mojom.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
@@ -76,6 +77,9 @@
   std::unique_ptr<base::FileDescriptorWatcher::Controller>
       testing_socket_watcher_;
 
+  // Used to pass ash-chrome specific flags/configurations to lacros-chrome.
+  std::unique_ptr<EnvironmentProvider> environment_provider_;
+
   base::WeakPtrFactory<TestMojoConnectionManager> weak_factory_{this};
 };
 
diff --git a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.cc b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.cc
index e7cc47a..b9440d1f 100644
--- a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.cc
+++ b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.cc
@@ -26,7 +26,6 @@
       clock_(base::DefaultClock::GetInstance()),
       primary_user_(ProfileHelper::Get()->GetUserByProfile(primary_profile)) {
   DCHECK(primary_user_);
-
   auto* session_manager = session_manager::SessionManager::Get();
   // Extra check as SessionManager may be not initialized in some unit
   // tests
diff --git a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h
index a0e4867..80d82b0 100644
--- a/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h
+++ b/chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h
@@ -13,6 +13,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/login/saml/password_sync_token_fetcher.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
 #include "chromeos/components/proximity_auth/screenlock_bridge.h"
 #include "components/account_id/account_id.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -81,6 +82,8 @@
   void OnTokenVerified(bool is_valid) override;
   void OnApiCallFailed(PasswordSyncTokenFetcher::ErrorType error_type) override;
 
+  std::unique_ptr<LockScreenStartReauthDialog> lock_screen_start_reauth_dialog;
+
  private:
   void UpdateOnlineAuth();
   // Password sync token API calls.
diff --git a/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc b/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc
index 1922273..dae11650 100644
--- a/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/family_link_notice_browsertest.cc
@@ -9,9 +9,9 @@
 #include "chrome/browser/chromeos/login/test/local_policy_test_server_mixin.h"
 #include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
-#include "chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/test/user_policy_mixin.h"
+#include "chrome/browser/chromeos/login/test/wizard_controller_screen_exit_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -53,7 +53,7 @@
 
   void LoginAsRegularUser() {
     login_manager_mixin_.LoginAsNewRegularUser();
-    OobeScreenExitWaiter(UserCreationView::kScreenId).Wait();
+    WizardControllerExitWaiter(UserCreationView::kScreenId).Wait();
   }
 
   void ExpectHelpAppPrefValue(bool expected) {
@@ -145,7 +145,7 @@
 
   void LoginAsChildUser() {
     login_manager_mixin_.LoginAsNewChildUser();
-    OobeScreenExitWaiter(UserCreationView::kScreenId).Wait();
+    WizardControllerExitWaiter(UserCreationView::kScreenId).Wait();
   }
 
  private:
@@ -186,7 +186,7 @@
   void LoginAsManagedUser() {
     user_policy_mixin_.RequestPolicyUpdate();
     login_manager_mixin_.LoginWithDefaultContext(test_user_);
-    OobeScreenExitWaiter(UserCreationView::kScreenId).Wait();
+    WizardControllerExitWaiter(UserCreationView::kScreenId).Wait();
   }
 
  private:
diff --git a/chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.cc b/chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.cc
index 6a7cce6..2114e87 100644
--- a/chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.cc
+++ b/chrome/browser/chromeos/login/test/oobe_screen_exit_waiter.cc
@@ -17,14 +17,14 @@
 OobeScreenExitWaiter::~OobeScreenExitWaiter() = default;
 
 void OobeScreenExitWaiter::Wait() {
-  DCHECK_EQ(State::IDLE, state_);
+  ASSERT_EQ(State::IDLE, state_);
 
   OobeUI* oobe_ui = GetOobeUI();
   if (!oobe_ui || oobe_ui->current_screen() != target_screen_) {
     state_ = State::DONE;
     return;
   }
-  DCHECK(!run_loop_);
+  ASSERT_FALSE(run_loop_);
 
   oobe_ui_observer_.Add(GetOobeUI());
 
@@ -43,7 +43,7 @@
 
 void OobeScreenExitWaiter::OnCurrentScreenChanged(OobeScreenId current_screen,
                                                   OobeScreenId new_screen) {
-  DCHECK_NE(state_, State::IDLE);
+  ASSERT_NE(state_, State::IDLE);
   if (new_screen != target_screen_)
     EndWait();
 }
diff --git a/chrome/browser/chromeos/login/test/wizard_controller_screen_exit_waiter.cc b/chrome/browser/chromeos/login/test/wizard_controller_screen_exit_waiter.cc
new file mode 100644
index 0000000..692f768
--- /dev/null
+++ b/chrome/browser/chromeos/login/test/wizard_controller_screen_exit_waiter.cc
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/test/wizard_controller_screen_exit_waiter.h"
+
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+WizardControllerExitWaiter::WizardControllerExitWaiter(OobeScreenId screen_id)
+    : WizardControllerExitWaiter(
+          WizardController::default_controller()->GetScreen(screen_id)) {}
+
+WizardControllerExitWaiter::WizardControllerExitWaiter(
+    BaseScreen* target_screen)
+    : target_screen_(target_screen) {}
+
+WizardControllerExitWaiter::~WizardControllerExitWaiter() = default;
+
+void WizardControllerExitWaiter::Wait() {
+  ASSERT_EQ(State::IDLE, state_);
+
+  WizardController* wizard_controller = WizardController::default_controller();
+  if (!wizard_controller ||
+      wizard_controller->current_screen() != target_screen_) {
+    state_ = State::DONE;
+    return;
+  }
+  ASSERT_FALSE(run_loop_);
+
+  screen_observer_.Add(wizard_controller);
+
+  state_ = State::WAITING_FOR_SCREEN_EXIT;
+
+  LOG(INFO) << "Actually waiting for exiting screen "
+            << target_screen_->screen_id();
+
+  run_loop_ = std::make_unique<base::RunLoop>();
+  run_loop_->Run();
+  run_loop_.reset();
+
+  ASSERT_EQ(State::DONE, state_);
+
+  screen_observer_.RemoveAll();
+}
+
+void WizardControllerExitWaiter::OnCurrentScreenChanged(
+    BaseScreen* new_screen) {
+  ASSERT_NE(state_, State::IDLE);
+  if (new_screen != target_screen_)
+    EndWait();
+}
+
+void WizardControllerExitWaiter::OnShutdown() {
+  screen_observer_.RemoveAll();
+  EndWait();
+}
+
+void WizardControllerExitWaiter::EndWait() {
+  if (state_ == State::DONE)
+    return;
+
+  state_ = State::DONE;
+  run_loop_->Quit();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/wizard_controller_screen_exit_waiter.h b/chrome/browser/chromeos/login/test/wizard_controller_screen_exit_waiter.h
new file mode 100644
index 0000000..63b5efe
--- /dev/null
+++ b/chrome/browser/chromeos/login/test/wizard_controller_screen_exit_waiter.h
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_TEST_WIZARD_CONTROLLER_SCREEN_EXIT_WAITER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_TEST_WIZARD_CONTROLLER_SCREEN_EXIT_WAITER_H_
+
+#include "base/macros.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/chromeos/login/oobe_screen.h"
+#include "chrome/browser/chromeos/login/screens/base_screen.h"
+#include "chrome/browser/chromeos/login/test/test_condition_waiter.h"
+#include "chrome/browser/chromeos/login/wizard_controller.h"
+
+namespace base {
+class RunLoop;
+}
+
+namespace chromeos {
+
+// A waiter that blocks until the the current WizardController screen is
+// different than the target screen, or the WizardController is destroyed.
+class WizardControllerExitWaiter : public test::TestConditionWaiter,
+                                   public WizardController::ScreenObserver {
+ public:
+  explicit WizardControllerExitWaiter(OobeScreenId screen_id);
+  explicit WizardControllerExitWaiter(BaseScreen* target_screen);
+  ~WizardControllerExitWaiter() override;
+
+  // WizardController::ScreenObserver:
+  void OnCurrentScreenChanged(BaseScreen* new_screen) override;
+  void OnShutdown() override;
+
+  // TestConditionWaiter;
+  void Wait() override;
+
+ private:
+  enum class State { IDLE, WAITING_FOR_SCREEN_EXIT, DONE };
+
+  void EndWait();
+
+  const BaseScreen* target_screen_;
+
+  State state_ = State::IDLE;
+
+  ScopedObserver<WizardController, WizardController::ScreenObserver>
+      screen_observer_{this};
+
+  std::unique_ptr<base::RunLoop> run_loop_;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_TEST_WIZARD_CONTROLLER_SCREEN_EXIT_WAITER_H_
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index ada2e1a..9b8805f 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -371,6 +371,8 @@
 }
 
 WizardController::~WizardController() {
+  for (ScreenObserver& obs : screen_observers_)
+    obs.OnShutdown();
   screen_manager_.reset();
 }
 
@@ -1572,8 +1574,10 @@
   previous_screen_ = current_screen_;
   current_screen_ = new_current;
 
-  if (!current_screen_)
+  if (!current_screen_) {
+    NotifyScreenChanged();
     return;
+  }
 
   // Record show time for UMA.
   screen_show_times_[new_current->screen_id()] = base::TimeTicks::Now();
@@ -1586,6 +1590,7 @@
 
   UpdateStatusAreaVisibilityForScreen(current_screen_->screen_id());
   current_screen_->Show(wizard_context_.get());
+  NotifyScreenChanged();
 }
 
 void WizardController::UpdateStatusAreaVisibilityForScreen(
@@ -1874,6 +1879,14 @@
          screen_id == GaiaView::kScreenId;
 }
 
+void WizardController::AddObserver(ScreenObserver* obs) {
+  screen_observers_.AddObserver(obs);
+}
+
+void WizardController::RemoveObserver(ScreenObserver* obs) {
+  screen_observers_.RemoveObserver(obs);
+}
+
 void WizardController::OnLocalStateInitialized(bool /* succeeded */) {
   if (GetLocalState()->GetInitializationStatus() !=
       PrefService::INITIALIZATION_STATUS_ERROR) {
@@ -2033,6 +2046,11 @@
   SetCurrentScreen(screen);
 }
 
+void WizardController::NotifyScreenChanged() {
+  for (ScreenObserver& obs : screen_observers_)
+    obs.OnCurrentScreenChanged(current_screen_);
+}
+
 AutoEnrollmentController* WizardController::GetAutoEnrollmentController() {
   if (!auto_enrollment_controller_)
     auto_enrollment_controller_ = std::make_unique<AutoEnrollmentController>();
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index da9c0fe..0161eb5 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -70,6 +70,12 @@
 // interacts with screen controllers to move the user between screens.
 class WizardController {
  public:
+  class ScreenObserver : public base::CheckedObserver {
+   public:
+    virtual void OnCurrentScreenChanged(BaseScreen* new_screen) = 0;
+    virtual void OnShutdown() = 0;
+  };
+
   WizardController();
   ~WizardController();
 
@@ -203,6 +209,9 @@
     return first_screen_for_testing_;
   }
 
+  void AddObserver(ScreenObserver* obs);
+  void RemoveObserver(ScreenObserver* obs);
+
  private:
   // Create BaseScreen instances. These are owned by |screen_manager_|.
   std::vector<std::unique_ptr<BaseScreen>> CreateScreens();
@@ -373,9 +382,7 @@
   // attestation-based enrollment if appropriate.
   void StartEnrollmentScreen(bool force_interactive);
 
-  void OnConfigurationLoaded(
-      OobeScreenId first_screen,
-      std::unique_ptr<base::DictionaryValue> configuration);
+  void NotifyScreenChanged();
 
   // Returns auto enrollment controller (lazily initializes one if it doesn't
   // exist already).
@@ -462,6 +469,8 @@
 
   bool is_initialized_ = false;
 
+  base::ObserverList<ScreenObserver> screen_observers_;
+
   base::WeakPtrFactory<WizardController> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(WizardController);
diff --git a/chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_manager_user_service.h b/chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_manager_user_service.h
deleted file mode 100644
index d5996c9..0000000
--- a/chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_manager_user_service.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_PLATFORM_KEYS_KEY_PERMISSIONS_KEY_PERMISSIONS_MANAGER_USER_SERVICE_H_
-#define CHROME_BROWSER_CHROMEOS_PLATFORM_KEYS_KEY_PERMISSIONS_KEY_PERMISSIONS_MANAGER_USER_SERVICE_H_
-
-#include "base/no_destructor.h"
-#include "chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_manager.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
-namespace chromeos {
-namespace platform_keys {
-
-// KeyPermissionsManagerUserService is a wrapper over KeyPermissionsManager
-// (KPM) to provide KPMs keyed by profile. KPM is not a KeyedService by itself
-// so as future work can introduce a global device-wide KPM instance.
-class KeyPermissionsManagerUserService : public KeyedService {
- public:
-  KeyPermissionsManagerUserService();
-  ~KeyPermissionsManagerUserService() override;
-
-  virtual KeyPermissionsManager* key_permissions_manager() = 0;
-};
-
-class KeyPermissionsManagerUserServiceFactory
-    : public BrowserContextKeyedServiceFactory {
- public:
-  static KeyPermissionsManagerUserService* GetForBrowserContext(
-      content::BrowserContext* context);
-  static KeyPermissionsManagerUserServiceFactory* GetInstance();
-
- private:
-  friend class base::NoDestructor<KeyPermissionsManagerUserServiceFactory>;
-
-  KeyPermissionsManagerUserServiceFactory();
-  ~KeyPermissionsManagerUserServiceFactory() override = default;
-
-  // BrowserStateKeyedServiceFactory.
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-  void RegisterProfilePrefs(
-      user_prefs::PrefRegistrySyncable* registry) override;
-};
-
-}  // namespace platform_keys
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_PLATFORM_KEYS_KEY_PERMISSIONS_KEY_PERMISSIONS_MANAGER_USER_SERVICE_H_
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
index 365aa553..9dec32e 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
@@ -206,9 +206,14 @@
   if (service_status == chromeos::DeviceSettingsService::STORE_SUCCESS) {
     policy_ = std::make_unique<em::PolicyData>();
     const em::PolicyData* policy_data = device_settings_service_->policy_data();
-    if (policy_data)
+    if (policy_data) {
       policy_->MergeFrom(*policy_data);
 
+      RecordDeviceIdValidityMetric(
+          "Enterprise.CachedDevicePolicyDeviceIdValidity", *policy_data,
+          *install_attributes_);
+    }
+
     PolicyMap new_policy_map;
     if (is_managed()) {
       DecodeDevicePolicy(*device_settings_service_->device_settings(),
diff --git a/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.cc b/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.cc
index 80183a1..29a2dc0 100644
--- a/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.cc
+++ b/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.cc
@@ -8,7 +8,9 @@
 
 #include "ash/public/cpp/toast_data.h"
 #include "ash/public/cpp/toast_manager.h"
+#include "base/notreached.h"
 #include "base/optional.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
@@ -60,13 +62,16 @@
             DlpRulesManager::Component::kPluginVm,
             DlpRulesManager::Component::kCrostini},
         DlpRulesManager::Restriction::kClipboard);
+  } else if (data_dst->type() == ui::EndpointType::kArc) {
+    level = DlpRulesManager::Get()->IsRestrictedComponent(
+        data_src->origin()->GetURL(), DlpRulesManager::Component::kArc,
+        DlpRulesManager::Restriction::kClipboard);
   } else {
     NOTREACHED();
   }
-  // TODO(crbug.com/1129345): Add a separate handling for ARC
 
   if (level == DlpRulesManager::Level::kBlock) {
-    ShowBlockToast(GetToastText(data_dst));
+    ShowBlockToast(GetToastText(data_src, data_dst));
   }
 
   return level == DlpRulesManager::Level::kAllow;
@@ -81,7 +86,12 @@
 }
 
 base::string16 EnterpriseClipboardDlpController::GetToastText(
+    const ui::ClipboardDataEndpoint* const data_src,
     const ui::ClipboardDataEndpoint* const data_dst) const {
+  DCHECK(data_src);
+  DCHECK(data_src->origin());
+  base::string16 host_name = base::UTF8ToUTF16(data_src->origin()->host());
+
   if (data_dst && data_dst->type() == ui::EndpointType::kGuestOs) {
     ProfileManager* profile_manager = g_browser_process->profile_manager();
     Profile* profile =
@@ -92,22 +102,30 @@
 
     if (is_crostini_running && is_plugin_vm_running) {
       return l10n_util::GetStringFUTF16(
-          IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_TWO_VMS,
+          IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_TWO_VMS, host_name,
           l10n_util::GetStringUTF16(IDS_CROSTINI_LINUX),
           l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME));
     } else if (is_crostini_running) {
       return l10n_util::GetStringFUTF16(
-          IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM,
+          IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
           l10n_util::GetStringUTF16(IDS_CROSTINI_LINUX));
     } else if (is_plugin_vm_running) {
       return l10n_util::GetStringFUTF16(
-          IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM,
+          IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
           l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME));
     } else {
       NOTREACHED();
     }
   }
-  return l10n_util::GetStringUTF16(IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE);
+
+  if (data_dst && data_dst->type() == ui::EndpointType::kArc) {
+    return l10n_util::GetStringFUTF16(
+        IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM, host_name,
+        l10n_util::GetStringUTF16(IDS_POLICY_DLP_ANDROID_APPS));
+  }
+
+  return l10n_util::GetStringFUTF16(IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE,
+                                    host_name);
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.h b/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.h
index 7529be1..bc4254e6 100644
--- a/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.h
+++ b/chrome/browser/chromeos/policy/dlp/enterprise_clipboard_dlp_controller.h
@@ -38,8 +38,9 @@
   void ShowBlockToast(const base::string16& text) const;
 
   // The text will be different if the clipboard data is shared with Crostini
-  // or Parallels or both of them.
+  // or Parallels or ARC.
   base::string16 GetToastText(
+      const ui::ClipboardDataEndpoint* const data_src,
       const ui::ClipboardDataEndpoint* const data_dst) const;
 };
 
diff --git a/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc b/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
index 073767d9..4a65754 100644
--- a/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
+++ b/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
@@ -25,7 +25,7 @@
 #include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router.h"
 #include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h"
 #include "chrome/browser/password_manager/bulk_leak_check_service_factory.h"
-#include "chrome/browser/password_manager/password_store_factory.h"
+#include "chrome/browser/password_manager/password_manager_test_util.h"
 #include "chrome/common/extensions/api/passwords_private.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -120,17 +120,6 @@
           })));
 }
 
-scoped_refptr<TestPasswordStore> CreateAndUseTestPasswordStore(
-    Profile* profile) {
-  return base::WrapRefCounted(static_cast<TestPasswordStore*>(
-      PasswordStoreFactory::GetInstance()
-          ->SetTestingFactoryAndUse(
-              profile,
-              base::BindRepeating(&password_manager::BuildPasswordStore<
-                                  content::BrowserContext, TestPasswordStore>))
-          .get()));
-}
-
 BulkLeakCheckService* CreateAndUseBulkLeakCheckService(
     signin::IdentityManager* identity_manager,
     Profile* profile) {
diff --git a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc
index a48896f8..0564e2a 100644
--- a/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc
+++ b/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc
@@ -25,7 +25,7 @@
 #include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h"
 #include "chrome/browser/password_manager/account_password_store_factory.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
-#include "chrome/browser/password_manager/password_store_factory.h"
+#include "chrome/browser/password_manager/password_manager_test_util.h"
 #include "chrome/common/extensions/api/passwords_private.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/autofill/core/common/password_form.h"
@@ -67,17 +67,6 @@
 using MockPlaintextPasswordCallback =
     base::MockCallback<PasswordsPrivateDelegate::PlaintextPasswordCallback>;
 
-scoped_refptr<TestPasswordStore> CreateAndUseTestPasswordStore(
-    Profile* profile) {
-  return base::WrapRefCounted(static_cast<TestPasswordStore*>(
-      PasswordStoreFactory::GetInstance()
-          ->SetTestingFactoryAndUse(
-              profile,
-              base::BindRepeating(&password_manager::BuildPasswordStore<
-                                  content::BrowserContext, TestPasswordStore>))
-          .get()));
-}
-
 scoped_refptr<TestPasswordStore> CreateAndUseTestAccountPasswordStore(
     Profile* profile) {
   if (!base::FeatureList::IsEnabled(
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
index 897c589..21d8c03 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
@@ -865,7 +865,8 @@
 }
 
 // Errors occurred because the fetched update manifest was invalid because app
-// status was not OK.
+// status was not OK. Verifies that this error with app status error as
+// "error-unknownApplication" is considered as a misconfiguration.
 TEST_F(ForceInstalledMetricsTest, ExtensionManifestInvalidAppStatusError) {
   SetupForceList();
   auto extension =
@@ -883,6 +884,11 @@
   histogram_tester_.ExpectUniqueSample(
       kExtensionManifestInvalidAppStatusError,
       InstallStageTracker::AppStatusError::kErrorUnknownApplication, 1);
+  // Verify that the session with either all the extensions installed
+  // successfully, or all failures as admin-side misconfigurations is recorded
+  // here and BAD_APP_STATUS error is considered as a misconfiguration.
+  histogram_tester_.ExpectBucketCount(kPossibleNonMisconfigurationFailures, 0,
+                                      1);
 }
 
 // Session in which either all the extensions installed successfully, or all
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_tracker.cc b/chrome/browser/extensions/forced_extensions/force_installed_tracker.cc
index d736a6c..3e471a4 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_tracker.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_tracker.cc
@@ -224,6 +224,13 @@
     }
   }
 
+  if (installation_data.manifest_invalid_error ==
+          ManifestInvalidError::BAD_APP_STATUS &&
+      installation_data.app_status_error ==
+          InstallStageTracker::AppStatusError::kErrorUnknownApplication) {
+    return true;
+  }
+
   return false;
 }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index e4478c8..f3f3d6b 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2340,7 +2340,7 @@
   {
     "name": "enable-webrtc-pipewire-capturer",
     "owners": [ "tomas.popela@gmail.com" ],
-    "expiry_milestone": 86
+    "expiry_milestone": 90
   },
   {
     "name": "enable-webrtc-remote-event-log",
diff --git a/chrome/browser/importer/profile_writer_unittest.cc b/chrome/browser/importer/profile_writer_unittest.cc
index 7bc05e0..63eb09ee 100644
--- a/chrome/browser/importer/profile_writer_unittest.cc
+++ b/chrome/browser/importer/profile_writer_unittest.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/importer/importer_unittest_utils.h"
-#include "chrome/browser/password_manager/password_store_factory.h"
+#include "chrome/browser/password_manager/password_manager_test_util.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/common/importer/imported_bookmark_entry.h"
 #include "chrome/test/base/testing_profile.h"
@@ -42,17 +42,6 @@
 using bookmarks::UrlAndTitle;
 using password_manager::TestPasswordStore;
 
-scoped_refptr<TestPasswordStore> CreateAndUseTestPasswordStore(
-    Profile* profile) {
-  return base::WrapRefCounted(static_cast<TestPasswordStore*>(
-      PasswordStoreFactory::GetInstance()
-          ->SetTestingFactoryAndUse(
-              profile,
-              base::BindRepeating(&password_manager::BuildPasswordStore<
-                                  content::BrowserContext, TestPasswordStore>))
-          .get()));
-}
-
 PasswordForm MakePasswordForm() {
   PasswordForm form;
   form.url = GURL("https://example.com/");
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl_unittest.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl_unittest.cc
index b6e2da65..e06b66f8 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/optional.h"
 #include "base/test/bind_test_util.h"
+#include "build/build_config.h"
 #include "chrome/browser/nearby_sharing/client/fake_nearby_share_client.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
 #include "chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_device_data_updater.h"
@@ -259,7 +260,13 @@
   EXPECT_EQ(id, manager()->GetId());
 }
 
-TEST_F(NearbyShareLocalDeviceDataManagerImplTest, ValidateDeviceName) {
+// Test is flaky. crbug.com/1133295.
+#if defined(OS_CHROMEOS)
+#define MAYBE_ValidateDeviceName DISABLED_ValidateDeviceName
+#else
+#define MAYBE_ValidateDeviceName ValidateDeviceName
+#endif
+TEST_F(NearbyShareLocalDeviceDataManagerImplTest, MAYBE_ValidateDeviceName) {
   CreateManager();
   EXPECT_EQ(manager()->ValidateDeviceName(kFakeDeviceName),
             nearby_share::mojom::DeviceNameValidationResult::kValid);
@@ -272,7 +279,13 @@
       nearby_share::mojom::DeviceNameValidationResult::kErrorNotValidUtf8);
 }
 
-TEST_F(NearbyShareLocalDeviceDataManagerImplTest, SetDeviceName) {
+// Test is flaky. crbug.com/1133295.
+#if defined(OS_CHROMEOS)
+#define MAYBE_SetDeviceName DISABLED_SetDeviceName
+#else
+#define MAYBE_SetDeviceName SetDeviceName
+#endif
+TEST_F(NearbyShareLocalDeviceDataManagerImplTest, MAYBE_SetDeviceName) {
   CreateManager();
 
   // The default device name is set in the ctor when the device name is empty.
diff --git a/chrome/browser/password_check/android/password_check_manager_unittest.cc b/chrome/browser/password_check/android/password_check_manager_unittest.cc
index c38db36c..0511a69 100644
--- a/chrome/browser/password_check/android/password_check_manager_unittest.cc
+++ b/chrome/browser/password_check/android/password_check_manager_unittest.cc
@@ -16,8 +16,8 @@
 #include "base/time/time.h"
 #include "chrome/browser/password_check/android/password_check_ui_status.h"
 #include "chrome/browser/password_manager/bulk_leak_check_service_factory.h"
+#include "chrome/browser/password_manager/password_manager_test_util.h"
 #include "chrome/browser/password_manager/password_scripts_fetcher_factory.h"
-#include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/password_manager/core/browser/bulk_leak_check_service.h"
@@ -97,19 +97,6 @@
   MOCK_METHOD(bool, IsScriptAvailable, (const url::Origin&), (const override));
 };
 
-// TODO(crbug.com/1112804): Extract this into a password manager test utils
-// file, since it's used across multiple tests.
-scoped_refptr<TestPasswordStore> CreateAndUseTestPasswordStore(
-    Profile* profile) {
-  return base::WrapRefCounted(static_cast<TestPasswordStore*>(
-      PasswordStoreFactory::GetInstance()
-          ->SetTestingFactoryAndUse(
-              profile,
-              base::BindRepeating(&password_manager::BuildPasswordStore<
-                                  content::BrowserContext, TestPasswordStore>))
-          .get()));
-}
-
 BulkLeakCheckService* CreateAndUseBulkLeakCheckService(
     signin::IdentityManager* identity_manager,
     Profile* profile) {
diff --git a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller_unittest.cc b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller_unittest.cc
index 205bb647..b9f2907 100644
--- a/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller_unittest.cc
+++ b/chrome/browser/password_manager/android/all_passwords_bottom_sheet_controller_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/mock_callback.h"
 #include "base/util/type_safety/pass_key.h"
-#include "chrome/browser/password_manager/password_store_factory.h"
+#include "chrome/browser/password_manager/password_manager_test_util.h"
 #include "chrome/browser/ui/android/passwords/all_passwords_bottom_sheet_view.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/autofill/core/common/mojom/autofill_types.mojom-forward.h"
@@ -82,17 +82,6 @@
   return form;
 }
 
-scoped_refptr<TestPasswordStore> CreateAndUseTestPasswordStore(
-    Profile* profile) {
-  return base::WrapRefCounted(static_cast<TestPasswordStore*>(
-      PasswordStoreFactory::GetInstance()
-          ->SetTestingFactoryAndUse(
-              profile,
-              base::BindRepeating(&password_manager::BuildPasswordStore<
-                                  content::BrowserContext, TestPasswordStore>))
-          .get()));
-}
-
 class AllPasswordsBottomSheetControllerTest : public testing::Test {
  protected:
   AllPasswordsBottomSheetControllerTest() {
diff --git a/chrome/browser/password_manager/password_manager_test_util.cc b/chrome/browser/password_manager/password_manager_test_util.cc
new file mode 100644
index 0000000..f896557
--- /dev/null
+++ b/chrome/browser/password_manager/password_manager_test_util.cc
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/password_manager_test_util.h"
+
+#include "chrome/browser/password_manager/password_store_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "components/password_manager/core/browser/test_password_store.h"
+
+using password_manager::TestPasswordStore;
+
+scoped_refptr<TestPasswordStore> CreateAndUseTestPasswordStore(
+    Profile* profile) {
+  TestPasswordStore* store = static_cast<TestPasswordStore*>(
+      PasswordStoreFactory::GetInstance()
+          ->SetTestingFactoryAndUse(
+              profile,
+              base::BindRepeating(&password_manager::BuildPasswordStore<
+                                  content::BrowserContext, TestPasswordStore>))
+          .get());
+  return base::WrapRefCounted(store);
+}
diff --git a/chrome/browser/password_manager/password_manager_test_util.h b/chrome/browser/password_manager/password_manager_test_util.h
new file mode 100644
index 0000000..c90800f2
--- /dev/null
+++ b/chrome/browser/password_manager/password_manager_test_util.h
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_MANAGER_TEST_UTIL_H_
+#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_MANAGER_TEST_UTIL_H_
+
+#include "base/memory/scoped_refptr.h"
+
+class Profile;
+namespace password_manager {
+class TestPasswordStore;
+}
+
+scoped_refptr<password_manager::TestPasswordStore>
+CreateAndUseTestPasswordStore(Profile* profile);
+
+#endif  // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_MANAGER_TEST_UTIL_H_
diff --git a/chrome/browser/password_manager/password_store_utils.cc b/chrome/browser/password_manager/password_store_utils.cc
index 08f26c6a..dc853f1 100644
--- a/chrome/browser/password_manager/password_store_utils.cc
+++ b/chrome/browser/password_manager/password_store_utils.cc
@@ -8,8 +8,14 @@
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_store.h"
 
+namespace {
+using password_manager::metrics_util::IsPasswordChanged;
+using password_manager::metrics_util::IsUsernameChanged;
+}  // namespace
+
 void EditSavedPasswords(
     Profile* profile,
     const base::span<const std::unique_ptr<autofill::PasswordForm>>
@@ -20,8 +26,10 @@
 
   const std::string signon_realm = forms_to_change[0]->signon_realm;
 
-  const bool username_changed =
-      new_username != forms_to_change[0]->username_value;
+  IsUsernameChanged username_changed(new_username !=
+                                     forms_to_change[0]->username_value);
+  IsPasswordChanged password_changed(new_password !=
+                                     forms_to_change[0]->password_value);
 
   // An updated username implies a change in the primary key, thus we need to
   // make sure to call the right API. Update every entry in the equivalence
@@ -47,6 +55,8 @@
       store->UpdateLogin(new_form);
     }
   }
+  password_manager::metrics_util::LogPasswordEditResult(username_changed,
+                                                        password_changed);
 }
 
 scoped_refptr<password_manager::PasswordStore> GetPasswordStore(
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index b6c26dc..8db2e78 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -709,6 +709,9 @@
   { key::kURLsToNotCheckComplianceOfUploadedContent,
     prefs::kURLsToNotCheckComplianceOfUploadedContent,
     base::Value::Type::LIST },
+  { key::kWebRtcAllowLegacyTLSProtocols,
+    prefs::kWebRTCAllowLegacyTLSProtocols,
+    base::Value::Type::BOOLEAN },
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index b841f58..ca36c316 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -9,6 +9,7 @@
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/net/profile_network_context_service.h"
@@ -64,6 +65,10 @@
 #include "extensions/browser/pref_names.h"
 #endif
 
+#if BUILDFLAG(IS_LACROS)
+#include "chromeos/lacros/lacros_chrome_service_impl.h"
+#endif
+
 #if DCHECK_IS_ON()
 
 #include <set>
@@ -376,8 +381,17 @@
           chromeos::switches::kGuestSession);
   return is_guest_session;
 #else
+#if BUILDFLAG(IS_LACROS)
+  DCHECK(chromeos::LacrosChromeServiceImpl::Get());
+  if (chromeos::LacrosChromeServiceImpl::Get()->init_params()->session_type !=
+      crosapi::mojom::SessionType::kUnknown) {
+    return chromeos::LacrosChromeServiceImpl::Get()
+               ->init_params()
+               ->session_type == crosapi::mojom::SessionType::kGuestSession;
+  }
+#endif  // BUILDFLAG(IS_LACROS)
   return is_guest_profile_;
-#endif
+#endif  // defined(OS_CHROMEOS)
 }
 
 bool Profile::IsSystemProfile() const {
diff --git a/chrome/browser/profiles/profiles_state.cc b/chrome/browser/profiles/profiles_state.cc
index b338e9f..169aaf1f 100644
--- a/chrome/browser/profiles/profiles_state.cc
+++ b/chrome/browser/profiles/profiles_state.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/profiles/profile.h"
@@ -40,6 +41,10 @@
 #include "components/signin/public/base/signin_pref_names.h"
 #endif
 
+#if BUILDFLAG(IS_LACROS)
+#include "chromeos/lacros/lacros_chrome_service_impl.h"
+#endif
+
 namespace profiles {
 
 bool IsMultipleProfilesEnabled() {
@@ -262,6 +267,11 @@
   if (chromeos::LoginState::IsInitialized()) {
     return chromeos::LoginState::Get()->IsPublicSessionUser();
   }
+#elif BUILDFLAG(IS_LACROS)
+  DCHECK(chromeos::LacrosChromeServiceImpl::Get());
+  return chromeos::LacrosChromeServiceImpl::Get()
+             ->init_params()
+             ->session_type == crosapi::mojom::SessionType::kPublicSession;
 #endif
   return false;
 }
diff --git a/chrome/browser/renderer_preferences_util.cc b/chrome/browser/renderer_preferences_util.cc
index 7ba5b3d..ddc3c1d 100644
--- a/chrome/browser/renderer_preferences_util.cc
+++ b/chrome/browser/renderer_preferences_util.cc
@@ -141,6 +141,8 @@
   const base::ListValue* allowed_urls =
       pref_service->GetList(prefs::kWebRtcLocalIpsAllowedUrls);
   prefs->webrtc_local_ips_allowed_urls = GetLocalIpsAllowedUrls(allowed_urls);
+  prefs->webrtc_allow_legacy_tls_protocols =
+      pref_service->GetBoolean(prefs::kWebRTCAllowLegacyTLSProtocols);
 #if defined(USE_AURA)
   prefs->focus_ring_color = SkColorSetRGB(0x4D, 0x90, 0xFE);
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index ddf68c4..60ea26a 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -510,13 +510,18 @@
   }
 
   grit("profile_picker_resources") {
-    source = "signin/profile_picker/profile_picker_resources.grd"
-
-    deps = [ "//chrome/browser/resources/signin/profile_picker:web_components" ]
     grit_flags = [
       "-E",
       "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
     ]
+    if (optimize_webui) {
+      source = "signin/profile_picker/profile_picker_resources_vulcanized.grd"
+      deps = [ "//chrome/browser/resources/signin/profile_picker:build" ]
+    } else {
+      source = "signin/profile_picker/profile_picker_resources.grd"
+      deps =
+          [ "//chrome/browser/resources/signin/profile_picker:web_components" ]
+    }
 
     defines = chrome_grit_defines
     outputs = [
diff --git a/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html
new file mode 100644
index 0000000..c830eb3d
--- /dev/null
+++ b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.html
@@ -0,0 +1,129 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+
+<head>
+  <include src="../login/components/oobe_icons.html">
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+
+  <script src="chrome://resources/js/cr.js"></script>
+  <script src="chrome://resources/js/cr/event_target.js"></script>
+  <script src="chrome://resources/js/load_time_data.js"></script>
+  <script src="chrome://resources/js/util.js"></script>
+  <script src="chrome://lock-reauth/authenticator.js"></script>
+
+  <script type="module" src="chrome://lock-reauth/lock_screen_reauth.js"></script>
+
+  <dom-module id="lock-reauth">
+    <template>
+      <style>
+        ::part(dialog) {
+          /* The HTML dialog should fill the entire system dialog. */
+          height: 100%;
+          width: 100%;
+          display: flex;
+        }
+
+        ::part(wrapper) {
+          height: 100%;
+          width: 100%;
+          display: flex;
+        }
+
+        #saml-close-button {
+          --cr-icon-button-margin-end: 0;
+          --cr-icon-button-margin-start: 0;
+        }
+
+        [slot='body'],
+        #signin-frame {
+          width: 100%;
+          height: 100%;
+        }
+
+        #title-icon {
+          --iron-icon-height: 32px;
+          --iron-icon-width: 32px;
+          /* #1a73e8 */
+          --iron-icon-fill-color: rgb(26, 115, 232);
+        }
+
+        [slot='header'] {
+          background: white;
+          padding-bottom: 0;
+          padding-inline-end: 64px;
+          padding-inline-start: 64px;
+          padding-top: 64px;
+          flex: 1;
+        }
+
+        [slot='header'],
+        #title {
+          /* #202124 */
+          color: rgb(32, 33, 36);
+          font-size: 28px;
+          font-weight: 400;
+          padding-top: 20px;
+          margin: 0;
+        }
+
+        [slot='header'],
+        #subtitle {
+          /* #5f6368 */
+          color: rgb(95, 99, 104);
+          font-size: 13px;
+          font-weight: 400;
+          padding-top: 8px;
+          margin: 0;
+        }
+
+        [slot="button-container"] {
+          padding: 40px;
+        }
+      </style>
+      <cr-dialog id="dialog" exportparts="dialog">
+        <div slot="header">
+          <iron-icon id="title-icon" icon="oobe-64:alert"></iron-icon>
+          <div id="title" hidden="[[isErrorDisplayed_]]">
+            $i18n{loginWelcomeMessage}
+          </div>
+          <div id="title" hidden="[[!isErrorDisplayed_]]">
+            $i18n{loginWelcomeMessageWithError}
+          </div>
+          <div id="subtitle" hidden="[[isErrorDisplayed_]]">
+            $i18n{lockScreenReauthSubtitile}
+          </div>
+          <div id="subtitle" hidden="[[!isErrorDisplayed_]]">
+            $i18n{lockScreenReauthSubtitileWithError}
+          </div>
+        </div>
+        <div slot="body" hidden="[[isButtonsEnabled_]]">
+          <cr-icon-button id="saml-close-button" iron-icon="cr:close" on-click="onCloseTap_">
+          </cr-icon-button>
+          <webview id="signin-frame" name="signin-frame" class="flex">
+          </webview>
+        </div>
+        <div slot="button-container" class="flex layout horizontal">
+          <cr-button id="cancelButton" class="cancel-button" on-click="onCloseTap_"
+              hidden="[[!isButtonsEnabled_]]">
+            $i18n{lockScreenCancelButton}
+          </cr-button>
+          <cr-button id="nextButton" class="action-button" on-click="onNext_"
+              hidden="[[!isVerifyButtonEnabled_]]">
+            $i18n{lockScreenVerifyButton}
+          </cr-button>
+          <cr-button id="nextButton" class="action-button" on-click="onNext_"
+              hidden="[[!isVerifyAgainButtonEnabled_]]">
+            $i18n{lockScreenVerifyAgainButton}
+          </cr-button>
+        </div>
+      </cr-dialog>
+    </template>
+  </dom-module>
+</head>
+
+<body>
+  <lock-reauth id="main-element">
+  </lock-reauth>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.js b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.js
new file mode 100644
index 0000000..fd9503d5
--- /dev/null
+++ b/chrome/browser/resources/chromeos/password_change/lock_screen_reauth.js
@@ -0,0 +1,106 @@
+// 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.
+
+/**
+ * @fileoverview An UI component to let user init online re-auth flow on
+ * the lock screen.
+ */
+
+
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
+import 'chrome://resources/cr_elements/icons.m.js';
+
+
+Polymer({
+  is: 'lock-reauth',
+  behaviors: [I18nBehavior],
+
+  properties: {
+    isErrorDisplayed_: {
+      type: Boolean,
+      value: false,
+    },
+
+    isButtonsEnabled_: {
+      type: Boolean,
+      value: true,
+    },
+
+    isVerifyButtonEnabled_: {
+      type: Boolean,
+      computed:
+          'computeVerifyButtonEnabled_(isErrorDisplayed_,isButtonsEnabled_)',
+    },
+
+    isVerifyAgainButtonEnabled_: {
+      type: Boolean,
+      computed:
+          'computeVerifyAgainButtonEnabled_(isErrorDisplayed_,isButtonsEnabled_)',
+    },
+  },
+
+  /**
+   * The UI component that hosts IdP pages.
+   * @type {!cr.login.Authenticator|undefined}
+   */
+  authenticator_: undefined,
+
+  /**
+   * Webview that view IdP page
+   * @type {!webview|undefined}
+   * @private
+   */
+  signinFrame_: undefined,
+
+  /** @override */
+  attached() {
+    this.$.dialog.showModal();
+  },
+
+  /** @override */
+  ready() {
+    this.signinFrame_ = this.getSigninFrame_();
+    this.authenticator_ = new cr.login.Authenticator(this.signinFrame_);
+    chrome.send('initialize');
+  },
+
+  /**
+   * @return {!Element}
+   * @private
+   */
+  getSigninFrame_() {
+    // Note: Can't use |this.$|, since it returns cached references to elements
+    // originally present in DOM, while the signin-frame is dynamically
+    // recreated (see Authenticator.setWebviewPartition()).
+    const signinFrame = this.shadowRoot.getElementById('signin-frame');
+    assert(signinFrame);
+    return signinFrame;
+  },
+
+  /** @private */
+  computeVerifyButtonEnabled_(isErrorDisplayed, isButtonsEnabled) {
+    return !isErrorDisplayed && isButtonsEnabled;
+  },
+
+  /** @private */
+  computeVerifyAgainButtonEnabled_(isErrorDisplayed, isButtonsEnabled) {
+    return isErrorDisplayed && isButtonsEnabled;
+  },
+
+  /** @private */
+  onNext_() {
+    this.isButtonsEnabled_ = false;
+  },
+
+  /** @private */
+  onCloseTap_() {
+    chrome.send('dialogClose');
+  },
+
+});
diff --git a/chrome/browser/resources/gaia_auth_host/post_message_channel.js b/chrome/browser/resources/gaia_auth_host/post_message_channel.js
index 0fab561d..c8bbd4a 100644
--- a/chrome/browser/resources/gaia_auth_host/post_message_channel.js
+++ b/chrome/browser/resources/gaia_auth_host/post_message_channel.js
@@ -20,8 +20,12 @@
    * Allowed origins of the hosting page.
    * @type {Array<string>}
    */
-  const ALLOWED_ORIGINS =
-      ['chrome://oobe', 'chrome://chrome-signin', 'chrome://password-change'];
+  const ALLOWED_ORIGINS = [
+    'chrome://oobe',
+    'chrome://chrome-signin',
+    'chrome://password-change',
+    'chrome://lock-reauth'
+  ];
 
   /** @const */
   const PORT_MESSAGE = 'post-message-port-message';
diff --git a/chrome/browser/resources/new_tab_page/app.js b/chrome/browser/resources/new_tab_page/app.js
index 915ea2d..f4ee9ed 100644
--- a/chrome/browser/resources/new_tab_page/app.js
+++ b/chrome/browser/resources/new_tab_page/app.js
@@ -323,7 +323,9 @@
   async loadOneGoogleBar_() {
     if (this.iframeOneGoogleBarEnabled_) {
       const oneGoogleBar = document.querySelector('#oneGoogleBar');
-      oneGoogleBar.remove();
+      if (oneGoogleBar) {
+        oneGoogleBar.remove();
+      }
       return;
     }
 
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn
index 4c41b69..2cb2c36 100644
--- a/chrome/browser/resources/print_preview/BUILD.gn
+++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -136,7 +136,6 @@
       "ui/destination_dropdown_cros.js",
       "ui/destination_select_cros.js",
       "ui/pin_settings.js",
-      "ui/printer_status_icon_cros.js",
     ]
   } else {
     in_files += [
diff --git a/chrome/browser/resources/print_preview/data/printer_status_cros.js b/chrome/browser/resources/print_preview/data/printer_status_cros.js
index 0a8ac4a0..4a4907e 100644
--- a/chrome/browser/resources/print_preview/data/printer_status_cros.js
+++ b/chrome/browser/resources/print_preview/data/printer_status_cros.js
@@ -51,16 +51,6 @@
 };
 
 /**
- * Enumeration used to choose styling based on whether this icon is located in
- * the destination display or the destination dropdown.
- * @enum {number}
- */
-export const IconLocation = {
-  DISPLAY: 0,
-  DROPDOWN: 1,
-};
-
-/**
  * A container for the results of a printer status query. A printer status query
  * can return multiple error reasons. |timestamp| is set at the time of status
  * creation.
diff --git a/chrome/browser/resources/print_preview/ui/BUILD.gn b/chrome/browser/resources/print_preview/ui/BUILD.gn
index 4954831e..9542918 100644
--- a/chrome/browser/resources/print_preview/ui/BUILD.gn
+++ b/chrome/browser/resources/print_preview/ui/BUILD.gn
@@ -56,7 +56,6 @@
       ":destination_dropdown_cros",
       ":destination_select_cros",
       ":pin_settings",
-      ":printer_status_icon_cros",
     ]
   } else {
     deps += [ ":destination_select" ]
@@ -187,19 +186,12 @@
 
   js_library("destination_dropdown_cros") {
     deps = [
-      ":printer_status_icon_cros",
       "..:print_preview_utils",
       "//third_party/polymer/v3_0/components-chromium/iron-dropdown:iron-dropdown",
       "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
       "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
     ]
   }
-
-  js_library("printer_status_icon_cros") {
-    deps = [
-      "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    ]
-  }
 } else {
   js_library("destination_select") {
     deps = [
@@ -571,7 +563,6 @@
       "destination_dropdown_cros.js",
       "destination_select_cros.js",
       "pin_settings.js",
-      "printer_status_icon_cros.js",
     ]
   } else {
     js_files += [ "destination_select.js" ]
diff --git a/chrome/browser/resources/print_preview/ui/printer_status_icon_cros.html b/chrome/browser/resources/print_preview/ui/printer_status_icon_cros.html
deleted file mode 100644
index 542255b6..0000000
--- a/chrome/browser/resources/print_preview/ui/printer_status_icon_cros.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<style include="cr-shared-style">
-  div {
-    display: inline;
-    position: relative;
-  }
-
-  .badge {
-    border-radius: 50%;
-    display: inline-block;
-    position: absolute;
-    --status-badge-radius: 8px;
-    --background-badge-radius: 12px;
-    --background-badge-left: 12px;
-    --background-badge-top: 6px;
-  }
-
-  :host-context([dir='rtl']) .badge {
-    --background-badge-left: -4px;
-  }
-
-  #status-badge {
-    height: var(--status-badge-radius);
-    left: calc(var(--background-badge-left) + (var(--background-badge-radius) - var(--status-badge-radius))/2);
-    top: calc(var(--background-badge-top) + (var(--background-badge-radius) - var(--status-badge-radius))/2);
-    width: var(--status-badge-radius);
-  }
-
-  :host([printer-state='0']) #status-badge {
-    background-color: var(--google-green-700);
-  }
-
-  :host([printer-state='1']) #status-badge {
-    background-color: var(--google-red-600);
-  }
-
-  :host([printer-state='2']) #status-badge {
-    background-color: var(--google-grey-500);
-  }
-
-  :host-context([dir='rtl']) #status-badge {
-    right: calc(var(--background-badge-left) + (var(--background-badge-radius) - var(--status-badge-radius))/2);
-  }
-
-  #background-badge {
-    height: var(--background-badge-radius);
-    left: var(--background-badge-left);
-    top: var(--background-badge-top);
-    width: var(--background-badge-radius);
-  }
-
-  :host([icon-location='0']) #background-badge {
-    background-color: var(--google-grey-refresh-100);
-  }
-
-  :host([icon-location='1']) #background-badge {
-    background-color: white;
-  }
-
-  :host-context([dir='rtl']) #background-badge {
-    right: var(--background-badge-left);
-  }
-
-  :host-context(.highlighted) #background-badge {
-    background-color: var(--google-blue-refresh-100);
-  }
-</style>
-<div>
-  <iron-icon icon="print-preview:print"></iron-icon>
-  <span id="background-badge" class="badge"></span>
-  <span id="status-badge" class="badge"></span>
-</div>
diff --git a/chrome/browser/resources/print_preview/ui/printer_status_icon_cros.js b/chrome/browser/resources/print_preview/ui/printer_status_icon_cros.js
deleted file mode 100644
index 6984175..0000000
--- a/chrome/browser/resources/print_preview/ui/printer_status_icon_cros.js
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://resources/cr_elements/shared_vars_css.m.js';
-import './icons.js';
-
-import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-
-import {IconLocation, PrinterState} from '../data/printer_status_cros.js';
-
-Polymer({
-  is: 'printer-status-icon-cros',
-
-  properties: {
-    /** Determines color of the background badge. */
-    background: String,
-
-    /**
-     * State of the associated printer. Determines color of the status badge.
-     * @type {!PrinterState}
-     */
-    printerState: {
-      type: Number,
-      reflectToAttribute: true,
-    },
-
-    /**
-     * Location of this icon. Determines color of the background badge.
-     * @type {!IconLocation}
-     */
-    iconLocation: {
-      type: Number,
-      reflectToAttribute: true,
-    },
-  },
-
-  _template: html`{__html_template__}`,
-
-});
diff --git a/chrome/browser/resources/settings/autofill_page/password_edit_dialog.js b/chrome/browser/resources/settings/autofill_page/password_edit_dialog.js
index 142eefe..2e05bc2 100644
--- a/chrome/browser/resources/settings/autofill_page/password_edit_dialog.js
+++ b/chrome/browser/resources/settings/autofill_page/password_edit_dialog.js
@@ -70,7 +70,7 @@
      * Check if editPasswordsInSettings flag is true and entry isn't federation
      * credential.
      * @private
-     * */
+     */
     isEditDialog_: {
       type: Boolean,
       computed: 'computeIsEditDialog_(editPasswordsInSettings_, entry)'
@@ -118,21 +118,21 @@
                     .map(item => item.username));
   },
 
+  /** Closes the dialog. */
+  close() {
+    this.$.dialog.close();
+  },
+
   /**
    * Helper function that checks if editPasswordsInSettings flag is true and
    * entry isn't federation credential.
    * @return {boolean}
    * @private
-   * */
+   */
   computeIsEditDialog_() {
     return this.editPasswordsInSettings_ && !this.entry.federationText;
   },
 
-  /** Closes the dialog. */
-  close() {
-    this.$.dialog.close();
-  },
-
   /**
    * Handler for tapping the 'cancel' button. Should just dismiss the dialog.
    * @private
@@ -251,7 +251,10 @@
     return this.isEditDialog_ ? this.i18n('save') : this.i18n('done');
   },
 
-  /** Manually de-select texts for readonly inputs. */
+  /**
+   * Manually de-select texts for readonly inputs.
+   * @private
+   */
   onInputBlur_() {
     this.shadowRoot.getSelection().removeAllRanges();
   },
@@ -259,6 +262,7 @@
   /**
    * Gets the HTML-formatted message to indicate in which locations the password
    * is stored.
+   * @private
    */
   getStorageDetailsMessage_() {
     if (this.entry.isPresentInAccount() && this.entry.isPresentOnDevice()) {
diff --git a/chrome/browser/resources/settings/autofill_page/password_move_to_account_dialog.js b/chrome/browser/resources/settings/autofill_page/password_move_to_account_dialog.js
index 0ecb377..b5a9d42 100644
--- a/chrome/browser/resources/settings/autofill_page/password_move_to_account_dialog.js
+++ b/chrome/browser/resources/settings/autofill_page/password_move_to_account_dialog.js
@@ -42,9 +42,7 @@
   behaviors: [I18nBehavior],
 
   properties: {
-    /**
-     * @type {!MultiStorePasswordUiEntry}
-     */
+    /** @type {!MultiStorePasswordUiEntry} */
     passwordToMove: Object,
 
   },
@@ -60,9 +58,7 @@
     this.$.dialog.showModal();
   },
 
-  /**
-   * @private
-   */
+  /** @private */
   onMoveButtonClick_() {
     assert(this.passwordToMove.isPresentOnDevice());
     PasswordManagerImpl.getInstance()
@@ -71,9 +67,7 @@
     this.$.dialog.close();
   },
 
-  /**
-   * @private
-   */
+  /** @private */
   onCancelButtonClick_() {
     this.$.dialog.close();
   }
diff --git a/chrome/browser/resources/settings/autofill_page/password_remove_dialog.js b/chrome/browser/resources/settings/autofill_page/password_remove_dialog.js
index 8dd3b91..7ba17a4 100644
--- a/chrome/browser/resources/settings/autofill_page/password_remove_dialog.js
+++ b/chrome/browser/resources/settings/autofill_page/password_remove_dialog.js
@@ -44,9 +44,7 @@
      */
     duplicatedPassword: Object,
 
-    /**
-     * @private
-     */
+    /** @private */
     removeFromAccountChecked_: {
       type: Boolean,
       // Both checkboxes are selected by default (see |removeFromDeviceChecked_|
@@ -54,17 +52,13 @@
       value: true,
     },
 
-    /**
-     * @private
-     */
+    /** @private */
     removeFromDeviceChecked_: {
       type: Boolean,
       value: true,
     },
 
-    /**
-     * @private
-     */
+    /** @private */
     accountEmail_: {
       type: String,
       value: '',
@@ -89,9 +83,7 @@
     });
   },
 
-  /**
-   * @private
-   */
+  /** @private */
   onRemoveButtonClick_() {
     /** @type{!Array<number>} */
     const idsToRemove = [];
@@ -110,9 +102,7 @@
     });
   },
 
-  /**
-   * @private
-   */
+  /** @private */
   onCancelButtonClick_() {
     this.$.dialog.close();
   },
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_device_section.js b/chrome/browser/resources/settings/autofill_page/passwords_device_section.js
index 442b237..97ed8162 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_device_section.js
+++ b/chrome/browser/resources/settings/autofill_page/passwords_device_section.js
@@ -29,7 +29,7 @@
 import {GlobalScrollTargetBehavior} from '../global_scroll_target_behavior.m.js';
 import {loadTimeData} from '../i18n_setup.js';
 import {OpenWindowProxyImpl} from '../open_window_proxy.js';
-import {StoredAccount, SyncBrowserProxyImpl, SyncStatus} from '../people_page/sync_browser_proxy.m.js';
+import {StoredAccount, SyncBrowserProxyImpl} from '../people_page/sync_browser_proxy.m.js';
 import {routes} from '../route.js';
 import {Route, RouteObserverBehavior, Router} from '../router.m.js';
 
@@ -89,8 +89,7 @@
 
     /**
      * Passwords displayed in the device-only subsection.
-     * @type {!Array<!MultiStorePasswordUiEntry>}
-     * @private
+     * @private {!Array<!MultiStorePasswordUiEntry>}
      */
     deviceOnlyPasswords_: {
       type: Array,
@@ -101,8 +100,7 @@
 
     /**
      * Passwords displayed in the 'device and account' subsection.
-     * @type {!Array<!MultiStorePasswordUiEntry>}
-     * @private
+     * @private {!Array<!MultiStorePasswordUiEntry>}
      */
     deviceAndAccountPasswords_: {
       type: Array,
@@ -120,6 +118,7 @@
     /** @private */
     accountEmail_: String,
 
+    /** @private */
     isUserAllowedToAccessPage_: {
       type: Boolean,
       computed: 'computeIsUserAllowedToAccessPage_(signedIn_, syncDisabled_,' +
@@ -128,8 +127,7 @@
 
     /**
      * Whether the user is signed in, one of the requirements to view this page.
-     * @private
-     * @type {boolean?}
+     * @private {boolean?}
      */
     signedIn_: {
       type: Boolean,
@@ -138,8 +136,7 @@
 
     /**
      * Whether Sync is disabled, one of the requirements to view this page.
-     * @private
-     * @type {boolean?}
+     * @private {boolean?}
      */
     syncDisabled_: {
       type: Boolean,
@@ -149,18 +146,14 @@
     /**
      * Whether the user has opted in to the account-scoped password storage, one
      * of the requirements to view this page.
-     * @private
-     * @type {boolean?}
+     * @private {boolean?}
      */
     optedInForAccountStorage_: {
       type: Boolean,
       value: null,
     },
 
-    /**
-     * @private
-     * @type {Route?}
-     */
+    /** @private {Route?} */
     currentRoute_: {
       type: Object,
       value: null,
@@ -168,13 +161,22 @@
 
   },
 
+  keyBindings: {
+    // <if expr="is_macosx">
+    'meta+z': 'onUndoKeyBinding_',
+    // </if>
+    // <if expr="not is_macosx">
+    'ctrl+z': 'onUndoKeyBinding_',
+    // </if>
+  },
+
+  /** @private {!function(boolean): void} */
+  accountStorageOptInStateListener_: Function,
+
   observers:
       ['maybeRedirectToPasswordsPage_(isUserAllowedToAccessPage_, ' +
        'currentRoute_)'],
 
-  /** @type {!function(boolean): void} */
-  accountStorageOptInStateListener_: Function,
-
   /** @override */
   attached() {
     this.addListenersForAccountStorageRequirements_();
@@ -197,59 +199,6 @@
   },
 
   /**
-   * @private
-   */
-  addListenersForAccountStorageRequirements_() {
-    const setSyncDisabled = syncStatus => {
-      this.syncDisabled_ = !syncStatus.signedIn;
-    };
-    SyncBrowserProxyImpl.getInstance().getSyncStatus().then(setSyncDisabled);
-    this.addWebUIListener('sync-status-changed', setSyncDisabled);
-
-    const setSignedIn = storedAccounts => {
-      this.signedIn_ = storedAccounts.length > 0;
-    };
-    SyncBrowserProxyImpl.getInstance().getStoredAccounts().then(setSignedIn);
-    this.addWebUIListener('stored-accounts-updated', setSignedIn);
-
-    const setOptedIn = optedInForAccountStorage => {
-      this.optedInForAccountStorage_ = optedInForAccountStorage;
-    };
-    PasswordManagerImpl.getInstance().isOptedInForAccountStorage().then(
-        setOptedIn);
-    PasswordManagerImpl.getInstance().addAccountStorageOptInStateListener(
-        setOptedIn);
-    this.accountStorageOptInStateListener_ = setOptedIn;
-  },
-
-  /**
-   * From RouteObserverBehavior.
-   * @param {!Route|undefined} route
-   * @protected
-   */
-  currentRouteChanged(route) {
-    this.currentRoute_ = route || null;
-  },
-
-  /**
-   * @param {!Array<!MultiStorePasswordUiEntry>} passwords
-   * @return {boolean}
-   * @private
-   */
-  isNonEmpty_(passwords) {
-    return passwords.length > 0;
-  },
-
-  keyBindings: {
-    // <if expr="is_macosx">
-    'meta+z': 'onUndoKeyBinding_',
-    // </if>
-    // <if expr="not is_macosx">
-    'ctrl+z': 'onUndoKeyBinding_',
-    // </if>
-  },
-
-  /**
    * @return {!Array<!MultiStorePasswordUiEntry>}
    * @private
    */
@@ -281,6 +230,48 @@
   },
 
   /**
+   * From RouteObserverBehavior.
+   * @param {!Route|undefined} route
+   * @protected
+   */
+  currentRouteChanged(route) {
+    this.currentRoute_ = route || null;
+  },
+
+  /** @private */
+  addListenersForAccountStorageRequirements_() {
+    const setSyncDisabled = syncStatus => {
+      this.syncDisabled_ = !syncStatus.signedIn;
+    };
+    SyncBrowserProxyImpl.getInstance().getSyncStatus().then(setSyncDisabled);
+    this.addWebUIListener('sync-status-changed', setSyncDisabled);
+
+    const setSignedIn = storedAccounts => {
+      this.signedIn_ = storedAccounts.length > 0;
+    };
+    SyncBrowserProxyImpl.getInstance().getStoredAccounts().then(setSignedIn);
+    this.addWebUIListener('stored-accounts-updated', setSignedIn);
+
+    const setOptedIn = optedInForAccountStorage => {
+      this.optedInForAccountStorage_ = optedInForAccountStorage;
+    };
+    PasswordManagerImpl.getInstance().isOptedInForAccountStorage().then(
+        setOptedIn);
+    PasswordManagerImpl.getInstance().addAccountStorageOptInStateListener(
+        setOptedIn);
+    this.accountStorageOptInStateListener_ = setOptedIn;
+  },
+
+  /**
+   * @param {!Array<!MultiStorePasswordUiEntry>} passwords
+   * @return {boolean}
+   * @private
+   */
+  isNonEmpty_(passwords) {
+    return passwords.length > 0;
+  },
+
+  /**
    * @param {!Array<!MultiStorePasswordUiEntry>} passwords
    * @param {string} filter
    * @return {!Array<!MultiStorePasswordUiEntry>}
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.html b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.html
index 0ead0c2e..23d780f 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.html
+++ b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.html
@@ -13,7 +13,7 @@
 
     <cr-action-menu id="menu" role-description="$i18n{menu}">
       <button id="menuCopyPassword" class="dropdown-item"
-          hidden$="[[activePassword.entry.federationText]]"
+          hidden$="[[activePassword_.entry.federationText]]"
           on-click="onMenuCopyPasswordButtonTap_">$i18n{copyPassword}</button>
       <button id="menuEditPassword" class="dropdown-item"
           on-click="onMenuEditPasswordTap_">
@@ -23,7 +23,7 @@
           on-click="onMenuRemovePasswordTap_">$i18n{removePassword}</button>
       <button id="menuMovePasswordToAccount"
           on-click="onMenuMovePasswordToAccountTap_"
-          hidden$="[[!shouldShowMoveToAccountOption_(activePassword,
+          hidden$="[[!shouldShowMoveToAccountOption_(activePassword_,
               allowMoveToAccountOption, firstSignedInAccountEmail_)]]"
           class="dropdown-item">$i18n{movePasswordToAccount}</button>
     </cr-action-menu>
@@ -34,21 +34,21 @@
 <if expr="chromeos">
           token-request-manager="[[tokenRequestManager]]"
 </if>
-          entry="[[activePassword.entry]]" saved-passwords="[[savedPasswords]]"
+          entry="[[activePassword_.entry]]" saved-passwords="[[savedPasswords]]"
           should-show-storage-details="[[shouldShowStorageDetails]]">
       </password-edit-dialog>
     </template>
 
     <template is="dom-if" if="[[showPasswordMoveToAccountDialog_]]" restamp>
       <password-move-to-account-dialog id="passwordMoveToAccountDialog"
-          password-to-move="[[activePassword.entry]]"
+          password-to-move="[[activePassword_.entry]]"
           on-close="onPasswordMoveToAccountDialogClosed_">
       </password-move-to-account-dialog>
     </template>
 
     <template is="dom-if" if="[[showPasswordRemoveDialog_]]" restamp>
       <password-remove-dialog id="passwordRemoveDialog"
-          duplicated-password="[[activePassword.entry]]"
+          duplicated-password="[[activePassword_.entry]]"
           on-close="onPasswordRemoveDialogClosed_">
       </password-remove-dialog>
     </template>
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js
index 982055ee5..0082dea 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js
+++ b/chrome/browser/resources/settings/autofill_page/passwords_list_handler.js
@@ -39,6 +39,11 @@
 
   _template: html`{__html_template__}`,
 
+  behaviors: [
+    I18nBehavior,
+    WebUIListenerBehavior,
+  ],
+
   properties: {
     /**
      * Saved passwords after deduplicating versions that are repeated in the
@@ -51,16 +56,6 @@
     },
 
     /**
-     * The model for any active menus or dialogs. The value is reset to null
-     * whenever actions from the menus/dialogs are concluded.
-     * @private {?PasswordListItemElement}
-     */
-    activePassword: {
-      type: Object,
-      value: null,
-    },
-
-    /**
      * Whether the edit dialog and removal notification should show information
      * about which location(s) a password is stored.
      */
@@ -83,6 +78,16 @@
     tokenRequestManager: Object,
     // </if>
 
+    /**
+     * The model for any active menus or dialogs. The value is reset to null
+     * whenever actions from the menus/dialogs are concluded.
+     * @private {?PasswordListItemElement}
+     */
+    activePassword_: {
+      type: Object,
+      value: null,
+    },
+
     /** @private */
     editPasswordsInSettings_: {
       type: Boolean,
@@ -95,10 +100,11 @@
      * Check if editPasswordsInSettings flag is true and entry isn't federation
      * credential.
      * @private
-     * */
+     */
     isEditDialog_: {
       type: Boolean,
-      computed: 'computeIsEditDialog_(editPasswordsInSettings_, activePassword)'
+      computed:
+          'computeIsEditDialog_(editPasswordsInSettings_, activePassword_)'
     },
 
     /** @private */
@@ -137,20 +143,15 @@
     }
   },
 
-  behaviors: [
-    I18nBehavior,
-    WebUIListenerBehavior,
-  ],
-
-  listeners: {
-    'password-more-actions-clicked': 'onPasswordMoreActionsClicked_',
-    'password-remove-dialog-passwords-removed':
-        'onPasswordRemoveDialogPasswordsRemoved_',
-  },
-
   /** @private {?PasswordManagerProxy} */
   passwordManager_: null,
 
+  listeners: {
+    'password-more-actions-clicked': 'passwordMoreActionsClickedHandler_',
+    'password-remove-dialog-passwords-removed':
+        'passwordRemoveDialogPasswordsRemovedHandler_',
+  },
+
   /** @override */
   attached() {
     this.passwordManager_ = PasswordManagerImpl.getInstance();
@@ -172,17 +173,6 @@
   },
 
   /**
-   * Helper function that checks if editPasswordsInSettings flag is true and
-   * entry isn't federation credential.
-   * @return {boolean}
-   * @private
-   * */
-  computeIsEditDialog_() {
-    return this.editPasswordsInSettings_ &&
-        (!this.activePassword || !this.activePassword.entry.federationText);
-  },
-
-  /**
    * Closes the toast manager.
    */
   onSavedPasswordOrExceptionRemoved() {
@@ -194,15 +184,35 @@
    * @param {PasswordMoreActionsClickedEvent} event
    * @private
    */
-  onPasswordMoreActionsClicked_(event) {
+  passwordMoreActionsClickedHandler_(event) {
     const target = event.detail.target;
 
-    this.activePassword = event.detail.listItem;
+    this.activePassword_ = event.detail.listItem;
     this.$.menu.showAt(target);
     this.activeDialogAnchor_ = target;
   },
 
   /**
+   * @param {PasswordRemoveDialogPasswordsRemovedEvent} event
+   * @private
+   */
+  passwordRemoveDialogPasswordsRemovedHandler_(event) {
+    this.displayRemovalNotification_(
+        event.detail.removedFromAccount, event.detail.removedFromDevice);
+  },
+
+  /**
+   * Helper function that checks if editPasswordsInSettings flag is true and
+   * entry isn't federation credential.
+   * @return {boolean}
+   * @private
+   */
+  computeIsEditDialog_() {
+    return this.editPasswordsInSettings_ &&
+        (!this.activePassword_ || !this.activePassword_.entry.federationText);
+  },
+
+  /**
    * Requests the plaintext password for the current active password.
    * @param {!chrome.passwordsPrivate.PlaintextReason} reason The reason why the
    *     plaintext password is requested.
@@ -212,7 +222,7 @@
    */
   requestActivePlaintextPassword_(reason, callback) {
     this.passwordManager_
-        .requestPlaintextPassword(this.activePassword.entry.getAnyId(), reason)
+        .requestPlaintextPassword(this.activePassword_.entry.getAnyId(), reason)
         .then(callback, error => {
           // <if expr="chromeos">
           // If no password was found, refresh auth token and retry.
@@ -228,14 +238,14 @@
     if (this.isEditDialog_) {
       this.requestActivePlaintextPassword_(
           chrome.passwordsPrivate.PlaintextReason.EDIT, password => {
-            this.set('activePassword.entry.password', password);
+            this.set('activePassword_.entry.password', password);
             this.showPasswordEditDialog_ = true;
           });
     } else {
       this.showPasswordEditDialog_ = true;
     }
     this.$.menu.close();
-    this.activePassword.hide();
+    this.activePassword_.hide();
   },
 
   /**
@@ -252,8 +262,8 @@
     this.showPasswordEditDialog_ = false;
     focusWithoutInk(assert(this.activeDialogAnchor_));
     this.activeDialogAnchor_ = null;
-    this.activePassword.hide();
-    this.activePassword = null;
+    this.activePassword_.hide();
+    this.activePassword_ = null;
   },
 
   /** @private */
@@ -261,7 +271,7 @@
     this.showPasswordEditDialog_ = false;
     focusWithoutInk(assert(this.activeDialogAnchor_));
     this.activeDialogAnchor_ = null;
-    this.activePassword = null;
+    this.activePassword_ = null;
   },
 
   /**
@@ -273,7 +283,7 @@
     // result back to javascript.
     this.requestActivePlaintextPassword_(
         chrome.passwordsPrivate.PlaintextReason.COPY, _ => {
-          this.activePassword = null;
+          this.activePassword_ = null;
         });
 
     this.$.menu.close();
@@ -288,20 +298,20 @@
   onMenuRemovePasswordTap_() {
     this.$.menu.close();
 
-    if (this.activePassword.entry.isPresentOnDevice() &&
-        this.activePassword.entry.isPresentInAccount()) {
+    if (this.activePassword_.entry.isPresentOnDevice() &&
+        this.activePassword_.entry.isPresentInAccount()) {
       this.showPasswordRemoveDialog_ = true;
       return;
     }
 
-    const idToRemove = this.activePassword.entry.isPresentInAccount() ?
-        this.activePassword.entry.accountId :
-        this.activePassword.entry.deviceId;
+    const idToRemove = this.activePassword_.entry.isPresentInAccount() ?
+        this.activePassword_.entry.accountId :
+        this.activePassword_.entry.deviceId;
     this.passwordManager_.removeSavedPassword(idToRemove);
     this.displayRemovalNotification_(
-        this.activePassword.entry.isPresentInAccount(),
-        this.activePassword.entry.isPresentOnDevice());
-    this.activePassword = null;
+        this.activePassword_.entry.isPresentInAccount(),
+        this.activePassword_.entry.isPresentOnDevice());
+    this.activePassword_ = null;
   },
 
   /**
@@ -328,24 +338,14 @@
     this.fire('iron-announce', {text: this.i18n('undoDescription')});
   },
 
-  /**
-   * @param {PasswordRemoveDialogPasswordsRemovedEvent} event
-   */
-  onPasswordRemoveDialogPasswordsRemoved_(event) {
-    this.displayRemovalNotification_(
-        event.detail.removedFromAccount, event.detail.removedFromDevice);
-  },
-
-  /**
-   * @private
-   */
+  /** @private */
   onUndoButtonClick_() {
     this.passwordManager_.undoRemoveSavedPasswordOrException();
     this.onSavedPasswordOrExceptionRemoved();
   },
 
   /**
-   * Should only be called when |activePassword| has a device copy.
+   * Should only be called when |activePassword_| has a device copy.
    * @private
    */
   onMenuMovePasswordToAccountTap_() {
@@ -353,23 +353,19 @@
     this.showPasswordMoveToAccountDialog_ = true;
   },
 
-  /**
-   * @private
-   */
+  /** @private */
   onPasswordMoveToAccountDialogClosed_() {
     this.showPasswordMoveToAccountDialog_ = false;
-    this.activePassword = null;
+    this.activePassword_ = null;
 
     // The entry possibly disappeared, so don't reset the focus.
     this.activeDialogAnchor_ = null;
   },
 
-  /**
-   * @private
-   */
+  /** @private */
   onPasswordRemoveDialogClosed_() {
     this.showPasswordRemoveDialog_ = false;
-    this.activePassword = null;
+    this.activePassword_ = null;
 
     // A removal possibly happened, so don't reset the focus.
     this.activeDialogAnchor_ = null;
@@ -381,9 +377,10 @@
    * @return {boolean}
    */
   shouldShowMoveToAccountOption_() {
-    const isFirstSignedInAccountPassword = !!this.activePassword &&
-        this.activePassword.entry.urls.origin.includes('accounts.google.com') &&
-        this.activePassword.entry.username === this.firstSignedInAccountEmail_;
+    const isFirstSignedInAccountPassword = !!this.activePassword_ &&
+        this.activePassword_.entry.urls.origin.includes(
+            'accounts.google.com') &&
+        this.activePassword_.entry.username === this.firstSignedInAccountEmail_;
     // It's not useful to move a password for an account into that same account.
     return this.allowMoveToAccountOption && !isFirstSignedInAccountPassword;
   },
diff --git a/chrome/browser/resources/settings/autofill_page/passwords_section.js b/chrome/browser/resources/settings/autofill_page/passwords_section.js
index c9ed577f..57d731a 100644
--- a/chrome/browser/resources/settings/autofill_page/passwords_section.js
+++ b/chrome/browser/resources/settings/autofill_page/passwords_section.js
@@ -8,7 +8,6 @@
  * save any passwords.
  */
 
-
 /** @typedef {!{model: !{item: !chrome.passwordsPrivate.ExceptionEntry}}} */
 let ExceptionEntryEntryEvent;
 
@@ -23,7 +22,6 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
 import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
-import {getImage} from 'chrome://resources/js/icon.m.js';
 import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
 import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
@@ -42,7 +40,6 @@
 import {MergeExceptionsStoreCopiesBehavior} from './merge_exceptions_store_copies_behavior.js';
 import {MergePasswordsStoreCopiesBehavior} from './merge_passwords_store_copies_behavior.js';
 import {MultiStorePasswordUiEntry} from './multi_store_password_ui_entry.js';
-import {MultiStoreExceptionEntry} from './multi_store_exception_entry.js';
 import {Router} from '../router.m.js';
 import '../settings_shared_css.m.js';
 import '../site_favicon.js';
@@ -53,7 +50,6 @@
 import './passwords_export_dialog.js';
 import './passwords_shared_css.js';
 import './avatar_icon.js';
-import {ProfileInfo, ProfileInfoBrowserProxy, ProfileInfoBrowserProxyImpl} from '../people_page/profile_info_browser_proxy.m.js';
 // <if expr="chromeos">
 import '../controls/password_prompt_dialog.m.js';
 import {BlockingRequestManager} from './blocking_request_manager.js';
@@ -90,10 +86,6 @@
   ],
 
   properties: {
-    // <if expr="not chromeos">
-    /** @private */
-    storedAccounts_: Array,
-    // </if>
 
     /** @type {!Map<string, (string|Function)>} */
     focusConfig: {
@@ -119,6 +111,17 @@
       value: () => document,
     },
 
+    /** Filter on the saved passwords and exceptions. */
+    filter: {
+      type: String,
+      value: '',
+    },
+
+    // <if expr="not chromeos">
+    /** @private */
+    storedAccounts_: Array,
+    // </if>
+
     /** @private */
     signedIn_: {
       type: Boolean,
@@ -163,6 +166,7 @@
       computed: 'computeHasPasswordExceptions_(passwordExceptions)',
     },
 
+    /** @private */
     shouldShowBanner_: {
       type: Boolean,
       value: true,
@@ -173,6 +177,7 @@
     /**
      * Whether the edit dialog and removal notification should show
      * information about which location(s) a password is stored.
+     * @private
      */
     shouldShowStorageDetails_: {
       type: Boolean,
@@ -252,12 +257,6 @@
     /** @private {SyncStatus} */
     syncStatus_: Object,
 
-    /** Filter on the saved passwords and exceptions. */
-    filter: {
-      type: String,
-      value: '',
-    },
-
     /** @private {!MultiStorePasswordUiEntry} */
     lastFocused_: Object,
 
@@ -269,7 +268,7 @@
     showPasswordPromptDialog_: Boolean,
 
     /** @private {BlockingRequestManager} */
-    tokenRequestManager_: Object
+    tokenRequestManager_: Object,
     // </if>
   },
 
@@ -295,36 +294,12 @@
   /** @private {?PasswordManagerProxy} */
   passwordManager_: null,
 
-  /**
-   * @type {?function(boolean):void}
-   * @private
-   */
+  /** @private {?function(boolean):void} */
   setIsOptedInForAccountStorageListener_: null,
 
-  /**
-   * @type {?function(!Array<PasswordManagerProxy.ExceptionEntry>):void}
-   * @private
-   */
+  /** @private {?function(!Array<PasswordManagerProxy.ExceptionEntry>):void} */
   setPasswordExceptionsListener_: null,
 
-  /**
-   * @param {!Map<string, string>} newConfig
-   * @param {?Map<string, string>} oldConfig
-   * @private
-   */
-  focusConfigChanged_(newConfig, oldConfig) {
-    // focusConfig is set only once on the parent, so this observer should
-    // only fire once.
-    assert(!oldConfig);
-
-    // Populate the |focusConfig| map of the parent <settings-autofill-page>
-    // element, with additional entries that correspond to subpage trigger
-    // elements residing in this element's Shadow DOM.
-    this.focusConfig.set(assert(routes.CHECK_PASSWORDS).path, () => {
-      focusWithoutInk(assert(this.$$('#icon')));
-    });
-  },
-
   /** @override */
   attached() {
     // Create listener functions.
@@ -388,56 +363,6 @@
   },
 
   /**
-   * Shows the check passwords sub page.
-   * @private
-   */
-  onCheckPasswordsClick_() {
-    Router.getInstance().navigateTo(
-        routes.CHECK_PASSWORDS, new URLSearchParams('start=true'));
-    this.passwordManager_.recordPasswordCheckReferrer(
-        PasswordManagerProxy.PasswordCheckReferrer.PASSWORD_SETTINGS);
-  },
-
-  /**
-   * Shows the 'device passwords' page.
-   */
-  onDevicePasswordsLinkClicked_() {
-    Router.getInstance().navigateTo(routes.DEVICE_PASSWORDS);
-  },
-
-  // <if expr="chromeos">
-  /**
-   * When this event fired, it means that the password-prompt-dialog succeeded
-   * in creating a fresh token in the quickUnlockPrivate API. Because new tokens
-   * can only ever be created immediately following a GAIA password check, the
-   * passwordsPrivate API can now safely grant requests for secure data (i.e.
-   * saved passwords) for a limited time. This observer resolves the request,
-   * triggering a callback that requires a fresh auth token to succeed and that
-   * was provided to the BlockingRequestManager by another DOM element seeking
-   * secure data.
-   *
-   * @param {!CustomEvent<!chrome.quickUnlockPrivate.TokenInfo>} e - Contains
-   *     newly created auth token. Note that its precise value is not relevant
-   *     here, only the facts that it's created.
-   * @private
-   */
-  onTokenObtained_(e) {
-    assert(e.detail);
-    this.tokenRequestManager_.resolve();
-  },
-
-  onPasswordPromptClosed_() {
-    this.showPasswordPromptDialog_ = false;
-    focusWithoutInk(assert(this.activeDialogAnchorStack_.pop()));
-  },
-
-  openPasswordPromptDialog_() {
-    this.activeDialogAnchorStack_.push(getDeepActiveElement());
-    this.showPasswordPromptDialog_ = true;
-  },
-  // </if>
-
-  /**
    * @return {boolean}
    * @private
    */
@@ -525,6 +450,86 @@
   },
 
   /**
+   * @private
+   * @return {boolean}
+   */
+  computeHasLeakedCredentials_() {
+    return this.leakedPasswords.length > 0;
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  computeHasNeverCheckedPasswords_() {
+    return !this.status.elapsedTimeSinceLastCheck;
+  },
+
+  /**
+   * @private
+   * @return {string}
+   */
+  computeDevicePasswordsLinkLabel_() {
+    return this.numberOfDevicePasswords_ === 1 ?
+        this.i18n('devicePasswordsLinkLabelSingular') :
+        this.i18n(
+            'devicePasswordsLinkLabelPlural', this.numberOfDevicePasswords_);
+  },
+
+  /**
+   * Shows the check passwords sub page.
+   * @private
+   */
+  onCheckPasswordsClick_() {
+    Router.getInstance().navigateTo(
+        routes.CHECK_PASSWORDS, new URLSearchParams('start=true'));
+    this.passwordManager_.recordPasswordCheckReferrer(
+        PasswordManagerProxy.PasswordCheckReferrer.PASSWORD_SETTINGS);
+  },
+
+  /**
+   * Shows the 'device passwords' page.
+   * @private
+   */
+  onDevicePasswordsLinkClicked_() {
+    Router.getInstance().navigateTo(routes.DEVICE_PASSWORDS);
+  },
+
+  // <if expr="chromeos">
+  /**
+   * When this event fired, it means that the password-prompt-dialog succeeded
+   * in creating a fresh token in the quickUnlockPrivate API. Because new tokens
+   * can only ever be created immediately following a GAIA password check, the
+   * passwordsPrivate API can now safely grant requests for secure data (i.e.
+   * saved passwords) for a limited time. This observer resolves the request,
+   * triggering a callback that requires a fresh auth token to succeed and that
+   * was provided to the BlockingRequestManager by another DOM element seeking
+   * secure data.
+   *
+   * @param {!CustomEvent<!chrome.quickUnlockPrivate.TokenInfo>} e - Contains
+   *     newly created auth token. Note that its precise value is not relevant
+   *     here, only the facts that it's created.
+   * @private
+   */
+  onTokenObtained_(e) {
+    assert(e.detail);
+    this.tokenRequestManager_.resolve();
+  },
+
+  /** @private */
+  onPasswordPromptClosed_() {
+    this.showPasswordPromptDialog_ = false;
+    focusWithoutInk(assert(this.activeDialogAnchorStack_.pop()));
+  },
+
+  /** @private */
+  openPasswordPromptDialog_() {
+    this.activeDialogAnchorStack_.push(getDeepActiveElement());
+    this.showPasswordPromptDialog_ = true;
+  },
+  // </if>
+
+  /**
    * @param {string} filter
    * @return {!Array<!MultiStorePasswordUiEntry>}
    * @private
@@ -644,33 +649,6 @@
   },
 
   /**
-   * @private
-   * @return {boolean}
-   */
-  computeHasLeakedCredentials_() {
-    return this.leakedPasswords.length > 0;
-  },
-
-  /**
-   * @private
-   * @return {boolean}
-   */
-  computeHasNeverCheckedPasswords_() {
-    return !this.status.elapsedTimeSinceLastCheck;
-  },
-
-  /**
-   * @private
-   * @return {string}
-   */
-  computeDevicePasswordsLinkLabel_() {
-    return this.numberOfDevicePasswords_ === 1 ?
-        this.i18n('devicePasswordsLinkLabelSingular') :
-        this.i18n(
-            'devicePasswordsLinkLabelPlural', this.numberOfDevicePasswords_);
-  },
-
-  /**
    * Return the first available stored account. This is useful when trying to
    * figure out the account logged into the content area which seems to always
    * be first even if multiple accounts are available.
@@ -683,4 +661,22 @@
         this.storedAccounts_[0].email :
         '';
   },
+
+  /**
+   * @param {!Map<string, string>} newConfig
+   * @param {?Map<string, string>} oldConfig
+   * @private
+   */
+  focusConfigChanged_(newConfig, oldConfig) {
+    // focusConfig is set only once on the parent, so this observer should
+    // only fire once.
+    assert(!oldConfig);
+
+    // Populate the |focusConfig| map of the parent <settings-autofill-page>
+    // element, with additional entries that correspond to subpage trigger
+    // elements residing in this element's Shadow DOM.
+    this.focusConfig.set(assert(routes.CHECK_PASSWORDS).path, () => {
+      focusWithoutInk(assert(this.$$('#icon')));
+    });
+  },
 });
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn
index 786172c9..12a0d76 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn
@@ -371,6 +371,7 @@
     ":os_languages_page_module",
     ":os_languages_page_v2_module",
     ":os_languages_section_module",
+    ":shared_style_module",
     ":smart_inputs_page_module",
     "../../languages_page:languages_module",
     "../../languages_page:modulize",
@@ -467,6 +468,12 @@
   auto_imports = os_settings_auto_imports
 }
 
+polymer_modulizer("shared_style") {
+  js_file = "shared_style.m.js"
+  html_file = "shared_style.html"
+  html_type = "style-module"
+}
+
 polymer_modulizer("smart_inputs_page") {
   js_file = "smart_inputs_page.js"
   html_file = "smart_inputs_page.html"
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.html b/chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.html
index 42fd0fb..86ca8b04 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.html
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/add_input_methods_dialog.html
@@ -7,12 +7,13 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
 <link rel="import" href="../metrics_recorder.html">
+<link rel="import" href="shared_style.html">
 <link rel="import" href="../../languages_page/languages.html">
 <link rel="import" href="../../settings_shared_css.html">
 
 <dom-module id="os-settings-add-input-methods-dialog">
   <template>
-    <style include="settings-shared iron-flex">
+    <style include="settings-shared iron-flex shared-style">
       #dialogBody {
         display: flex;
         flex-direction: column;
@@ -22,9 +23,7 @@
       }
 
       cr-search-field {
-        --cr-search-field-search-input-width: 100%;
-        padding-bottom: 8px;
-        padding-inline-end: 20px;
+        margin-bottom: 8px;
       }
 
       .label {
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.html b/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.html
index bfe7d76f..cc897ca 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.html
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/change_device_language_dialog.html
@@ -10,6 +10,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-ripple/paper-ripple.html">
 <link rel="import" href="languages_metrics_proxy.html">
+<link rel="import" href="shared_style.html">
 <link rel="import" href="../localized_link/localized_link.html">
 <link rel="import" href="../metrics_recorder.html">
 <link rel="import" href="../../languages_page/languages.html">
@@ -18,7 +19,7 @@
 
 <dom-module id="os-settings-change-device-language-dialog">
   <template>
-    <style include="settings-shared iron-flex">
+    <style include="settings-shared iron-flex shared-style">
       #dialogBody {
         display: flex;
         flex-direction: column;
@@ -30,6 +31,7 @@
 
       cr-search-field {
         margin-bottom: 16px;
+        margin-inline-start: 20px;
         margin-top: 16px;
       }
 
@@ -56,6 +58,7 @@
       }
 
       .padded {
+        padding-inline-end: 20px;
         padding-inline-start: 20px;
       }
 
@@ -71,7 +74,7 @@
             localized-string="[[i18nAdvanced(
                 'changeDeviceLanguageDialogDescription')]]">
         </settings-localized-link>
-        <cr-search-field class="padded" label="$i18n{searchLanguages}"
+        <cr-search-field label="$i18n{searchLanguages}"
             id="search" on-search-changed="onSearchChanged_"
             clear-label="$i18n{clearSearch}" on-keydown="onKeydown_" autofocus>
         </cr-search-field>
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
index 0ec67f9..bf8a462c 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
@@ -89,6 +89,7 @@
 
       .subsection .list-frame {
         padding-inline-end: 0;
+        padding-inline-start: 40px;
       }
 
       .subsection > settings-toggle-button,
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.html b/chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.html
index 61d14f5..9ad3af03b 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.html
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_add_languages_dialog.html
@@ -7,13 +7,15 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/find_shortcut_behavior.html">
+<link rel="import" href="chrome://resources/html/load_time_data.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
+<link rel="import" href="shared_style.html">
 <link rel="import" href="../../languages_page/languages.html">
 <link rel="import" href="../../settings_shared_css.html">
 
 <dom-module id="os-settings-add-languages-dialog">
   <template>
-    <style include="settings-shared">
+    <style include="settings-shared shared-style">
       #dialog-body {
         display: flex;
         flex-direction: column;
@@ -23,21 +25,20 @@
       }
 
       cr-search-field {
-        padding-inline-end: 24px;
+        margin-bottom: 16px;
       }
 
       iron-list {
         flex: 1;
       }
 
-      .ripple-padding {
-        /* Create a little extra space for checkbox ink ripple to flow into. */
-        padding-inline-start: 20px;
-      }
-
       cr-checkbox::part(label-container) {
         white-space: nowrap;
       }
+
+      .list-item {
+        min-height: 36px;
+      }
     </style>
     <cr-dialog id="dialog" close-text="$i18n{close}">
       <div slot="title">$i18n{addLanguagesDialogTitle}</div>
@@ -46,7 +47,7 @@
             on-search-changed="onSearchChanged_" on-keydown="onKeydown_"
             clear-label="$i18n{clearSearch}" autofocus>
         </cr-search-field>
-        <iron-list class="ripple-padding" scroll-target="[[$$('[slot=body]')]]"
+        <iron-list scroll-target="[[$$('[slot=body]')]]"
             items="[[getLanguages_(
                 languages.supported, languages.enabled.*, filterValue_)]]">
           <template>
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/shared_style.html b/chrome/browser/resources/settings/chromeos/os_languages_page/shared_style.html
new file mode 100644
index 0000000..a8940ac6
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/shared_style.html
@@ -0,0 +1,33 @@
+
+<!-- Common styles for 'Languages and inputs' section. -->
+<dom-module id="shared-style">
+  <template>
+    <style>
+      cr-search-field {
+        --cr-search-field-clear-icon-fill: var(--cros-icon-color-secondary);
+        --cr-search-field-clear-icon-margin-end: 8px;
+        --cr-search-field-clear-icon-size: 18px;
+        --cr-search-field-input-border-bottom: none;
+        --cr-search-field-input-min-height: 32px;
+        --cr-search-field-input-padding-bottom: 0;
+        --cr-search-field-input-padding-start: 8px;
+        --cr-search-field-input-padding-top: 0;
+        --cr-search-field-input-width: 100%;
+        --cr-search-field-search-icon-display: none;
+        --cr-search-field-search-icon-fill: var(--cros-icon-color-secondary);
+        --cr-search-field-search-icon-inline-display: block;
+        --cr-search-field-search-icon-inline-margin-start: 6px;
+        background-color: var(--google-grey-100);
+        border-radius: 4px;
+        margin-inline-end: 20px;
+      }
+
+      cr-dialog [slot=button-container] {
+        padding-bottom: 20px;
+        padding-inline-end: 20px;
+        padding-inline-start: 20px;
+        padding-top: 20px;
+      }
+    </style>
+  </template>
+</dom-module>
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
index de2f3d8e4..bc2d741 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
+++ b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
@@ -209,6 +209,11 @@
            use_base_dir="false"
            compress="false"
            type="BINDATA" />
+  <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_SHARED_STYLE_M_JS"
+           file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/shared_style.m.js"
+           use_base_dir="false"
+           compress="false"
+           type="BINDATA" />
   <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_SMART_INPUTS_PAGE_M_JS"
            file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.m.js"
            use_base_dir="false"
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd
index 0e5d673d..f83bf32 100644
--- a/chrome/browser/resources/settings/os_settings_resources.grd
+++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -779,6 +779,9 @@
       <structure name="IDR_OS_SETTINGS_LANGUAGES_INPUT_METHOD_UTIL_JS"
                  file="chromeos/os_languages_page/input_method_util.js"
                  compress="false" type="chrome_html" />
+      <structure name="IDR_OS_SETTINGS_LANGUAGES_SHARED_STYLE_HTML"
+                 file="chromeos/os_languages_page/shared_style.html"
+                 compress="false" type="chrome_html" />
       <structure name="IDR_OS_SETTINGS_LANGUAGES_SMART_INPUTS_PAGE_HTML"
                  file="chromeos/os_languages_page/smart_inputs_page.html"
                  compress="false" type="chrome_html" />
diff --git a/chrome/browser/resources/signin/profile_picker/BUILD.gn b/chrome/browser/resources/signin/profile_picker/BUILD.gn
index 833539b..8886a31 100644
--- a/chrome/browser/resources/signin/profile_picker/BUILD.gn
+++ b/chrome/browser/resources/signin/profile_picker/BUILD.gn
@@ -2,8 +2,77 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/preprocess_grit.gni")
 import("//tools/polymer/html_to_js.gni")
+import("../../optimize_webui.gni")
+
+if (optimize_webui) {
+  preprocess_folder = "preprocessed"
+
+  optimize_webui("build") {
+    host = "profile-picker"
+    js_module_in_files = [
+      "profile_picker.js",
+      "lazy_load.js",
+    ]
+    input = rebase_path("$target_gen_dir/$preprocess_folder", root_build_dir)
+    js_out_files = [
+      "profile_picker.rollup.js",
+      "lazy_load.rollup.js",
+      "shared.rollup.js",
+    ]
+
+    deps = [
+      ":preprocess",
+      ":preprocess_generated",
+      ":shared",
+      "../../../../../ui/webui/resources:preprocess",
+    ]
+    excludes = [
+      "chrome://resources/js/cr.m.js",
+      "chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js",
+      "chrome://resources/mojo/skia/public/mojom/skcolor.mojom-lite.js",
+    ]
+  }
+
+  preprocess_grit("preprocess") {
+    in_folder = "./"
+    out_folder = "$target_gen_dir/$preprocess_folder"
+    in_files = [
+      "profile_picker.js",
+      "navigation_behavior.js",
+      "policy_helper.js",
+      "icons.js",
+      "lazy_load.js",
+      "ensure_lazy_loaded.js",
+      "manage_profiles_browser_proxy.js",
+    ]
+  }
+
+  preprocess_grit("shared") {
+    in_folder = "../"
+    out_folder = "$target_gen_dir/$preprocess_folder"
+    in_files = [ "signin_icons.js" ]
+  }
+
+  preprocess_grit("preprocess_generated") {
+    deps = [ ":web_components" ]
+    in_folder = target_gen_dir
+    out_folder = "$target_gen_dir/$preprocess_folder"
+    in_files = [
+      "profile_picker_app.js",
+      "profile_picker_main_view.js",
+      "profile_card.js",
+      "profile_card_menu.js",
+      "profile_creation_flow/profile_type_choice.js",
+      "profile_creation_flow/local_profile_customization.js",
+      "profile_picker_shared_css.js",
+      "profile_creation_flow/shared_css.js",
+    ]
+  }
+}
 
 group("closure_compile") {
   deps = [
@@ -20,11 +89,38 @@
         "js_module_root=./gen/chrome/browser/resources/signin/profile_picker/",
       ]
   deps = [
+    ":ensure_lazy_loaded",
+    ":lazy_load",
+    ":navigation_behavior",
+    ":policy_helper",
+    ":profile_card",
+    ":profile_card_menu",
+    ":profile_picker",
     ":profile_picker_app",
     ":profile_picker_main_view",
   ]
 }
 
+js_library("profile_picker") {
+  deps = [
+    ":ensure_lazy_loaded",
+    ":manage_profiles_browser_proxy",
+    ":navigation_behavior",
+    ":profile_picker_app",
+  ]
+}
+
+js_library("ensure_lazy_loaded") {
+  deps = [ ":lazy_load" ]
+}
+
+js_library("lazy_load") {
+  deps = [
+    "profile_creation_flow:local_profile_customization",
+    "profile_creation_flow:profile_type_choice",
+  ]
+}
+
 js_library("profile_picker_main_view") {
   deps = [
     ":manage_profiles_browser_proxy",
@@ -50,7 +146,9 @@
 
 js_library("profile_picker_app") {
   deps = [
+    ":ensure_lazy_loaded",
     ":navigation_behavior",
+    ":profile_picker_main_view",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render.m",
     "//ui/webui/resources/cr_elements/cr_view_manager:cr_view_manager.m",
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/ensure_lazy_loaded.js b/chrome/browser/resources/signin/profile_picker/ensure_lazy_loaded.js
similarity index 92%
rename from chrome/browser/resources/signin/profile_picker/profile_creation_flow/ensure_lazy_loaded.js
rename to chrome/browser/resources/signin/profile_picker/ensure_lazy_loaded.js
index 0bea58dc..78ccede 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/ensure_lazy_loaded.js
+++ b/chrome/browser/resources/signin/profile_picker/ensure_lazy_loaded.js
@@ -13,7 +13,7 @@
   if (!lazyLoadPromise) {
     const script = document.createElement('script');
     script.type = 'module';
-    script.src = './profile_creation_flow/lazy_load.js';
+    script.src = './lazy_load.js';
     document.body.appendChild(script);
 
     lazyLoadPromise = Promise.all([
diff --git a/chrome/browser/resources/signin/profile_picker/lazy_load.js b/chrome/browser/resources/signin/profile_picker/lazy_load.js
new file mode 100644
index 0000000..6ed3d8f8
--- /dev/null
+++ b/chrome/browser/resources/signin/profile_picker/lazy_load.js
@@ -0,0 +1,6 @@
+// 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 './profile_creation_flow/profile_type_choice.js';
+import './profile_creation_flow/local_profile_customization.js';
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/BUILD.gn b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/BUILD.gn
index 9c3a1c9e..e5b2e17 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/BUILD.gn
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/BUILD.gn
@@ -13,9 +13,6 @@
   ]
 }
 
-js_library("ensure_lazy_loaded") {
-}
-
 js_library("profile_type_choice") {
   deps = [
     "..:manage_profiles_browser_proxy",
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/lazy_load.js b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/lazy_load.js
deleted file mode 100644
index ab38aa4..0000000
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/lazy_load.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import './profile_type_choice.js';
-import './local_profile_customization.js';
\ No newline at end of file
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html
index 534c545..688e73e3 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.html
@@ -127,7 +127,7 @@
 
 <div id="wrapperContainer">
   <div id="wrapper">
-    <cr-input id="nameInput" value="{{profileName_}}" pattern=".*\\S.*"
+    <cr-input id="nameInput" value="{{profileName_}}" pattern="[[pattern_]]"
         placeholder="$i18n{createProfileNamePlaceholder}"
         auto-validate spellcheck="false">
     </cr-input>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js
index 98262e8..e5836bd 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/local_profile_customization.js
@@ -91,6 +91,12 @@
       type: Boolean,
       value: false,
     },
+
+    /** @private */
+    pattern_: {
+      type: String,
+      value: '.*\\S.*',
+    },
   },
 
   /** @private {?ManageProfilesBrowserProxy} */
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker.html b/chrome/browser/resources/signin/profile_picker/profile_picker.html
index 50393e2a..354582a6 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker.html
@@ -1,6 +1,7 @@
 <!doctype html>
 <html dir="$i18n{textdirection}" lang="$i18n{language}">
   <head>
+    <base href="chrome://profile-picker">
     <meta charset="utf-8">
     <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
     <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
@@ -18,6 +19,6 @@
       }
     </style>
     <profile-picker-app></profile-picker-app>
-    <script type="module" src="profile_picker_app.js"></script>
+    <script type="module" src="profile_picker.js"></script>
   </body>
 </html>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker.js b/chrome/browser/resources/signin/profile_picker/profile_picker.js
new file mode 100644
index 0000000..371ba51
--- /dev/null
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker.js
@@ -0,0 +1,5 @@
+import './profile_picker_app.js';
+
+export {ensureLazyLoaded} from './ensure_lazy_loaded.js';
+export {ManageProfilesBrowserProxy, ManageProfilesBrowserProxyImpl} from './manage_profiles_browser_proxy.js';
+export {navigateTo, Routes} from './navigation_behavior.js';
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_app.js b/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
index 0fa0fdd0..3220292 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
@@ -11,10 +11,10 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
+import {ensureLazyLoaded} from './ensure_lazy_loaded.js';
 import {AutogeneratedThemeColorInfo, ManageProfilesBrowserProxy, ManageProfilesBrowserProxyImpl} from './manage_profiles_browser_proxy.js';
 import {navigateTo, NavigationBehavior, ProfileCreationSteps, Routes} from './navigation_behavior.js';
 import {isProfileCreationAllowed} from './policy_helper.js';
-import {ensureLazyLoaded} from './profile_creation_flow/ensure_lazy_loaded.js';
 
 Polymer({
   is: 'profile-picker-app',
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd b/chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd
index 66f0f145..5113e8d 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd
@@ -63,6 +63,11 @@
           type="chrome_html"
           compress="false"/>
       <structure
+          name="IDR_PROFILE_PICKER_PROFILE_PICKER_JS"
+          file="profile_picker.js"
+          type="chrome_html"
+          compress="false"/>
+      <structure
           name="IDR_PROFILE_PICKER_NAVIGATION_BEHAVIOR_JS"
           file="navigation_behavior.js"
           type="chrome_html"
@@ -78,18 +83,13 @@
           type="chrome_html"
           compress="false"/>
       <structure
-          name="IDR_SIGNIN_ICONS_JS"
-          file="../signin_icons.js"
-          type="chrome_html"
-          compress="false"/>
-      <structure
           name="IDR_PROFILE_PICKER_LAZY_LOAD_JS"
-          file="profile_creation_flow/lazy_load.js"
+          file="lazy_load.js"
           type="chrome_html"
           compress="false"/>
       <structure
           name="IDR_PROFILE_PICKER_ENSURE_LAZY_LOADED_JS"
-          file="profile_creation_flow/ensure_lazy_loaded.js"
+          file="ensure_lazy_loaded.js"
           type="chrome_html"
           compress="false"/>
       <structure
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_resources_vulcanized.grd b/chrome/browser/resources/signin/profile_picker/profile_picker_resources_vulcanized.grd
new file mode 100644
index 0000000..a63a97c
--- /dev/null
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_resources_vulcanized.grd
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+  <outputs>
+    <output filename="grit/profile_picker_resources.h" type="rc_header">
+      <emit emit_type='prepend'></emit>
+    </output>
+    <output filename="grit/profile_picker_resources_map.cc"
+            type="resource_map_source" />
+    <output filename="grit/profile_picker_resources_map.h"
+            type="resource_map_header" />
+    <output filename="profile_picker_resources.pak" type="data_package" />
+  </outputs>
+  <release seq="1">
+    <includes>
+      <include name="IDR_PROFILE_PICKER_PROFILE_PICKER_HTML"
+               file="profile_picker.html"
+               type="chrome_html" />
+      <include name="IDR_PROFILE_PICKER_PROFILE_PICKER_ROLLUP_JS"
+               file="${root_gen_dir}/chrome/browser/resources/signin/profile_picker/profile_picker.rollup.js"
+               use_base_dir="false"
+               type="chrome_html" />
+      <include name="IDR_PROFILE_PICKER_LAZY_LOAD_ROLLUP_JS"
+               file="${root_gen_dir}/chrome/browser/resources/signin/profile_picker/lazy_load.rollup.js"
+               type="BINDATA"
+               use_base_dir="false" />
+      <include name="IDR_PROFILE_PICKER_SHARED_ROLLUP_JS"
+               file="${root_gen_dir}/chrome/browser/resources/signin/profile_picker/shared.rollup.js"
+               type="BINDATA"
+               use_base_dir="false" />
+      <include name="IDR_PROFILE_PICKER_IMAGES_LEFT_BANNER_IMAGE"
+               file="images/left_banner_image.svg"
+               type="BINDATA" />
+      <include name="IDR_PROFILE_PICKER_IMAGES_RIGHT_BANNER_IMAGE"
+               file="images/right_banner_image.svg"
+               type="BINDATA" />
+      <include name="IDR_PROFILE_PICKER_IMAGES_DARK_MODE_LEFT_BANNER_IMAGE"
+               file="images/dark_mode_left_banner_image.svg"
+               type="BINDATA" />
+      <include name="IDR_PROFILE_PICKER_IMAGES_DARK_MODE_RIGHT_BANNER_IMAGE"
+               file="images/dark_mode_right_banner_image.svg"
+               type="BINDATA" />
+      <include name="IDR_PROFILE_PICKER_PROFILE_CREATION_FLOW_IMAGES_BANNER_LIGHT_IMAGE"
+               file="profile_creation_flow/images/banner_light_image.svg"
+               type="BINDATA" />
+      <include name="IDR_PROFILE_PICKER_PROFILE_CREATION_FLOW_IMAGES_BANNER_DARK_IMAGE"
+               file="profile_creation_flow/images/banner_dark_image.svg"
+               type="BINDATA" />
+    </includes>
+  </release>
+</grit>
diff --git a/chrome/browser/ssl/sct_reporting_service_browsertest.cc b/chrome/browser/ssl/sct_reporting_service_browsertest.cc
index f9f46979..16ce472e 100644
--- a/chrome/browser/ssl/sct_reporting_service_browsertest.cc
+++ b/chrome/browser/ssl/sct_reporting_service_browsertest.cc
@@ -53,7 +53,7 @@
       std::unique_ptr<net::StreamSocket> socket) override {}
 
   void WaitForConnections(size_t num_connections) {
-    if (connections_seen_ >= connections_expected_)
+    if (connections_seen_ >= num_connections)
       return;
 
     connections_expected_ = num_connections;
@@ -206,7 +206,7 @@
 
 // Tests that disabling Extended Reporting causes the cache to be cleared.
 IN_PROC_BROWSER_TEST_F(SCTReportingServiceBrowserTest,
-                       DISABLED_OptingOutClearsSCTAuditingCache) {
+                       OptingOutClearsSCTAuditingCache) {
   // Enable SCT auditing and enqueue a report.
   SetExtendedReportingEnabled(true);
 
@@ -231,7 +231,7 @@
 // Tests that reports are still sent for opted-in profiles after the network
 // service crashes and is restarted.
 IN_PROC_BROWSER_TEST_F(SCTReportingServiceBrowserTest,
-                       DISABLED_ReportsSentAfterNetworkServiceRestart) {
+                       ReportsSentAfterNetworkServiceRestart) {
   // This test is only applicable to out-of-process network service because it
   // tests what happens when the network service crashes and restarts.
   if (content::IsInProcessNetworkService()) {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 91f180fe2..523123b9 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2181,6 +2181,12 @@
       "webui/chromeos/image_source.h",
       "webui/chromeos/in_session_password_change/confirm_password_change_handler.cc",
       "webui/chromeos/in_session_password_change/confirm_password_change_handler.h",
+      "webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc",
+      "webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h",
+      "webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc",
+      "webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h",
+      "webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.cc",
+      "webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h",
       "webui/chromeos/in_session_password_change/password_change_dialogs.cc",
       "webui/chromeos/in_session_password_change/password_change_dialogs.h",
       "webui/chromeos/in_session_password_change/password_change_handler.cc",
diff --git a/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.cc b/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.cc
index 8f409b0d..6c8991acc 100644
--- a/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.cc
+++ b/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.cc
@@ -13,6 +13,7 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
@@ -27,7 +28,9 @@
 namespace app_list {
 namespace {
 
-constexpr char kSchema[] = "drive_zero_state://";
+// Schemas of result IDs for the results list and suggestion chips.
+constexpr char kListSchema[] = "drive_zero_state://";
+constexpr char kChipSchema[] = "drive_zero_state_chip://";
 
 // Given an absolute path representing a file in the user's Drive, returns a
 // reparented version of the path within the user's drive fs mount.
@@ -56,18 +59,36 @@
   task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
       {base::TaskPriority::BEST_EFFORT, base::MayBlock(),
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+
+  // Warm the results cache if or when drivefs is mounted by fetching from the
+  // Drive QuickAccess API. This is necessary only if the suggested files
+  // experiment is enabled, so that results are ready for display in the
+  // suggested chips on the first launcher open after login.
+  if (suggested_files_enabled_ && drive_service_) {
+    if (drive_service_->IsMounted()) {
+      // Drivefs is mounted, so we can fetch results immediately.
+      OnFileSystemMounted();
+    } else {
+      // Wait for DriveFS to be mounted, then fetch results. This happens in
+      // OnFileSystemMounted.
+      drive_service_->AddObserver(this);
+    }
+  }
 }
 
-DriveZeroStateProvider::~DriveZeroStateProvider() = default;
+DriveZeroStateProvider::~DriveZeroStateProvider() {
+  if (suggested_files_enabled_ && drive_service_)
+    drive_service_->RemoveObserver(this);
+}
 
 void DriveZeroStateProvider::OnFileSystemMounted() {
+  // This method is called on login, and each time the device wakes from sleep.
+  // We only want to warm the cache once.
   if (have_warmed_up_cache_)
     return;
   have_warmed_up_cache_ = true;
 
-  // TODO(crbug.com/1034842): Query ItemSuggest. We may need to call
-  // SearchController::Start afterwards, or preferably could just publish the
-  // results for this search provider.
+  item_suggest_cache_.UpdateCache();
 }
 
 void DriveZeroStateProvider::AppListShown() {
@@ -144,10 +165,10 @@
     // the result.
 
     provider_results.emplace_back(
-        MakeResult(path_or_error->get_path(), score, /*is_chip=*/false));
+        MakeListResult(path_or_error->get_path(), score));
     if (suggested_files_enabled_) {
       provider_results.emplace_back(
-          MakeResult(path_or_error->get_path(), score, /*is_chip=*/true));
+          MakeChipResult(path_or_error->get_path(), score));
     }
   }
 
@@ -155,16 +176,22 @@
   SwapResults(&provider_results);
 }
 
-std::unique_ptr<FileResult> DriveZeroStateProvider::MakeResult(
+std::unique_ptr<FileResult> DriveZeroStateProvider::MakeListResult(
     const base::FilePath& filepath,
-    const float relevance,
-    const bool is_chip) {
+    const float relevance) {
   return std::make_unique<FileResult>(
-      kSchema, ReparentToDriveMount(filepath, drive_service_),
+      kListSchema, ReparentToDriveMount(filepath, drive_service_),
+      ash::AppListSearchResultType::kDriveQuickAccess,
+      ash::SearchResultDisplayType::kList, relevance, profile_);
+}
+
+std::unique_ptr<FileResult> DriveZeroStateProvider::MakeChipResult(
+    const base::FilePath& filepath,
+    const float relevance) {
+  return std::make_unique<FileResult>(
+      kChipSchema, ReparentToDriveMount(filepath, drive_service_),
       ash::AppListSearchResultType::kDriveQuickAccessChip,
-      is_chip ? ash::SearchResultDisplayType::kChip
-              : ash::SearchResultDisplayType::kList,
-      relevance, profile_);
+      ash::SearchResultDisplayType::kChip, relevance, profile_);
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.h b/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.h
index a87a991e..fd8bb422 100644
--- a/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.h
+++ b/chrome/browser/ui/app_list/search/files/drive_zero_state_provider.h
@@ -50,9 +50,10 @@
   void OnFilePathsLocated(
       base::Optional<std::vector<drivefs::mojom::FilePathOrErrorPtr>> paths);
 
-  std::unique_ptr<FileResult> MakeResult(const base::FilePath& filepath,
-                                         const float relevance,
-                                         const bool is_chip);
+  std::unique_ptr<FileResult> MakeListResult(const base::FilePath& filepath,
+                                             const float relevance);
+  std::unique_ptr<FileResult> MakeChipResult(const base::FilePath& filepath,
+                                             const float relevance);
 
   Profile* const profile_;
   drive::DriveIntegrationService* const drive_service_;
diff --git a/chrome/browser/ui/app_list/search/files/file_result.cc b/chrome/browser/ui/app_list/search/files/file_result.cc
index cf90088f..d017dfeb 100644
--- a/chrome/browser/ui/app_list/search/files/file_result.cc
+++ b/chrome/browser/ui/app_list/search/files/file_result.cc
@@ -58,8 +58,10 @@
   SetResultType(result_type);
   switch (result_type) {
     case ResultType::kDriveQuickAccess:
+    case ResultType::kDriveQuickAccessChip:
       SetMetricsType(ash::DRIVE_QUICK_ACCESS);
       break;
+    case ResultType::kFileChip:
     case ResultType::kZeroStateFile:
       SetMetricsType(ash::ZERO_STATE_FILE);
       break;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 5075fb3..2d98a99 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -18,6 +18,7 @@
 #include "ash/public/cpp/window_animation_types.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/pattern.h"
@@ -1153,7 +1154,13 @@
     ash::ShelfItemType shelf_item_type,
     const base::string16& title) {
   CHECK(item_delegate);
-  CHECK(!GetItem(item_delegate->shelf_id()));
+  if (GetItem(item_delegate->shelf_id())) {
+    // TODO(crbug.com/1090134): try and identify why this would be called when
+    // there is an already existing shelf item for this ID.
+    base::debug::DumpWithoutCrashing();
+    return item_delegate->shelf_id();
+  }
+
   ash::ShelfItem item;
   item.status = status;
   item.type = shelf_item_type;
diff --git a/chrome/browser/ui/ash/login_screen_client.cc b/chrome/browser/ui/ash/login_screen_client.cc
index 2adc1562..0337c40 100644
--- a/chrome/browser/ui/ash/login_screen_client.cc
+++ b/chrome/browser/ui/ash/login_screen_client.cc
@@ -15,16 +15,22 @@
 #include "chrome/browser/chromeos/login/help_app_launcher.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
 #include "chrome/browser/chromeos/login/login_auth_recorder.h"
+#include "chrome/browser/chromeos/login/login_pref_names.h"
 #include "chrome/browser/chromeos/login/reauth_stats.h"
+#include "chrome/browser/chromeos/login/saml/in_session_password_sync_manager.h"
+#include "chrome/browser/chromeos/login/saml/in_session_password_sync_manager_factory.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
 #include "chrome/common/webui_url_constants.h"
+#include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/remove_user_delegate.h"
 #include "components/user_manager/user_names.h"
 
@@ -329,5 +335,21 @@
   if (chromeos::LoginDisplayHost::default_host()) {
     chromeos::LoginDisplayHost::default_host()->ShowGaiaDialog(
         prefilled_account);
+  } else {
+    const user_manager::User* user =
+        user_manager::UserManager::Get()->FindUser(prefilled_account);
+    Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user);
+    if (profile->GetPrefs()->GetBoolean(
+            chromeos::prefs::kSamlLockScreenReauthenticationEnabled)) {
+      DCHECK(session_manager::SessionManager::Get()->IsScreenLocked());
+      chromeos::InSessionPasswordSyncManager* password_sync_manager =
+          chromeos::InSessionPasswordSyncManagerFactory::GetForProfile(profile);
+      if (!password_sync_manager->lock_screen_start_reauth_dialog) {
+        password_sync_manager->lock_screen_start_reauth_dialog =
+            std::unique_ptr<chromeos::LockScreenStartReauthDialog>(
+                new chromeos::LockScreenStartReauthDialog());
+      }
+      password_sync_manager->lock_screen_start_reauth_dialog->Show();
+    }
   }
 }
diff --git a/chrome/browser/ui/browser_ui_prefs.cc b/chrome/browser/ui/browser_ui_prefs.cc
index 887bfc8..796f732 100644
--- a/chrome/browser/ui/browser_ui_prefs.cc
+++ b/chrome/browser/ui/browser_ui_prefs.cc
@@ -94,6 +94,7 @@
   registry->RegisterStringPref(prefs::kWebRTCUDPPortRange, std::string());
   registry->RegisterBooleanPref(prefs::kWebRtcEventLogCollectionAllowed, false);
   registry->RegisterListPref(prefs::kWebRtcLocalIpsAllowedUrls);
+  registry->RegisterBooleanPref(prefs::kWebRTCAllowLegacyTLSProtocols, false);
 
   // Dictionaries to keep track of default tasks in the file browser.
   registry->RegisterDictionaryPref(
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
index 4a414df0..d9e3dcd4 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -420,7 +420,7 @@
 // embedded flash fullscreen, since the Flash plugin handles user permissions
 // requests itself).
 // Flaky on Linux: crbug.com/1066607
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC)
 #define MAYBE_PrivilegedMouseLockAndFullscreen \
   DISABLED_PrivilegedMouseLockAndFullscreen
 #else
diff --git a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
index 37e19db..c5a0f7d4 100644
--- a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
+++ b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
@@ -84,7 +84,7 @@
 // Launches the app, waits for the app url to load.
 Browser* LaunchWebAppBrowserAndWait(Profile* profile, const AppId& app_id) {
   ui_test_utils::UrlLoadObserver url_observer(
-      WebAppProvider::Get(profile)->registrar().GetAppStartUrl(app_id),
+      WebAppProvider::Get(profile)->registrar().GetAppLaunchUrl(app_id),
       content::NotificationService::AllSources());
   Browser* const app_browser = LaunchWebAppBrowser(profile, app_id);
   url_observer.Wait();
diff --git a/chrome/browser/ui/web_applications/web_app_launch_manager.cc b/chrome/browser/ui/web_applications/web_app_launch_manager.cc
index fe87220..3befff5 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_manager.cc
+++ b/chrome/browser/ui/web_applications/web_app_launch_manager.cc
@@ -131,7 +131,7 @@
       params.override_url.is_empty()
           ? os_integration_manager
                 .GetMatchingFileHandlerURL(params.app_id, params.launch_files)
-                .value_or(provider_->registrar().GetAppStartUrl(params.app_id))
+                .value_or(provider_->registrar().GetAppLaunchUrl(params.app_id))
           : params.override_url;
 
   // Place new windows on the specified display.
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index c414e6cd..eb6691ef 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/ui/webui/chromeos/account_manager/account_manager_welcome_ui.h"
 #include "chrome/browser/ui/webui/chromeos/account_manager/account_migration_welcome_ui.h"
 #include "chrome/browser/ui/webui/chromeos/chrome_url_disabled/chrome_url_disabled_ui.h"
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h"
 #include "chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_ui.h"
 #include "chrome/browser/ui/webui/commander/commander_ui.h"
 #include "chrome/browser/ui/webui/components/components_ui.h"
@@ -623,6 +624,13 @@
     }
     return &NewWebUI<chromeos::UrgentPasswordExpiryNotificationUI>;
   }
+  if (url.host_piece() == chrome::kChromeUILockScreenStartReauthHost) {
+    if (!profile->GetPrefs()->GetBoolean(
+            chromeos::prefs::kSamlLockScreenReauthenticationEnabled)) {
+      return nullptr;
+    }
+    return &NewWebUI<chromeos::LockScreenStartReauthUI>;
+  }
   if (url.host_piece() == chrome::kChromeUIAccountManagerErrorHost)
     return &NewWebUI<chromeos::AccountManagerErrorUI>;
   if (url.host_piece() == chrome::kChromeUIAccountManagerWelcomeHost)
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc
new file mode 100644
index 0000000..0275b3f
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.cc
@@ -0,0 +1,93 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/json/json_writer.h"
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/browser_resources.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/strings/grit/ui_strings.h"
+
+namespace chromeos {
+
+namespace {
+
+LockScreenStartReauthDialog* g_dialog = nullptr;
+
+constexpr gfx::Size kLockScreenReauthSize(768, 640);
+
+gfx::Size FitSizeToDisplay(const gfx::Size& desired) {
+  const display::Display display =
+      display::Screen::GetScreen()->GetPrimaryDisplay();
+
+  gfx::Size display_size = display.size();
+
+  if (display.rotation() == display::Display::ROTATE_90 ||
+      display.rotation() == display::Display::ROTATE_270) {
+    display_size = gfx::Size(display_size.height(), display_size.width());
+  }
+
+  display_size.SetToMin(desired);
+  return display_size;
+}
+
+}  // namespace
+
+BaseLockDialog::BaseLockDialog(GURL url, gfx::Size desired_size)
+    : SystemWebDialogDelegate(url, /*title=*/base::string16()),
+      desired_size_(desired_size) {}
+
+BaseLockDialog::~BaseLockDialog() {}
+
+void BaseLockDialog::GetDialogSize(gfx::Size* size) const {
+  *size = FitSizeToDisplay(desired_size_);
+}
+
+void BaseLockDialog::AdjustWidgetInitParams(views::Widget::InitParams* params) {
+  params->type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
+}
+
+ui::ModalType BaseLockDialog::GetDialogModalType() const {
+  return ui::ModalType::MODAL_TYPE_SYSTEM;
+}
+
+void LockScreenStartReauthDialog::Show() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (g_dialog) {
+    g_dialog->Focus();
+    return;
+  }
+  g_dialog = new LockScreenStartReauthDialog();
+  g_dialog->ShowSystemDialog();
+}
+
+void LockScreenStartReauthDialog::Dismiss() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (g_dialog)
+    g_dialog->Close();
+}
+
+bool LockScreenStartReauthDialog::IsRunning() {
+  return g_dialog;
+}
+
+LockScreenStartReauthDialog::LockScreenStartReauthDialog()
+    : BaseLockDialog(GURL(chrome::kChromeUILockScreenStartReauthURL),
+                           kLockScreenReauthSize) {}
+
+LockScreenStartReauthDialog::~LockScreenStartReauthDialog() {
+  DCHECK_EQ(this, g_dialog);
+  g_dialog = nullptr;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h
new file mode 100644
index 0000000..f46252c
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_dialogs.h
@@ -0,0 +1,44 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_DIALOGS_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_DIALOGS_H_
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h"
+#include "ui/web_dialogs/web_dialog_ui.h"
+
+namespace chromeos {
+
+// A modal system dialog without any frame decorating it.
+class BaseLockDialog : public SystemWebDialogDelegate {
+ protected:
+  BaseLockDialog(GURL url, gfx::Size desired_size);
+  BaseLockDialog(BaseLockDialog const&) = delete;
+  ~BaseLockDialog() override;
+
+  // ui::WebDialogDelegate:
+  void GetDialogSize(gfx::Size* size) const override;
+  void AdjustWidgetInitParams(views::Widget::InitParams* params) override;
+  ui::ModalType GetDialogModalType() const override;
+
+ private:
+  gfx::Size desired_size_;
+};
+
+class LockScreenStartReauthDialog : public BaseLockDialog {
+ public:
+  LockScreenStartReauthDialog();
+  LockScreenStartReauthDialog(LockScreenStartReauthDialog const&) = delete;
+  ~LockScreenStartReauthDialog() override;
+
+  void Show();
+  void Dismiss();
+  bool IsRunning();
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_DIALOGS_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc
new file mode 100644
index 0000000..58d29d6f
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.cc
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h"
+
+namespace chromeos {
+
+LockScreenReauthHandler::LockScreenReauthHandler() = default;
+LockScreenReauthHandler::~LockScreenReauthHandler() = default;
+
+void LockScreenReauthHandler::HandleInitialize(const base::ListValue* value) {}
+
+void LockScreenReauthHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "initialize",
+      base::BindRepeating(&LockScreenReauthHandler::HandleInitialize,
+                          weak_factory_.GetWeakPtr()));
+}
+
+}  // namespace chromeos
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h
new file mode 100644
index 0000000..f8871e1
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "components/user_manager/user.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace chromeos {
+
+class LockScreenReauthHandler : public content::WebUIMessageHandler {
+ public:
+  LockScreenReauthHandler();
+  ~LockScreenReauthHandler() override;
+
+  void RegisterMessages() override;
+
+  void HandleInitialize(const base::ListValue*);
+
+ private:
+  base::WeakPtrFactory<LockScreenReauthHandler> weak_factory_{this};
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_REAUTH_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.cc
new file mode 100644
index 0000000..b358215
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.cc
@@ -0,0 +1,68 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h"
+
+#include <memory>
+
+#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
+#include "chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_reauth_handler.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/browser_resources.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace chromeos {
+
+LockScreenStartReauthUI::LockScreenStartReauthUI(content::WebUI* web_ui)
+    : ui::WebDialogUI(web_ui) {
+  Profile* profile = Profile::FromWebUI(web_ui);
+  const user_manager::User* user =
+      ProfileHelper::Get()->GetUserByProfile(profile);
+  std::string email;
+  if (user) {
+    email = user->GetDisplayEmail();
+  }
+
+  content::WebUIDataSource* source = content::WebUIDataSource::Create(
+      chrome::kChromeUILockScreenStartReauthHost);
+
+  web_ui->AddMessageHandler(std::make_unique<LockScreenReauthHandler>());
+
+  // TODO(crbug.com/1098690): Trusted Type Polymer
+  source->DisableTrustedTypesCSP();
+
+  source->AddString("lockScreenReauthSubtitile",
+                    l10n_util::GetStringFUTF16(IDS_LOCK_SCREEN_REAUTH_SUBTITLE,
+                                               base::UTF8ToUTF16(email)));
+  source->AddString("lockScreenReauthSubtitileWithError",
+                    l10n_util::GetStringFUTF16(IDS_LOCK_SCREEN_WRONG_USER,
+                                               base::UTF8ToUTF16(email)));
+
+  source->AddString("lockScreenVerifyButton",
+                    l10n_util::GetStringUTF16(IDS_LOCK_SCREEN_VERIFY_BUTTON));
+  source->AddString(
+      "lockScreenVerifyAgainButton",
+      l10n_util::GetStringUTF16(IDS_LOCK_SCREEN_VERIFY_AGAIN_BUTTON));
+  source->AddString("lockScreenCancelButton",
+                    l10n_util::GetStringUTF16(IDS_LOCK_SCREEN_CANCEL_BUTTON));
+  source->AddString("loginWelcomeMessage",
+                    l10n_util::GetStringUTF16(IDS_LOCK_SCREEN_VERIFY_ACCOUNT));
+  source->AddString(
+      "loginWelcomeMessageWithError",
+      l10n_util::GetStringUTF16(IDS_LOCK_SCREEN_VERIFICATION_FAILED));
+
+  source->SetDefaultResource(IDR_LOCK_SCREEN_REAUTH_HTML);
+
+  source->AddResourcePath("authenticator.js", IDR_GAIA_AUTH_AUTHENTICATOR_JS);
+
+  source->AddResourcePath("lock_screen_reauth.js", IDR_LOCK_SCREEN_REAUTH_JS);
+
+  content::WebUIDataSource::Add(profile, source);
+}
+
+LockScreenStartReauthUI::~LockScreenStartReauthUI() = default;
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h
new file mode 100644
index 0000000..99dfba9e
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/lock_screen_start_reauth_ui.h
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_START_REAUTH_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_START_REAUTH_UI_H_
+
+#include "ui/web_dialogs/web_dialog_ui.h"
+
+namespace chromeos {
+
+// For chrome:://lock-reauth
+class LockScreenStartReauthUI : public ui::WebDialogUI {
+ public:
+  explicit LockScreenStartReauthUI(content::WebUI* web_ui);
+  ~LockScreenStartReauthUI() override;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_IN_SESSION_PASSWORD_CHANGE_LOCK_SCREEN_START_REAUTH_UI_H_
diff --git a/chrome/browser/ui/webui/new_tab_page/promo_browser_command/promo_browser_command_handler.cc b/chrome/browser/ui/webui/new_tab_page/promo_browser_command/promo_browser_command_handler.cc
index 57ce137..8a70b840 100644
--- a/chrome/browser/ui/webui/new_tab_page/promo_browser_command/promo_browser_command_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_page/promo_browser_command/promo_browser_command_handler.cc
@@ -6,6 +6,7 @@
 
 #include "base/feature_list.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/metrics/user_metrics.h"
 #include "chrome/browser/browser_features.h"
 #include "chrome/browser/command_updater_impl.h"
 #include "chrome/browser/profiles/profile.h"
@@ -64,6 +65,8 @@
     case Command::kOpenSafetyCheck:
       NavigateToURL(GURL(chrome::GetSettingsUrl(chrome::kSafetyCheckSubPage)),
                     disposition);
+      base::RecordAction(
+          base::UserMetricsAction("NewTabPage_Promos_SafetyCheck"));
       break;
     default:
       NOTREACHED() << "Unspecified behavior for command " << id;
diff --git a/chrome/browser/ui/webui/settings/chromeos/OWNERS b/chrome/browser/ui/webui/settings/chromeos/OWNERS
index 2161067..b89ca31 100644
--- a/chrome/browser/ui/webui/settings/chromeos/OWNERS
+++ b/chrome/browser/ui/webui/settings/chromeos/OWNERS
@@ -2,5 +2,6 @@
 
 per-file languages_section*=myy@chromium.org
 per-file multidevice_handler*=file://chromeos/components/multidevice/OWNERS
+per-file account_manager_*=file://chromeos/components/account_manager/OWNERS
 
 # COMPONENT: OS>Systems>Settings
diff --git a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler_browsertest.cc b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler_browsertest.cc
index dda1439..3cd2374 100644
--- a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler_browsertest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
-#include "chrome/browser/web_applications/external_web_app_manager.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/components/account_manager/account_manager.h"
@@ -127,11 +126,6 @@
       delete;
 
   void SetUpOnMainThread() override {
-    // Disable preinstalled app scan, it is not compatible with the testing
-    // profile we create here.
-    // TODO(crbug.com/1131834): Make it compatible.
-    web_app::ExternalWebAppManager::SkipStartupForTesting();
-
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
         std::make_unique<chromeos::FakeChromeUserManager>());
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -232,8 +226,9 @@
   std::unique_ptr<TestingAccountManagerUIHandler> handler_;
 };
 
+// TODO(https://crbug.com/1131834): Re-enable flaky test.
 IN_PROC_BROWSER_TEST_P(AccountManagerUIHandlerTest,
-                       OnGetAccountsNoSecondaryAccounts) {
+                       DISABLED_OnGetAccountsNoSecondaryAccounts) {
   const std::vector<AccountManager::Account> account_manager_accounts =
       GetAccountsFromAccountManager();
   // Only Primary account.
@@ -276,8 +271,9 @@
   }
 }
 
+// TODO(https://crbug.com/1131819): Re-enable flaky test.
 IN_PROC_BROWSER_TEST_P(AccountManagerUIHandlerTest,
-                       OnGetAccountsWithSecondaryAccounts) {
+                       DISABLED_OnGetAccountsWithSecondaryAccounts) {
   UpsertAccount("secondary1@example.com");
   UpsertAccount("secondary2@example.com");
   const std::vector<AccountManager::Account> account_manager_accounts =
diff --git a/chrome/browser/ui/webui/signin/profile_picker_ui.cc b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
index 088614e3..c047c18 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/browser_resources.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/profile_picker_resources.h"
@@ -136,12 +137,40 @@
 
   std::string generated_path =
       "@out_folder@/gen/chrome/browser/resources/signin/profile_picker/";
+
+  AddStrings(html_source);
+#if BUILDFLAG(OPTIMIZE_WEBUI)
+  webui::SetupBundledWebUIDataSource(
+      html_source, "profile_picker.js",
+      IDR_PROFILE_PICKER_PROFILE_PICKER_ROLLUP_JS,
+      IDR_PROFILE_PICKER_PROFILE_PICKER_HTML);
+  html_source->AddResourcePath("lazy_load.js",
+                               IDR_PROFILE_PICKER_LAZY_LOAD_ROLLUP_JS);
+  html_source->AddResourcePath("shared.rollup.js",
+                               IDR_PROFILE_PICKER_SHARED_ROLLUP_JS);
+  html_source->AddResourcePath("images/left_banner_image.svg",
+                               IDR_PROFILE_PICKER_IMAGES_LEFT_BANNER_IMAGE);
+  html_source->AddResourcePath("images/right_banner_image.svg",
+                               IDR_PROFILE_PICKER_IMAGES_RIGHT_BANNER_IMAGE);
+  html_source->AddResourcePath(
+      "images/dark_mode_left_banner_image.svg",
+      IDR_PROFILE_PICKER_IMAGES_DARK_MODE_LEFT_BANNER_IMAGE);
+  html_source->AddResourcePath(
+      "images/dark_mode_right_banner_image.svg",
+      IDR_PROFILE_PICKER_IMAGES_DARK_MODE_RIGHT_BANNER_IMAGE);
+  html_source->AddResourcePath(
+      "profile_creation_flow/images/banner_light_image.svg",
+      IDR_PROFILE_PICKER_PROFILE_CREATION_FLOW_IMAGES_BANNER_LIGHT_IMAGE);
+  html_source->AddResourcePath(
+      "profile_creation_flow/images/banner_dark_image.svg",
+      IDR_PROFILE_PICKER_PROFILE_CREATION_FLOW_IMAGES_BANNER_DARK_IMAGE);
+#else
+  html_source->AddResourcePath("signin_icons.js", IDR_SIGNIN_ICONS_JS);
   webui::SetupWebUIDataSource(
       html_source,
       base::make_span(kProfilePickerResources, kProfilePickerResourcesSize),
       generated_path, IDR_PROFILE_PICKER_PROFILE_PICKER_HTML);
-  html_source->AddResourcePath("signin_icons.js", IDR_SIGNIN_ICONS_JS);
-  AddStrings(html_source);
+#endif
   content::WebUIDataSource::Add(profile, html_source);
 }
 
diff --git a/chrome/browser/web_applications/components/app_registrar.cc b/chrome/browser/web_applications/components/app_registrar.cc
index b308ea6a..103e40c 100644
--- a/chrome/browser/web_applications/components/app_registrar.cc
+++ b/chrome/browser/web_applications/components/app_registrar.cc
@@ -131,6 +131,23 @@
       profile()->GetPrefs(), app_id, install_source);
 }
 
+GURL AppRegistrar::GetAppLaunchUrl(const AppId& app_id) const {
+  const GURL& start_url = GetAppStartUrl(app_id);
+  const std::string* launch_query_params = GetAppLaunchQueryParams(app_id);
+  if (!start_url.is_valid() || !launch_query_params)
+    return start_url;
+
+  GURL::Replacements replacements;
+  if (start_url.query_piece().empty()) {
+    replacements.SetQueryStr(*launch_query_params);
+    return start_url.ReplaceComponents(replacements);
+  }
+
+  std::string query_params = start_url.query() + "&" + *launch_query_params;
+  replacements.SetQueryStr(query_params);
+  return start_url.ReplaceComponents(replacements);
+}
+
 extensions::BookmarkAppRegistrar* AppRegistrar::AsBookmarkAppRegistrar() {
   return nullptr;
 }
diff --git a/chrome/browser/web_applications/components/app_registrar.h b/chrome/browser/web_applications/components/app_registrar.h
index a974a94..96f637c 100644
--- a/chrome/browser/web_applications/components/app_registrar.h
+++ b/chrome/browser/web_applications/components/app_registrar.h
@@ -90,6 +90,11 @@
   virtual base::Optional<SkColor> GetAppBackgroundColor(
       const AppId& app_id) const = 0;
   virtual const GURL& GetAppStartUrl(const AppId& app_id) const = 0;
+  virtual const std::string* GetAppLaunchQueryParams(
+      const AppId& app_id) const = 0;
+
+  // Returns the start_url with launch_query_params appended to the end if any.
+  GURL GetAppLaunchUrl(const AppId& app_id) const;
 
   // TODO(crbug.com/910016): Replace uses of this with GetAppScope().
   virtual base::Optional<GURL> GetAppScopeInternal(
diff --git a/chrome/browser/web_applications/components/external_install_options.cc b/chrome/browser/web_applications/components/external_install_options.cc
index ffbc0c33..5b49a29f 100644
--- a/chrome/browser/web_applications/components/external_install_options.cc
+++ b/chrome/browser/web_applications/components/external_install_options.cc
@@ -120,6 +120,8 @@
 
   params.additional_search_terms = install_options.additional_search_terms;
 
+  params.launch_query_params = install_options.launch_query_params;
+
   return params;
 }
 
diff --git a/chrome/browser/web_applications/components/external_install_options.h b/chrome/browser/web_applications/components/external_install_options.h
index b1555403..589c1f6 100644
--- a/chrome/browser/web_applications/components/external_install_options.h
+++ b/chrome/browser/web_applications/components/external_install_options.h
@@ -103,6 +103,9 @@
   // it.
   bool reinstall_placeholder = false;
 
+  // Optional query parameters to add to the start_url when launching the app.
+  base::Optional<std::string> launch_query_params;
+
   // Whether we should load |service_worker_registration_url| after successful
   // installation to allow the site to install its service worker and set up
   // offline caching.
diff --git a/chrome/browser/web_applications/components/install_manager.h b/chrome/browser/web_applications/components/install_manager.h
index 6701606..b0dff73 100644
--- a/chrome/browser/web_applications/components/install_manager.h
+++ b/chrome/browser/web_applications/components/install_manager.h
@@ -122,6 +122,8 @@
     bool require_manifest = false;
 
     std::vector<std::string> additional_search_terms;
+
+    base::Optional<std::string> launch_query_params;
   };
   // Starts a background web app installation process for a given
   // |web_contents|.
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_registrar.cc b/chrome/browser/web_applications/extensions/bookmark_app_registrar.cc
index 313d4d5..379f1253 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_registrar.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_registrar.cc
@@ -149,6 +149,12 @@
                    : GURL::EmptyGURL();
 }
 
+// Only implemented for WebApp. Bookmark apps are going away.
+const std::string* BookmarkAppRegistrar::GetAppLaunchQueryParams(
+    const web_app::AppId& app_id) const {
+  return nullptr;
+}
+
 base::Optional<GURL> BookmarkAppRegistrar::GetAppScopeInternal(
     const web_app::AppId& app_id) const {
   const Extension* extension = GetBookmarkAppDchecked(app_id);
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_registrar.h b/chrome/browser/web_applications/extensions/bookmark_app_registrar.h
index 3931f26..dcb11e2 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_registrar.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_registrar.h
@@ -46,6 +46,8 @@
   base::Optional<SkColor> GetAppBackgroundColor(
       const web_app::AppId& app_id) const override;
   const GURL& GetAppStartUrl(const web_app::AppId& app_id) const override;
+  const std::string* GetAppLaunchQueryParams(
+      const web_app::AppId& app_id) const override;
   base::Optional<GURL> GetAppScopeInternal(
       const web_app::AppId& app_id) const override;
   web_app::DisplayMode GetAppDisplayMode(
diff --git a/chrome/browser/web_applications/external_web_app_manager_browsertest.cc b/chrome/browser/web_applications/external_web_app_manager_browsertest.cc
index 296a8d7..e134328 100644
--- a/chrome/browser/web_applications/external_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/external_web_app_manager_browsertest.cc
@@ -81,8 +81,73 @@
   ~ExternalWebAppManagerBrowserTest() override = default;
 };
 
-// This JSON config functionality is only available on Chrome OS.
-#if defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
+                       LaunchQueryParamsBasic) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL start_url = embedded_test_server()->GetURL("/web_apps/basic.html");
+  AppId app_id = GenerateAppIdFromURL(start_url);
+  EXPECT_FALSE(registrar().IsInstalled(app_id));
+
+  InstallResultCode code =
+      SyncDefaultAppConfig(start_url, base::ReplaceStringPlaceholders(
+                                          R"({
+                "app_url": "$1",
+                "launch_container": "window",
+                "user_type": ["unmanaged"],
+                "launch_query_params": "test_launch_params"
+              })",
+                                          {start_url.spec()}, nullptr));
+  EXPECT_EQ(code, InstallResultCode::kSuccessNewInstall);
+
+  EXPECT_TRUE(registrar().IsInstalled(app_id));
+  EXPECT_EQ(registrar().GetAppStartUrl(app_id).spec(), start_url);
+
+  GURL launch_url =
+      embedded_test_server()->GetURL("/web_apps/basic.html?test_launch_params");
+  EXPECT_EQ(registrar().GetAppLaunchUrl(app_id), launch_url);
+
+  Browser* app_browser = LaunchWebAppBrowserAndWait(profile(), app_id);
+  EXPECT_EQ(
+      app_browser->tab_strip_model()->GetActiveWebContents()->GetVisibleURL(),
+      launch_url);
+}
+
+IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
+                       LaunchQueryParamsComplex) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL install_url = embedded_test_server()->GetURL(
+      "/web_apps/query_params_in_start_url.html");
+  GURL start_url = embedded_test_server()->GetURL(
+      "/web_apps/query_params_in_start_url.html?query_params=in&start=url");
+  AppId app_id = GenerateAppIdFromURL(start_url);
+  EXPECT_FALSE(registrar().IsInstalled(app_id));
+
+  InstallResultCode code =
+      SyncDefaultAppConfig(install_url, base::ReplaceStringPlaceholders(
+                                            R"({
+                "app_url": "$1",
+                "launch_container": "window",
+                "user_type": ["unmanaged"],
+                "launch_query_params": "!@#$$%^*&)("
+              })",
+                                            {install_url.spec()}, nullptr));
+  EXPECT_EQ(code, InstallResultCode::kSuccessNewInstall);
+
+  EXPECT_TRUE(registrar().IsInstalled(app_id));
+  EXPECT_EQ(registrar().GetAppStartUrl(app_id).spec(), start_url);
+
+  GURL launch_url = embedded_test_server()->GetURL(
+      "/web_apps/"
+      "query_params_in_start_url.html?query_params=in&start=url&!@%23$%^*&)(");
+  EXPECT_EQ(registrar().GetAppLaunchUrl(app_id), launch_url);
+
+  Browser* app_browser = LaunchWebAppBrowserAndWait(profile(), app_id);
+  EXPECT_EQ(
+      app_browser->tab_strip_model()->GetActiveWebContents()->GetVisibleURL(),
+      launch_url);
+}
 
 IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, UninstallAndReplace) {
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -117,6 +182,10 @@
   EXPECT_EQ(app, uninstalled_app.get());
 }
 
+// The offline manifest JSON config functionality is only available on Chrome
+// OS.
+#if defined(OS_CHROMEOS)
+
 // Check that offline fallback installs work offline.
 IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
                        OfflineFallbackManifestSiteOffline) {
diff --git a/chrome/browser/web_applications/external_web_app_utils.cc b/chrome/browser/web_applications/external_web_app_utils.cc
index 19046c7..77f5cb24 100644
--- a/chrome/browser/web_applications/external_web_app_utils.cc
+++ b/chrome/browser/web_applications/external_web_app_utils.cc
@@ -71,6 +71,10 @@
 constexpr char kLaunchContainerTab[] = "tab";
 constexpr char kLaunchContainerWindow[] = "window";
 
+// kLaunchQueryParams is an optional string which specifies query parameters to
+// add to the start_url when launching the app.
+constexpr char kLaunchQueryParams[] = "launch_query_params";
+
 // kLoadAndAwaitServiceWorkerRegistration is an optional bool that specifies
 // whether to fetch the |kServiceWorkerRegistrationUrl| after installation to
 // allow time for the app to register its service worker. This is done as a
@@ -281,6 +285,16 @@
     return Result::Error();
   }
 
+  // launch_query_params
+  value = app_config.FindKey(kLaunchQueryParams);
+  if (value) {
+    if (!value->is_string()) {
+      LOG(ERROR) << file << " had an invalid " << kLaunchQueryParams;
+      return Result::Error();
+    }
+    options.launch_query_params = value->GetString();
+  }
+
   // load_and_await_service_worker_registration
   value = app_config.FindKey(kLoadAndAwaitServiceWorkerRegistration);
   if (value) {
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto
index 1b73095..5d8a5198 100644
--- a/chrome/browser/web_applications/proto/web_app.proto
+++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -157,4 +157,6 @@
   optional RunOnOsLoginMode user_run_on_os_login_mode = 24;
 
   optional ShareTarget share_target = 25;
+
+  optional string launch_query_params = 26;
 }
diff --git a/chrome/browser/web_applications/test/test_app_registrar.cc b/chrome/browser/web_applications/test/test_app_registrar.cc
index 9e22814..eb8fb30a 100644
--- a/chrome/browser/web_applications/test/test_app_registrar.cc
+++ b/chrome/browser/web_applications/test/test_app_registrar.cc
@@ -112,6 +112,11 @@
   return iterator->second.launch_url;
 }
 
+const std::string* TestAppRegistrar::GetAppLaunchQueryParams(
+    const AppId& app_id) const {
+  return nullptr;
+}
+
 base::Optional<GURL> TestAppRegistrar::GetAppScopeInternal(
     const AppId& app_id) const {
   const auto& result = installed_apps_.find(app_id);
diff --git a/chrome/browser/web_applications/test/test_app_registrar.h b/chrome/browser/web_applications/test/test_app_registrar.h
index 4bb0b6b..28683cf 100644
--- a/chrome/browser/web_applications/test/test_app_registrar.h
+++ b/chrome/browser/web_applications/test/test_app_registrar.h
@@ -60,6 +60,8 @@
   base::Optional<SkColor> GetAppBackgroundColor(
       const AppId& app_id) const override;
   const GURL& GetAppStartUrl(const AppId& app_id) const override;
+  const std::string* GetAppLaunchQueryParams(
+      const AppId& app_id) const override;
   base::Optional<GURL> GetAppScopeInternal(const AppId& app_id) const override;
   DisplayMode GetAppDisplayMode(const AppId& app_id) const override;
   DisplayMode GetAppUserDisplayMode(const AppId& app_id) const override;
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc
index ad7b65f..47407e200 100644
--- a/chrome/browser/web_applications/web_app.cc
+++ b/chrome/browser/web_applications/web_app.cc
@@ -263,6 +263,11 @@
   sync_fallback_data_ = std::move(sync_fallback_data);
 }
 
+void WebApp::SetLaunchQueryParams(
+    base::Optional<std::string> launch_query_params) {
+  launch_query_params_ = std::move(launch_query_params);
+}
+
 WebApp::SyncFallbackData::SyncFallbackData() = default;
 
 WebApp::SyncFallbackData::~SyncFallbackData() = default;
@@ -288,6 +293,9 @@
   out << "app_id: " << app.app_id_ << std::endl
       << "  name: " << app.name_ << std::endl
       << "  start_url: " << app.start_url_ << std::endl
+      << "  launch_query_params: "
+      << (app.launch_query_params_ ? *app.launch_query_params_ : std::string())
+      << std::endl
       << "  scope: " << app.scope_ << std::endl
       << "  theme_color: " << ColorToString(app.theme_color_) << std::endl
       << "  background_color: " << ColorToString(app.background_color_)
@@ -354,8 +362,8 @@
 
 bool operator==(const WebApp& app1, const WebApp& app2) {
   return std::tie(app1.app_id_, app1.sources_, app1.name_, app1.start_url_,
-                  app1.description_, app1.scope_, app1.theme_color_,
-                  app1.background_color_, app1.icon_infos_,
+                  app1.launch_query_params_, app1.description_, app1.scope_,
+                  app1.theme_color_, app1.background_color_, app1.icon_infos_,
                   app1.downloaded_icon_sizes_any_,
                   app1.downloaded_icon_sizes_maskable_, app1.is_generated_icon_,
                   app1.display_mode_, app1.display_mode_override_,
@@ -367,8 +375,8 @@
                   app1.sync_fallback_data_, app1.last_launch_time_,
                   app1.install_time_, app1.run_on_os_login_mode_) ==
          std::tie(app2.app_id_, app2.sources_, app2.name_, app2.start_url_,
-                  app2.description_, app2.scope_, app2.theme_color_,
-                  app2.background_color_, app2.icon_infos_,
+                  app2.launch_query_params_, app2.description_, app2.scope_,
+                  app2.theme_color_, app2.background_color_, app2.icon_infos_,
                   app2.downloaded_icon_sizes_any_,
                   app2.downloaded_icon_sizes_maskable_, app2.is_generated_icon_,
                   app2.display_mode_, app2.display_mode_override_,
diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h
index 63edf22..5aa6546 100644
--- a/chrome/browser/web_applications/web_app.h
+++ b/chrome/browser/web_applications/web_app.h
@@ -45,6 +45,11 @@
   const std::string& description() const { return description_; }
 
   const GURL& start_url() const { return start_url_; }
+
+  const std::string* launch_query_params() const {
+    return launch_query_params_ ? &launch_query_params_.value() : nullptr;
+  }
+
   const GURL& scope() const { return scope_; }
 
   const base::Optional<SkColor>& theme_color() const { return theme_color_; }
@@ -171,6 +176,7 @@
   void SetName(const std::string& name);
   void SetDescription(const std::string& description);
   void SetStartUrl(const GURL& launch_url);
+  void SetLaunchQueryParams(base::Optional<std::string> launch_query_params);
   void SetScope(const GURL& scope);
   void SetThemeColor(base::Optional<SkColor> theme_color);
   void SetBackgroundColor(base::Optional<SkColor> background_color);
@@ -218,6 +224,7 @@
   std::string name_;
   std::string description_;
   GURL start_url_;
+  base::Optional<std::string> launch_query_params_;
   // TODO(loyso): Implement IsValid() function that verifies that the start_url
   // is within the scope.
   GURL scope_;
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc
index 7115c45..89743aa3 100644
--- a/chrome/browser/web_applications/web_app_database.cc
+++ b/chrome/browser/web_applications/web_app_database.cc
@@ -157,6 +157,9 @@
   local_data->set_is_locally_installed(web_app.is_locally_installed());
 
   // Optional fields:
+  if (web_app.launch_query_params())
+    local_data->set_launch_query_params(*web_app.launch_query_params());
+
   if (web_app.display_mode() != DisplayMode::kUndefined) {
     local_data->set_display_mode(
         ToWebAppProtoDisplayMode(web_app.display_mode()));
@@ -394,6 +397,9 @@
   }
 
   // Optional fields:
+  if (local_data.has_launch_query_params())
+    web_app->SetLaunchQueryParams(local_data.launch_query_params());
+
   if (local_data.has_display_mode())
     web_app->SetDisplayMode(ToMojomDisplayMode(local_data.display_mode()));
 
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc
index 2985706..be9328f4 100644
--- a/chrome/browser/web_applications/web_app_database_unittest.cc
+++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -245,6 +245,9 @@
     app->SetDisplayModeOverride(std::vector<DisplayMode>(
         display_mode_override.begin(), display_mode_override.end()));
 
+    if (random.next_bool())
+      app->SetLaunchQueryParams(base::NumberToString(random.next_uint()));
+
     const RunOnOsLoginMode run_on_os_login_modes[3] = {
         RunOnOsLoginMode::kUndefined, RunOnOsLoginMode::kWindowed,
         RunOnOsLoginMode::kMinimized};
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc
index 9faa11fb..2fd18154 100644
--- a/chrome/browser/web_applications/web_app_install_task.cc
+++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -449,6 +449,9 @@
       if (!search_term.empty())
         web_app_info->additional_search_terms.push_back(std::move(search_term));
     }
+
+    if (install_params_->launch_query_params)
+      web_app_info->launch_query_params = install_params_->launch_query_params;
   }
 
   data_retriever_->CheckInstallabilityAndRetrieveManifest(
diff --git a/chrome/browser/web_applications/web_app_installation_utils.cc b/chrome/browser/web_applications/web_app_installation_utils.cc
index 6833d7c9..8c3540f 100644
--- a/chrome/browser/web_applications/web_app_installation_utils.cc
+++ b/chrome/browser/web_applications/web_app_installation_utils.cc
@@ -157,6 +157,7 @@
   web_app.SetDisplayModeOverride(web_app_info.display_override);
 
   web_app.SetDescription(base::UTF16ToUTF8(web_app_info.description));
+  web_app.SetLaunchQueryParams(web_app_info.launch_query_params);
   web_app.SetScope(web_app_info.scope);
   DCHECK(!web_app_info.theme_color.has_value() ||
          SkColorGetA(*web_app_info.theme_color) == SK_AlphaOPAQUE);
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc
index e1b0403..87d11c3 100644
--- a/chrome/browser/web_applications/web_app_registrar.cc
+++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -92,6 +92,12 @@
   return web_app ? web_app->start_url() : GURL::EmptyGURL();
 }
 
+const std::string* WebAppRegistrar::GetAppLaunchQueryParams(
+    const AppId& app_id) const {
+  auto* web_app = GetAppById(app_id);
+  return web_app ? web_app->launch_query_params() : nullptr;
+}
+
 base::Optional<GURL> WebAppRegistrar::GetAppScopeInternal(
     const AppId& app_id) const {
   auto* web_app = GetAppById(app_id);
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h
index be0be8f..184a167 100644
--- a/chrome/browser/web_applications/web_app_registrar.h
+++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -49,6 +49,8 @@
   base::Optional<SkColor> GetAppBackgroundColor(
       const AppId& app_id) const override;
   const GURL& GetAppStartUrl(const AppId& app_id) const override;
+  const std::string* GetAppLaunchQueryParams(
+      const AppId& app_id) const override;
   base::Optional<GURL> GetAppScopeInternal(const AppId& app_id) const override;
   DisplayMode GetAppDisplayMode(const AppId& app_id) const override;
   DisplayMode GetAppUserDisplayMode(const AppId& app_id) const override;
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 9210e94..98ceb1d1 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1601337561-307983a438d89a0d060ed0a79e008eada61629c3.profdata
+chrome-linux-master-1601380366-03c4c1b9f0c0034a1b47d4510e955a5823e9948c.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 8b06fed..1b99a0a0 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1601337561-8feee235133953607f7453082566ed5b7d8ffb34.profdata
+chrome-mac-master-1601380366-c2cef07ee462371a6daba327da84ce5730b353c6.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 89dfc05..ad3768ed 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1601294375-ec6f4fd0c2345f1003140fa4e4e991347147fa6d.profdata
+chrome-win32-master-1601326576-88be268f41c8e627e3f353defda83bb3fe16d327.profdata
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index f5b1882..c865923d 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1559,6 +1559,10 @@
 // Holds URL patterns that specify URLs for which local IP addresses are exposed
 // in ICE candidates.
 const char kWebRtcLocalIpsAllowedUrls[] = "webrtc.local_ips_allowed_urls";
+// Whether WebRTC PeerConnections are allowed to use legacy versions of the TLS
+// and DTLS protocols.
+const char kWebRTCAllowLegacyTLSProtocols[] =
+    "webrtc.allow_legacy_tls_protocols";
 
 #if !defined(OS_ANDROID)
 // Whether or not this profile has been shown the Welcome page.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 6ad2e8ff..196240e 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -503,6 +503,7 @@
 extern const char kWebRTCUDPPortRange[];
 extern const char kWebRtcEventLogCollectionAllowed[];
 extern const char kWebRtcLocalIpsAllowedUrls[];
+extern const char kWebRTCAllowLegacyTLSProtocols[];
 
 #if !defined(OS_ANDROID)
 extern const char kHasSeenWelcomePage[];
diff --git a/chrome/common/web_application_info.h b/chrome/common/web_application_info.h
index 34c81d1d..2ec0fe7 100644
--- a/chrome/common/web_application_info.h
+++ b/chrome/common/web_application_info.h
@@ -103,6 +103,9 @@
   // https://www.w3.org/TR/appmanifest/#start_url-member
   GURL start_url;
 
+  // Optional query parameters to add to the start_url when launching the app.
+  base::Optional<std::string> launch_query_params;
+
   // Scope for the app. Dictates what URLs will be opened in the app.
   GURL scope;
 
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 4ca3af4..51a36ce 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -255,6 +255,8 @@
 const char kChromeUIInternetDetailDialogHost[] = "internet-detail-dialog";
 const char kChromeUICrostiniCreditsHost[] = "crostini-credits";
 const char kChromeUICrostiniCreditsURL[] = "chrome://crostini-credits/";
+const char kChromeUILockScreenStartReauthHost[] = "lock-reauth";
+const char kChromeUILockScreenStartReauthURL[] = "chrome://lock-reauth";
 const char kChromeUIMachineLearningInternalsHost[] =
     "machine-learning-internals";
 const char kChromeUIMobileSetupHost[] = "mobilesetup";
@@ -315,6 +317,7 @@
       kChromeUIFirstRunHost,
       kChromeUIInternetConfigDialogHost,
       kChromeUIInternetDetailDialogHost,
+      kChromeUILockScreenStartReauthHost,
       kChromeUIMobileSetupHost,
       kChromeUIMultiDeviceSetupHost,
       kChromeUINetworkHost,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index 2fd2995..d9e05e4b 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -246,6 +246,8 @@
 extern const char kChromeUIInternetDetailDialogHost[];
 extern const char kChromeUICrostiniCreditsHost[];
 extern const char kChromeUICrostiniCreditsURL[];
+extern const char kChromeUILockScreenStartReauthHost[];
+extern const char kChromeUILockScreenStartReauthURL[];
 extern const char kChromeUIMachineLearningInternalsHost[];
 extern const char kChromeUIMobileSetupHost[];
 extern const char kChromeUIMobileSetupURL[];
diff --git a/chrome/installer/util/work_item_list.cc b/chrome/installer/util/work_item_list.cc
index c3485a0..9b06f78 100644
--- a/chrome/installer/util/work_item_list.cc
+++ b/chrome/installer/util/work_item_list.cc
@@ -175,10 +175,9 @@
                                                const std::wstring& value_name,
                                                int64_t value_data,
                                                bool overwrite) {
-  WorkItem* item =
-      reinterpret_cast<WorkItem*>(WorkItem::CreateSetRegValueWorkItem(
-          predefined_root, key_path, wow64_access, value_name, value_data,
-          overwrite));
+  WorkItem* item = WorkItem::CreateSetRegValueWorkItem(
+      predefined_root, key_path, wow64_access, value_name, value_data,
+      overwrite);
   AddWorkItem(item);
   return item;
 }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 7983783..07c059f 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -125,6 +125,8 @@
     "../browser/notifications/notification_display_service_tester.h",
     "../browser/notifications/stub_notification_platform_bridge.cc",
     "../browser/notifications/stub_notification_platform_bridge.h",
+    "../browser/password_manager/password_manager_test_util.cc",
+    "../browser/password_manager/password_manager_test_util.h",
     "../browser/permissions/crowd_deny_fake_safe_browsing_database_manager.cc",
     "../browser/permissions/crowd_deny_fake_safe_browsing_database_manager.h",
     "../browser/search_engines/template_url_service_factory_test_util.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java
index 98702d3..e31193f 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java
@@ -4,55 +4,13 @@
 
 package org.chromium.chrome.test;
 
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
-import org.chromium.chrome.browser.feed.FeedProcessScopeFactory;
-import org.chromium.chrome.browser.feed.TestNetworkClient;
 
 /**
- * Custom ActivityTestRule for test using ChromeTabbedActivity
+ * Custom ActivityTestRule for tests using ChromeTabbedActivity
  */
 public class ChromeTabbedActivityTestRule extends ChromeActivityTestRule<ChromeTabbedActivity> {
-    // Response file for Feed's network stub.
-    private static final String DEFAULT_FEED_TEST_RESPONSE_FILE_PATH =
-            "/chrome/test/data/android/feed/feed_large.gcl.bin";
-
-    private final String mFeedTestResponseFilePath;
-
     public ChromeTabbedActivityTestRule() {
-        this(DEFAULT_FEED_TEST_RESPONSE_FILE_PATH);
-    }
-
-    /**
-     * @param feedTestResponseFilePath The file path of the response that the feed library returns
-     *                                 in tests.
-     */
-    public ChromeTabbedActivityTestRule(String feedTestResponseFilePath) {
         super(ChromeTabbedActivity.class);
-        mFeedTestResponseFilePath = feedTestResponseFilePath;
-    }
-
-    @Override
-    public Statement apply(final Statement base, Description description) {
-        Statement tabbedActivityStatement = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                // Setup Feed stubs.
-                TestNetworkClient client = new TestNetworkClient();
-                client.setNetworkResponseFile(
-                        UrlUtils.getIsolatedTestFilePath(mFeedTestResponseFilePath));
-                FeedProcessScopeFactory.setTestNetworkClient(client);
-
-                base.evaluate();
-
-                // Teardown the network stubs for Feed if they've been setup.
-                FeedProcessScopeFactory.setTestNetworkClient(null);
-            }
-        };
-
-        return super.apply(tabbedActivityStatement, description);
     }
 }
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 02009bab5..f6e45a1 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -8199,5 +8199,14 @@
         "prefs": { "policy.dlp_rules_list": { "local_state": true } }
       }
     ]
+  },
+  "WebRtcAllowLegacyTLSProtocols": {
+    "os": ["win", "linux", "mac", "chromeos"],
+    "policy_pref_mapping_test": [
+      {
+        "policies": { "WebRtcAllowLegacyTLSProtocols": false },
+        "prefs": { "webrtc.allow_legacy_tls_protocols": {} }
+      }
+    ]
   }
 }
diff --git a/chrome/test/data/web_apps/query_params_in_start_url.html b/chrome/test/data/web_apps/query_params_in_start_url.html
new file mode 100644
index 0000000..df7ac91e
--- /dev/null
+++ b/chrome/test/data/web_apps/query_params_in_start_url.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <link rel="manifest" href="query_params_in_start_url.json">
+  <link rel="icon" href="basic-48.png">
+</head>
+<body>
+  <h1>Query params in start_url</h1>
+  <script>
+    navigator.serviceWorker.register('/web_apps/service_worker.js');
+  </script>
+</body>
+</html>
diff --git a/chrome/test/data/web_apps/query_params_in_start_url.json b/chrome/test/data/web_apps/query_params_in_start_url.json
new file mode 100644
index 0000000..cf2955d
--- /dev/null
+++ b/chrome/test/data/web_apps/query_params_in_start_url.json
@@ -0,0 +1,17 @@
+{
+  "name": "Query params in start_url",
+  "icons": [
+    {
+      "src": "basic-48.png",
+      "sizes": "48x48",
+      "type": "image/png"
+    },
+    {
+      "src": "basic-192.png",
+      "sizes": "192x192",
+      "type": "image/png"
+    }
+  ],
+  "start_url": "query_params_in_start_url.html?query_params=in&start=url",
+  "display": "standalone"
+}
diff --git a/chrome/test/data/webui/settings/passwords_device_section_test.js b/chrome/test/data/webui/settings/passwords_device_section_test.js
index 3411f49..bb424635 100644
--- a/chrome/test/data/webui/settings/passwords_device_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_device_section_test.js
@@ -5,7 +5,7 @@
 /** @fileoverview Runs the Polymer tests for the PasswordsDeviceSection page. */
 
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {MultiStorePasswordUiEntry, PasswordManagerImpl, PasswordManagerProxy, Router, routes, SyncBrowserProxyImpl} from 'chrome://settings/settings.js';
+import {MultiStorePasswordUiEntry, PasswordManagerImpl, Router, routes, SyncBrowserProxyImpl} from 'chrome://settings/settings.js';
 import {createMultiStorePasswordEntry, createPasswordEntry} from 'chrome://test/settings/passwords_and_autofill_fake_data.js';
 import {simulateStoredAccounts, simulateSyncStatus} from 'chrome://test/settings/sync_test_util.m.js';
 import {TestPasswordManagerProxy} from 'chrome://test/settings/test_password_manager_proxy.js';
diff --git a/chrome/test/data/webui/settings/passwords_section_test.js b/chrome/test/data/webui/settings/passwords_section_test.js
index 60bebf7..1a593ef2 100644
--- a/chrome/test/data/webui/settings/passwords_section_test.js
+++ b/chrome/test/data/webui/settings/passwords_section_test.js
@@ -8,15 +8,13 @@
 import {isChromeOS, webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {MultiStoreExceptionEntry, MultiStorePasswordUiEntry, PasswordManagerImpl, PasswordManagerProxy, ProfileInfoBrowserProxyImpl, Router, routes, SettingsPluralStringProxyImpl} from 'chrome://settings/settings.js';
+import {MultiStoreExceptionEntry, MultiStorePasswordUiEntry, PasswordManagerImpl, PasswordManagerProxy, Router, routes, SettingsPluralStringProxyImpl} from 'chrome://settings/settings.js';
 import {createExceptionEntry, createMultiStoreExceptionEntry, createMultiStorePasswordEntry, createPasswordEntry, makeCompromisedCredential, makePasswordCheckStatus, PasswordSectionElementFactory} from 'chrome://test/settings/passwords_and_autofill_fake_data.js';
 import {runCancelExportTest, runExportFlowErrorRetryTest, runExportFlowErrorTest, runExportFlowFastTest, runExportFlowSlowTest, runFireCloseEventAfterExportCompleteTest,runStartExportTest} from 'chrome://test/settings/passwords_export_test.js';
 import {getSyncAllPrefs, simulateStoredAccounts, simulateSyncStatus} from 'chrome://test/settings/sync_test_util.m.js';
 import {TestPasswordManagerProxy} from 'chrome://test/settings/test_password_manager_proxy.js';
-import {TestProfileInfoBrowserProxy} from 'chrome://test/settings/test_profile_info_browser_proxy.m.js';
 import {TestPluralStringProxy} from 'chrome://test/test_plural_string_proxy.js';
 import {eventToPromise} from 'chrome://test/test_util.m.js';
-
 // clang-format on
 
 const PasswordCheckState = chrome.passwordsPrivate.PasswordCheckState;
diff --git a/chrome/test/data/webui/signin/BUILD.gn b/chrome/test/data/webui/signin/BUILD.gn
index 09d855d..b80ad1d2 100644
--- a/chrome/test/data/webui/signin/BUILD.gn
+++ b/chrome/test/data/webui/signin/BUILD.gn
@@ -36,7 +36,7 @@
   deps = [
     "..:chai_assert",
     "..:test_util.m",
-    "//chrome/browser/resources/signin/profile_picker/profile_creation_flow:profile_type_choice",
+    "//chrome/browser/resources/signin/profile_picker:lazy_load",
   ]
 }
 
@@ -45,10 +45,7 @@
     ":test_manage_profiles_browser_proxy",
     "..:chai_assert",
     "..:test_util.m",
-    "//chrome/browser/resources/signin/profile_picker:navigation_behavior",
-    "//chrome/browser/resources/signin/profile_picker:profile_picker_app",
-    "//chrome/browser/resources/signin/profile_picker/profile_creation_flow:ensure_lazy_loaded",
-    "//chrome/browser/resources/signin/profile_picker/profile_creation_flow:local_profile_customization",
+    "//chrome/browser/resources/signin/profile_picker:profile_picker",
   ]
 }
 
@@ -62,6 +59,6 @@
 js_library("test_manage_profiles_browser_proxy") {
   deps = [
     "..:test_browser_proxy.m",
-    "//chrome/browser/resources/signin/profile_picker:manage_profiles_browser_proxy",
+    "//chrome/browser/resources/signin/profile_picker:profile_picker",
   ]
 }
diff --git a/chrome/test/data/webui/signin/profile_creation_flow_test.js b/chrome/test/data/webui/signin/profile_creation_flow_test.js
index 0663c21..a4a8f02 100644
--- a/chrome/test/data/webui/signin/profile_creation_flow_test.js
+++ b/chrome/test/data/webui/signin/profile_creation_flow_test.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://profile-picker/profile_creation_flow/profile_type_choice.js';
+import 'chrome://profile-picker/lazy_load.js';
 
 import {assertTrue} from '../chai_assert.js';
 import {isChildVisible} from '../test_util.m.js';
diff --git a/chrome/test/data/webui/signin/profile_picker_app_test.js b/chrome/test/data/webui/signin/profile_picker_app_test.js
index de5b0387..811eec7c 100644
--- a/chrome/test/data/webui/signin/profile_picker_app_test.js
+++ b/chrome/test/data/webui/signin/profile_picker_app_test.js
@@ -2,11 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://profile-picker/profile_picker_app.js';
-
-import {ManageProfilesBrowserProxyImpl} from 'chrome://profile-picker/manage_profiles_browser_proxy.js';
-import {navigateTo, Routes} from 'chrome://profile-picker/navigation_behavior.js';
-import {ensureLazyLoaded} from 'chrome://profile-picker/profile_creation_flow/ensure_lazy_loaded.js';
+import {ensureLazyLoaded, ManageProfilesBrowserProxyImpl, navigateTo, Routes} from 'chrome://profile-picker/profile_picker.js';
 
 import {assertTrue} from '../chai_assert.js';
 import {waitBeforeNextRender} from '../test_util.m.js';
diff --git a/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js b/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
index 3c6126b..adc1aa9 100644
--- a/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
+++ b/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {ManageProfilesBrowserProxy} from 'chrome://profile-picker/manage_profiles_browser_proxy.js';
+import {ManageProfilesBrowserProxy} from 'chrome://profile-picker/profile_picker.js';
 
 import {TestBrowserProxy} from '../test_browser_proxy.m.js';
 
diff --git a/chromeos/components/camera_app_ui/resources/css/main.css b/chromeos/components/camera_app_ui/resources/css/main.css
index 082b2c63..ef0de76 100644
--- a/chromeos/components/camera_app_ui/resources/css/main.css
+++ b/chromeos/components/camera_app_ui/resources/css/main.css
@@ -11,8 +11,11 @@
 }
 
 body {
+  --default-font-family: 'Google Sans', sans-serif;
+
   background: black;
   bottom: 0;
+  font-family: var(--default-font-family);
   height: 100%;
   left: 0;
   margin: 0;
@@ -269,7 +272,6 @@
   border-radius: 16px/50%;
   color: white;
   display: inline-block;
-  font-family: 'Roboto', sans-serif;
   font-size: 14px;
   font-weight: 500;
   line-height: 32px;
@@ -517,7 +519,6 @@
 
 #timer-tick-msg {
   color: white;
-  font-family: 'Roboto', sans-serif;
   font-size: 72px;
   visibility: hidden;
 }
@@ -825,7 +826,6 @@
 }
 
 #preview-metadata {
-  font-family: 'Roboto', sans-serif;
   font-size: 14px;
   left: 60px;
   position: absolute;
@@ -1024,7 +1024,6 @@
 #record-time [i18n-content=record_video_paused_msg] {
   color: white;
   flex-shrink: 0;
-  font-family: 'Roboto', sans-serif;
   font-size: 13px;
 }
 
@@ -1059,7 +1058,6 @@
   background: rgba(241, 243, 244, 0.8);
   border-radius: 2px;
   color: rgb(32, 33, 36);
-  font-family: 'Roboto', sans-serif;
   font-size: 12px;
   left: 0;
   line-height: 22px;
@@ -1081,7 +1079,6 @@
   background: rgb(30, 30, 35);
   border-radius: 16px;
   color: white;
-  font-family: 'Roboto', sans-serif;
   font-size: 16px;
   line-height: 32px;
   opacity: 0;
@@ -1158,13 +1155,13 @@
 }
 
 #banner-title-text {
-  font: 450 18px 'Google Sans', sans-serif;
+  font: 450 18px var(--default-font-family);
   vertical-align: middle;
 }
 
 #banner-msg {
   color: rgb(95, 99, 104);
-  font: 375 15px/22px 'Roboto';
+  font: 375 15px/22px var(--default-font-family);
 }
 
 #banner-close {
@@ -1199,7 +1196,6 @@
   color: rgb(241, 243, 244);
   display: flex;
   flex-shrink: 0;
-  font-family: 'Roboto', sans-serif;
   font-size: 13px;
   height: 64px;
   justify-content: flex-start;
@@ -1394,7 +1390,6 @@
 }
 
 #view-warning #error-msg {
-  font-family: 'Roboto', sans-serif;
   font-size: 18px;
   line-height: 32px;
   text-align: center;
@@ -1423,7 +1418,6 @@
 .dialog .dialog-msg {
   color: rgb(32, 33, 36);
   cursor: text;
-  font-family: 'Roboto', sans-serif;
   font-size: 14px;
   max-height: 320px;
   max-width: 472px;
@@ -1459,7 +1453,6 @@
   background-color: white;
   border-style: solid;
   color: rgb(37, 129, 223);
-  font-family: 'Roboto', sans-serif;
   font-size: 12px;
   margin: 4px;
   padding: 6px 18px;
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service.cc b/chromeos/components/telemetry_extension_ui/diagnostics_service.cc
index a95cb23..c79d92f 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service.cc
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service.cc
@@ -190,6 +190,22 @@
           std::move(callback)));
 }
 
+void DiagnosticsService::RunDiskReadRoutine(
+    health::mojom::DiskReadRoutineTypeEnum type,
+    uint32_t length_seconds,
+    uint32_t file_size_mb,
+    RunDiskReadRoutineCallback callback) {
+  GetService()->RunDiskReadRoutine(
+      converters::Convert(type), length_seconds, file_size_mb,
+      base::BindOnce(
+          [](health::mojom::DiagnosticsService::RunDiskReadRoutineCallback
+                 callback,
+             cros_healthd::mojom::RunRoutineResponsePtr ptr) {
+            std::move(callback).Run(converters::ConvertPtr(std::move(ptr)));
+          },
+          std::move(callback)));
+}
+
 void DiagnosticsService::RunPrimeSearchRoutine(
     uint32_t length_seconds,
     uint64_t max_num,
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service.h b/chromeos/components/telemetry_extension_ui/diagnostics_service.h
index 750fe33..381b470a 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service.h
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service.h
@@ -63,6 +63,10 @@
   void RunNvmeSelfTestRoutine(
       health::mojom::NvmeSelfTestTypeEnum nvme_self_test_type,
       RunNvmeSelfTestRoutineCallback callback) override;
+  void RunDiskReadRoutine(health::mojom::DiskReadRoutineTypeEnum type,
+                          uint32_t length_seconds,
+                          uint32_t file_size_mb,
+                          RunDiskReadRoutineCallback callback) override;
   void RunPrimeSearchRoutine(uint32_t length_seconds,
                              uint64_t max_num,
                              RunPrimeSearchRoutineCallback callback) override;
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.cc b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.cc
index d837e10..999a1a2 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.cc
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.cc
@@ -205,5 +205,20 @@
       1);
 }
 
+cros_healthd::mojom::DiskReadRoutineTypeEnum Convert(
+    health::mojom::DiskReadRoutineTypeEnum input) {
+  switch (input) {
+    case health::mojom::DiskReadRoutineTypeEnum::kLinearRead:
+      return cros_healthd::mojom::DiskReadRoutineTypeEnum::kLinearRead;
+    case health::mojom::DiskReadRoutineTypeEnum::kRandomRead:
+      return cros_healthd::mojom::DiskReadRoutineTypeEnum::kRandomRead;
+  }
+  NOTREACHED();
+  return static_cast<cros_healthd::mojom::DiskReadRoutineTypeEnum>(
+      static_cast<int>(
+          cros_healthd::mojom::DiskReadRoutineTypeEnum::kMaxValue) +
+      1);
+}
+
 }  // namespace converters
 }  // namespace chromeos
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h
index 14d1bd6..5a12bd3f 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h
@@ -63,6 +63,9 @@
 cros_healthd::mojom::NvmeSelfTestTypeEnum Convert(
     health::mojom::NvmeSelfTestTypeEnum input);
 
+cros_healthd::mojom::DiskReadRoutineTypeEnum Convert(
+    health::mojom::DiskReadRoutineTypeEnum input);
+
 }  // namespace converters
 }  // namespace chromeos
 
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters_unittest.cc b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters_unittest.cc
index 0150e5a..83985a9 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters_unittest.cc
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters_unittest.cc
@@ -86,5 +86,15 @@
             cros_healthd::NvmeSelfTestTypeEnum::kLongSelfTest);
 }
 
+TEST(DiagnosticsServiceConvertersTest, ConvertDiskReadRoutineTypeEnum) {
+  namespace cros_healthd = ::chromeos::cros_healthd::mojom;
+  namespace health = ::chromeos::health::mojom;
+
+  EXPECT_EQ(Convert(health::DiskReadRoutineTypeEnum::kLinearRead),
+            cros_healthd::DiskReadRoutineTypeEnum::kLinearRead);
+  EXPECT_EQ(Convert(health::DiskReadRoutineTypeEnum::kRandomRead),
+            cros_healthd::DiskReadRoutineTypeEnum::kRandomRead);
+}
+
 }  // namespace converters
 }  // namespace chromeos
diff --git a/chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom b/chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom
index 8f8d4c9..759a5bd6 100644
--- a/chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom
+++ b/chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom
@@ -184,6 +184,28 @@
   RunNvmeSelfTestRoutine(NvmeSelfTestTypeEnum nvme_self_test_type)
       => (RunRoutineResponse response);
 
+  // Requests that the DiskRead routine is created and started on the platform.
+  // The routine will create a test file with md5 checksum, read the test file
+  // either randomly or linearly, repeatedly for a dedicated duration. If the
+  // md5 checksum of read back is validated, then the test will pass.
+  // This routine is only available if GetAvailableRoutines returned kDiskRead.
+  //
+  // The request:
+  // * |type| - type of how disk reading is performed, either linear or random.
+  //
+  // * |length_seconds| - length of time, in seconds, to run the DiskRead
+  //                      routine for. This parameter needs to be strictly
+  //                      greater than zero.
+  //                    - TODO(b:167963397) - limit routine duration.
+  // * |file_size_mb| - test file size, in mega bytes, to test with DiskRead
+  //                    routine. Maximum file size is 10 GB.
+  // The response:
+  // * |response| - contains a unique identifier and status for the created
+  //                routine.
+  RunDiskReadRoutine(DiskReadRoutineTypeEnum type, uint32 length_seconds,
+                     uint32 file_size_mb)
+      => (RunRoutineResponse response);
+
   // Requests that the PrimeSearch routine is created and started on the
   // platform. Calculate prime numbers between 2 to max_num and verify the
   // calculation repeatedly in a duration. This routine is only available
@@ -355,3 +377,9 @@
   kShortSelfTest = 0, // Short time self-test.
   kLongSelfTest = 1,  // Long time self-test.
 };
+
+// Enumeration of the possible DiskRead routine's command type
+enum DiskReadRoutineTypeEnum {
+  kLinearRead,
+  kRandomRead,
+};
diff --git a/chromeos/components/telemetry_extension_ui/resources/message_types.js b/chromeos/components/telemetry_extension_ui/resources/message_types.js
index bb51f8a7..153b19a 100644
--- a/chromeos/components/telemetry_extension_ui/resources/message_types.js
+++ b/chromeos/components/telemetry_extension_ui/resources/message_types.js
@@ -35,6 +35,7 @@
       'DiagnosticsService.RunNvmeWearLevelRoutine',
   DIAGNOSTICS_RUN_NVME_SELF_TEST_ROUTINE:
       'DiagnosticsService.RunNvmeSelfTestRoutine',
+  DIAGNOSTICS_RUN_DISK_READ_ROUTINE: 'DiagnosticsService.RunDiskReadRoutine',
   DIAGNOSTICS_RUN_PRIME_SEARCH_ROUTINE:
       'DiagnosticsService.RunPrimeSearchRoutine',
   DIAGNOSTICS_RUN_BATTERY_DISCHARGE_ROUTINE:
@@ -146,6 +147,16 @@
 
 /**
  * Request message sent by the unprivileged context to the privileged
+ * context to run disk read routine.
+ * @typedef {{
+ * type: !string,
+ * lengthSeconds: !number,
+ * fileSizeMb: !number}}
+ */
+dpsl_internal.DiagnosticsRunDiskReadRoutineRequest;
+
+/**
+ * Request message sent by the unprivileged context to the privileged
  * context to run prime search routine.
  * @typedef {{
  * lengthSeconds: !number,
diff --git a/chromeos/components/telemetry_extension_ui/resources/trusted.js b/chromeos/components/telemetry_extension_ui/resources/trusted.js
index d4f3cad..b2837e00d 100644
--- a/chromeos/components/telemetry_extension_ui/resources/trusted.js
+++ b/chromeos/components/telemetry_extension_ui/resources/trusted.js
@@ -162,6 +162,24 @@
       throw RangeError(
           'nvmeSelfTestTypeToEnum_ does not contain all items from enum!');
     }
+
+    const diskReadRoutineTypeEnum =
+        chromeos.health.mojom.DiskReadRoutineTypeEnum;
+
+    /**
+     * @type { !Map<!string, !chromeos.health.mojom.DiskReadRoutineTypeEnum> }
+     * @const
+     */
+    this.diskReadRoutineTypeToEnum_ = new Map([
+      ['linear-read', diskReadRoutineTypeEnum.kLinearRead],
+      ['random-read', diskReadRoutineTypeEnum.kRandomRead],
+    ]);
+
+    if (this.diskReadRoutineTypeToEnum_.size !==
+        diskReadRoutineTypeEnum.MAX_VALUE + 1) {
+      throw RangeError(
+          'diskReadRoutineTypeToEnum_ does not contain all items from enum!');
+    }
   }
 
   /**
@@ -478,6 +496,48 @@
   };
 
   /**
+   * Converts disk read type string to DiskReadRoutineTypeEnum.
+   * @param { !string } type
+   * @return { !chromeos.health.mojom.DiskReadRoutineTypeEnum }
+   */
+  convertDiskReadTypeToEnum(type) {
+    if (!this.diskReadRoutineTypeToEnum_.has(type)) {
+      throw TypeError(`Diagnostic disk read type '${type}' is unknown.`);
+    }
+
+    return this.diskReadRoutineTypeToEnum_.get(type);
+  }
+
+  /**
+   * Throws an error if fileSizeMb exceeds maxSizeMb.
+   * @param { !number } fileSizeMb
+   * @param { !number } maxSizeMb
+   */
+  assertFileSizeLargerThan(fileSizeMb, maxSizeMb) {
+    if (fileSizeMb > maxSizeMb) {
+      throw RangeError(
+          `Diagnostic disk read routine does not allow file sizes greater ` +
+          `than '${maxSizeMb}'.`);
+    }
+  }
+
+  /**
+   * Runs disk read routine.
+   * @param { !Object } message
+   * @return { !RunRoutineResponsePromise }
+   */
+  async handleRunDiskReadRoutine(message) {
+    const request =
+        /** @type {!dpsl_internal.DiagnosticsRunDiskReadRoutineRequest} */
+        (message);
+    this.assertNumberIsPositive(request.lengthSeconds);
+    this.assertFileSizeLargerThan(request.fileSizeMb, 10 * 1000);
+    return await getOrCreateDiagnosticsService().runDiskReadRoutine(
+        this.convertDiskReadTypeToEnum(request.type), request.lengthSeconds,
+        request.fileSizeMb);
+  };
+
+  /**
    * Runs prime search routine.
    * @param { !Object } message
    * @return { !RunRoutineResponsePromise }
@@ -857,6 +917,12 @@
         message));
 
 untrustedMessagePipe.registerHandler(
+    dpsl_internal.Message.DIAGNOSTICS_RUN_DISK_READ_ROUTINE,
+    (message) => diagnosticsProxy.genericRunRoutineHandler(
+        (message) => diagnosticsProxy.handleRunDiskReadRoutine(message),
+        message));
+
+untrustedMessagePipe.registerHandler(
     dpsl_internal.Message.DIAGNOSTICS_RUN_PRIME_SEARCH_ROUTINE,
     (message) => diagnosticsProxy.genericRunRoutineHandler(
         (message) => diagnosticsProxy.handleRunPrimeSearchRoutine(message),
diff --git a/chromeos/components/telemetry_extension_ui/resources/untrusted.js b/chromeos/components/telemetry_extension_ui/resources/untrusted.js
index 42de8883..e77f3db 100644
--- a/chromeos/components/telemetry_extension_ui/resources/untrusted.js
+++ b/chromeos/components/telemetry_extension_ui/resources/untrusted.js
@@ -268,6 +268,30 @@
     }
 
     /**
+     * Requests disk read routine to be run.
+     * @param { !string } type
+     * @param { !number } lengthSeconds
+     * @param { !number } fileSizeMb
+     * @return { !Promise<!Object> }
+     * @public
+     */
+    async runDiskReadRoutine(type, lengthSeconds, fileSizeMb) {
+      const message =
+          /**
+             @type {!dpsl_internal.DiagnosticsRunDiskReadRoutineRequest}
+           */
+          ({type: type, lengthSeconds: lengthSeconds, fileSizeMb: fileSizeMb});
+      const response =
+          /** @type {!Object} */ (await messagePipe.sendMessage(
+              dpsl_internal.Message.DIAGNOSTICS_RUN_DISK_READ_ROUTINE,
+              message));
+      if (response instanceof Error) {
+        throw response;
+      }
+      return response;
+    }
+
+    /**
      * Requests prime search routine to be run.
      * @param { !number } lengthSeconds
      * @param { !number } maximumNumber
diff --git a/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js b/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js
index 4944cbc..afba56c2 100644
--- a/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js
+++ b/chromeos/components/telemetry_extension_ui/test/telemetry_extension_ui_browsertest.js
@@ -133,6 +133,15 @@
       diagnosticsProxy.convertNvmeSelfTestTypeToEnum('long-self-test'),
       nvmeSelfTestTypeEnum.kLongSelfTest);
 
+  // Unit tests for convertDiskReadTypeToEnum
+  const diskReadRoutineTypeEnum = chromeos.health.mojom.DiskReadRoutineTypeEnum;
+  assertEquals(
+      diagnosticsProxy.convertDiskReadTypeToEnum('linear-read'),
+      diskReadRoutineTypeEnum.kLinearRead);
+  assertEquals(
+      diagnosticsProxy.convertDiskReadTypeToEnum('random-read'),
+      diskReadRoutineTypeEnum.kRandomRead);
+
   testDone();
 });
 
@@ -391,6 +400,8 @@
   ['UntrustedDiagnosticsRequestRunNvmeWearLevelRoutine'],
   ['UntrustedDiagnosticsRequestRunNvmeSelfTestRoutineInvalidInput'],
   ['UntrustedDiagnosticsRequestRunNvmeSelfTestRoutine'],
+  ['UntrustedDiagnosticsRequestRunDiskReadRoutineInvalidInput'],
+  ['UntrustedDiagnosticsRequestRunDiskReadRoutine'],
   ['UntrustedDiagnosticsRequestRunPrimeSearchRoutineInvalidInput'],
   ['UntrustedDiagnosticsRequestRunPrimeSearchRoutine'],
   ['UntrustedDiagnosticsRequestRunBatteryDischargeRoutineInvalidInput'],
diff --git a/chromeos/components/telemetry_extension_ui/test/untrusted_browsertest.js b/chromeos/components/telemetry_extension_ui/test/untrusted_browsertest.js
index fa22efe..d9a5512d 100644
--- a/chromeos/components/telemetry_extension_ui/test/untrusted_browsertest.js
+++ b/chromeos/components/telemetry_extension_ui/test/untrusted_browsertest.js
@@ -279,6 +279,66 @@
       assertDeepEquals(response2, {id: 123456789, status: 'ready'});
     });
 
+// Tests that runDiskReadRoutine throws the correct error when invalid enum
+// is passed as input.
+UNTRUSTED_TEST(
+    'UntrustedDiagnosticsRequestRunDiskReadRoutineInvalidInput', async () => {
+      let caughtError1;
+      try {
+        await chromeos.diagnostics.runDiskReadRoutine(
+            'this-does-not-exist', 10, 10);
+      } catch (error) {
+        caughtError1 = error;
+      }
+
+      assertEquals(caughtError1.name, 'TypeError');
+      assertEquals(
+          caughtError1.message,
+          `Diagnostic disk read type \'this-does-not-exist\' is unknown.`);
+
+      let caughtError2;
+      try {
+        await chromeos.diagnostics.runDiskReadRoutine('linear-read', 0, 10);
+      } catch (error) {
+        caughtError2 = error;
+      }
+      let caughtError3;
+      try {
+        await chromeos.diagnostics.runDiskReadRoutine(
+            'random-read', -2147483648, 10);
+      } catch (error) {
+        caughtError3 = error;
+      }
+
+      assertEquals(caughtError3.name, 'RangeError');
+      assertEquals(caughtError3.message, `Parameter must be positive.`);
+
+      let caughtError4;
+      try {
+        await chromeos.diagnostics.runDiskReadRoutine(
+            'random-read', 10, 987654321);
+      } catch (error) {
+        caughtError4 = error;
+      }
+
+      assertEquals(caughtError4.name, 'RangeError');
+      assertEquals(
+          caughtError4.message,
+          `Diagnostic disk read routine does not allow file sizes greater ` +
+              `than '10000'.`);
+    });
+
+// Tests that runDiskReadRoutine returns the correct Object.
+UNTRUSTED_TEST('UntrustedDiagnosticsRequestRunDiskReadRoutine', async () => {
+  const response1 =
+      await chromeos.diagnostics.runDiskReadRoutine('linear-read', 12, 20);
+  assertDeepEquals(response1, {id: 123456789, status: 'ready'});
+
+  const response2 =
+      await chromeos.diagnostics.runDiskReadRoutine('random-read', 20, 10);
+  assertDeepEquals(response2, {id: 123456789, status: 'ready'});
+});
+
 // Tests that runPrimeSearchRoutine throws the correct error when invalid enum
 // is passed as input.
 UNTRUSTED_TEST(
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom
index f1a6557..22f2efd 100644
--- a/chromeos/crosapi/mojom/crosapi.mojom
+++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -62,6 +62,14 @@
   [MinVersion=3] OnLacrosStartup@6(LacrosInfo lacros_info);
 };
 
+[Stable, Extensible]
+enum SessionType {
+  kUnknown,
+  kRegularSession,
+  kGuestSession,
+  kPublicSession
+};
+
 // LacrosInitParams is a set of parameters for initialization of lacros-chrome,
 // which is passed from ash-chrome to lacros-chrome. Since ash-chrome and
 // lacros-chrome may have different versions, lacros-chrome must handle this
@@ -96,6 +104,10 @@
   // consent via settings.
   [MinVersion=2]
   bool ash_metrics_enabled@2;
+
+  // Type of the ash-chrome session.
+  [MinVersion=3]
+  SessionType session_type@3;
 };
 
 // LacrosChromeService defines the APIs that live in lacros-chrome and
diff --git a/components/arc/clipboard/arc_clipboard_bridge.cc b/components/arc/clipboard/arc_clipboard_bridge.cc
index 9c01aa2..860b420 100644
--- a/components/arc/clipboard/arc_clipboard_bridge.cc
+++ b/components/arc/clipboard/arc_clipboard_bridge.cc
@@ -49,7 +49,7 @@
   // Unused. URL is sent from CreatePlainText() by reading it from the Bookmark.
   std::string url;
   uint32_t fragment_start, fragment_end;
-  const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kGuestOs);
+  const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kArc);
 
   clipboard->ReadHTML(ui::ClipboardBuffer::kCopyPaste, &data_dst, &markup16,
                       &url, &fragment_start, &fragment_end);
@@ -71,7 +71,7 @@
   base::string16 title;
   std::string text;
   std::string mime_type(ui::kMimeTypeText);
-  const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kGuestOs);
+  const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kArc);
 
   // Both Bookmark and AsciiText are represented by text/plain. If both are
   // present, only use Bookmark.
@@ -87,7 +87,7 @@
   DCHECK(clipboard);
 
   std::vector<base::string16> mime_types;
-  const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kGuestOs);
+  const ui::ClipboardDataEndpoint data_dst(ui::EndpointType::kArc);
   clipboard->ReadAvailableTypes(ui::ClipboardBuffer::kCopyPaste, &data_dst,
                                 &mime_types);
 
@@ -178,7 +178,7 @@
   base::AutoReset<bool> auto_reset(&event_originated_at_instance_, true);
   ui::ScopedClipboardWriter writer(
       ui::ClipboardBuffer::kCopyPaste,
-      std::make_unique<ui::ClipboardDataEndpoint>(ui::EndpointType::kGuestOs));
+      std::make_unique<ui::ClipboardDataEndpoint>(ui::EndpointType::kArc));
 
   for (const auto& repr : clip_data->representations) {
     const std::string& mime_type(repr->mime_type);
diff --git a/components/autofill/core/browser/form_parsing/form_field.cc b/components/autofill/core/browser/form_parsing/form_field.cc
index 474a952..cafb28d 100644
--- a/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/components/autofill/core/browser/form_parsing/form_field.cc
@@ -11,6 +11,7 @@
 #include <string>
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -159,6 +160,13 @@
   return ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT, match, logging);
 }
 
+bool FormField::ParseField(AutofillScanner* scanner,
+                           const std::vector<MatchingPattern>& patterns,
+                           AutofillField** match,
+                           const RegExLogging& logging) {
+  return ParseFieldSpecifics(scanner, patterns, match, logging);
+}
+
 bool FormField::ParseFieldSpecifics(AutofillScanner* scanner,
                                     const base::string16& pattern,
                                     int match_field_attributes,
@@ -178,6 +186,43 @@
                          match_field_input_types, match, logging);
 }
 
+bool FormField::ParseFieldSpecifics(
+    AutofillScanner* scanner,
+    const std::vector<MatchingPattern>& patterns,
+    AutofillField** match,
+    const RegExLogging& logging) {
+  if (scanner->IsEnd())
+    return false;
+
+  const AutofillField* field = scanner->Cursor();
+
+  for (const auto& pattern : patterns) {
+    if (!MatchesFormControlType(field->form_control_type,
+                                pattern.match_field_input_types)) {
+      continue;
+    }
+
+    // TODO(crbug.com/1132831): Remove feature check once launched.
+    if (base::FeatureList::IsEnabled(
+            features::
+                kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+      if (FormField::Match(field, base::UTF8ToUTF16(pattern.negative_pattern),
+                           pattern.match_field_attributes,
+                           pattern.match_field_input_types, logging)) {
+        continue;
+      }
+    }
+
+    if (MatchAndAdvance(scanner, base::UTF8ToUTF16(pattern.positive_pattern),
+                        pattern.match_field_attributes,
+                        pattern.match_field_input_types, match, logging)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 // static
 bool FormField::ParseFieldSpecifics(AutofillScanner* scanner,
                                     const base::string16& pattern,
diff --git a/components/autofill/core/browser/form_parsing/form_field.h b/components/autofill/core/browser/form_parsing/form_field.h
index 5e024f6..b4e66505 100644
--- a/components/autofill/core/browser/form_parsing/form_field.h
+++ b/components/autofill/core/browser/form_parsing/form_field.h
@@ -66,6 +66,11 @@
                          AutofillField** match,
                          const RegExLogging& logging = {});
 
+  static bool ParseField(AutofillScanner* scanner,
+                         const std::vector<MatchingPattern>& patterns,
+                         AutofillField** match,
+                         const RegExLogging& logging = {});
+
   // Parses the stream of fields in |scanner| with regular expression |pattern|
   // as specified in the |match_type| bit field (see |MatchType|).  If |match|
   // is non-NULL and the pattern matches, |match| will be set to the matched
@@ -77,6 +82,11 @@
                                   AutofillField** match,
                                   const RegExLogging& logging = {});
 
+  static bool ParseFieldSpecifics(AutofillScanner* scanner,
+                                  const std::vector<MatchingPattern>& patterns,
+                                  AutofillField** match,
+                                  const RegExLogging& logging = {});
+
   // The same as ParseFieldSpecifics but with splitted match_types into
   // MatchAttributes and MatchFieldTypes.
   static bool ParseFieldSpecifics(AutofillScanner* scanner,
diff --git a/components/autofill/core/browser/pattern_provider/pattern_provider.h b/components/autofill/core/browser/pattern_provider/pattern_provider.h
index 78563b53..2cb7422 100644
--- a/components/autofill/core/browser/pattern_provider/pattern_provider.h
+++ b/components/autofill/core/browser/pattern_provider/pattern_provider.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "base/no_destructor.h"
-#include "base/synchronization/lock.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
 #include "components/autofill/core/common/autofill_regex_constants.h"
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index a90f58fe..50444cf 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -48,6 +48,13 @@
 const base::Feature kAutofillAlwaysFillAddresses{
     "AlwaysFillAddresses", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Controls whether negative patterns are used to parse the field type.
+// TODO(crbug.com/1132831): Remove once launched.
+const base::Feature
+    kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics{
+        "AutofillApplyNegativePatternsForFieldTypeDetectionHeuristics",
+        base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls the use of GET (instead of POST) to fetch cacheable autofill query
 // responses.
 const base::Feature kAutofillCacheQueryResponses{
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 82f5615..1bbf2397 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -26,6 +26,8 @@
 extern const base::Feature kAutofillAllowHtmlTypeCountryCodesWithFullNames;
 extern const base::Feature kAutofillAllowNonHttpActivation;
 extern const base::Feature kAutofillAlwaysFillAddresses;
+extern const base::Feature
+    kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics;
 extern const base::Feature kAutofillCacheQueryResponses;
 extern const base::Feature kAutofillCreateDataForTest;
 extern const base::Feature kAutofillEnableAccountWalletStorage;
diff --git a/components/autofill_assistant/browser/actions/select_option_action.cc b/components/autofill_assistant/browser/actions/select_option_action.cc
index 0f659d06..2a4fdfb0 100644
--- a/components/autofill_assistant/browser/actions/select_option_action.cc
+++ b/components/autofill_assistant/browser/actions/select_option_action.cc
@@ -8,9 +8,11 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill_assistant/browser/actions/action_delegate.h"
 #include "components/autofill_assistant/browser/actions/action_delegate_util.h"
 #include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/field_formatter.h"
 
 namespace autofill_assistant {
 
@@ -23,50 +25,86 @@
 SelectOptionAction::~SelectOptionAction() {}
 
 void SelectOptionAction::InternalProcessAction(ProcessActionCallback callback) {
+  process_action_callback_ = std::move(callback);
   const SelectOptionProto& select_option = proto_.select_option();
 
-  // A non prefilled |select_option| is not supported.
-  if (!select_option.has_selected_option()) {
-    VLOG(1) << __func__ << ": empty option";
-    UpdateProcessedAction(INVALID_ACTION);
-    std::move(callback).Run(std::move(processed_action_proto_));
-    return;
-  }
   Selector selector = Selector(select_option.element());
   if (selector.empty()) {
     VLOG(1) << __func__ << ": empty selector";
-    UpdateProcessedAction(INVALID_SELECTOR);
-    std::move(callback).Run(std::move(processed_action_proto_));
+    EndAction(ClientStatus(INVALID_SELECTOR));
     return;
   }
+
+  switch (select_option.value_case()) {
+    case SelectOptionProto::kSelectedOption:
+      if (select_option.selected_option().empty()) {
+        VLOG(1) << __func__ << ": empty |selected_option|";
+        EndAction(ClientStatus(INVALID_ACTION));
+        return;
+      }
+
+      value_ = select_option.selected_option();
+      break;
+    case SelectOptionProto::kAutofillValue: {
+      if (select_option.autofill_value().profile().identifier().empty() ||
+          select_option.autofill_value().value_expression().empty()) {
+        VLOG(1) << "SelectOptionAction: |autofill_value| with empty "
+                   "|profile.identifier| or |value_expression|";
+        EndAction(ClientStatus(INVALID_ACTION));
+        return;
+      }
+
+      const autofill::AutofillProfile* address =
+          delegate_->GetUserData()->selected_address(
+              select_option.autofill_value().profile().identifier());
+      if (address == nullptr) {
+        VLOG(1) << "SelectOptionAction: requested unknown address '"
+                << select_option.autofill_value().profile().identifier() << "'";
+        EndAction(ClientStatus(PRECONDITION_FAILED));
+        return;
+      }
+
+      auto value = field_formatter::FormatString(
+          select_option.autofill_value().value_expression(),
+          field_formatter::CreateAutofillMappings(*address,
+                                                  /* locale= */ "en-US"));
+      if (!value.has_value()) {
+        EndAction(ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE));
+        return;
+      }
+
+      value_ = *value;
+      break;
+    }
+    default:
+      VLOG(1) << "Unrecognized field for SelectOptionAction";
+      EndAction(ClientStatus(INVALID_ACTION));
+      return;
+  }
+
   delegate_->ShortWaitForElement(
       selector, base::BindOnce(&SelectOptionAction::OnWaitForElement,
-                               weak_ptr_factory_.GetWeakPtr(),
-                               std::move(callback), selector));
+                               weak_ptr_factory_.GetWeakPtr(), selector));
 }
 
-void SelectOptionAction::OnWaitForElement(ProcessActionCallback callback,
-                                          const Selector& selector,
+void SelectOptionAction::OnWaitForElement(const Selector& selector,
                                           const ClientStatus& element_status) {
   if (!element_status.ok()) {
-    UpdateProcessedAction(element_status.proto_status());
-    std::move(callback).Run(std::move(processed_action_proto_));
+    EndAction(element_status);
     return;
   }
 
   ActionDelegateUtil::FindElementAndPerform(
       delegate_, selector,
       base::BindOnce(&ActionDelegate::SelectOption, delegate_->GetWeakPtr(),
-                     proto_.select_option().selected_option(),
-                     proto_.select_option().select_strategy()),
-      base::BindOnce(&SelectOptionAction::OnSelectOption,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+                     value_, proto_.select_option().select_strategy()),
+      base::BindOnce(&SelectOptionAction::EndAction,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
-void SelectOptionAction::OnSelectOption(ProcessActionCallback callback,
-                                        const ClientStatus& status) {
+void SelectOptionAction::EndAction(const ClientStatus& status) {
   UpdateProcessedAction(status);
-  std::move(callback).Run(std::move(processed_action_proto_));
+  std::move(process_action_callback_).Run(std::move(processed_action_proto_));
 }
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/select_option_action.h b/components/autofill_assistant/browser/actions/select_option_action.h
index d178b195..e47160d 100644
--- a/components/autofill_assistant/browser/actions/select_option_action.h
+++ b/components/autofill_assistant/browser/actions/select_option_action.h
@@ -28,11 +28,13 @@
   // Overrides Action:
   void InternalProcessAction(ProcessActionCallback callback) override;
 
-  void OnWaitForElement(ProcessActionCallback callback,
-                        const Selector& selector,
+  void OnWaitForElement(const Selector& selector,
                         const ClientStatus& element_status);
-  void OnSelectOption(ProcessActionCallback callback,
-                      const ClientStatus& status);
+
+  void EndAction(const ClientStatus& status);
+
+  std::string value_;
+  ProcessActionCallback process_action_callback_;
 
   base::WeakPtrFactory<SelectOptionAction> weak_ptr_factory_{this};
 
diff --git a/components/autofill_assistant/browser/actions/select_option_action_unittest.cc b/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
index 0380902..3470225b 100644
--- a/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/select_option_action_unittest.cc
@@ -4,8 +4,14 @@
 
 #include "components/autofill_assistant/browser/actions/select_option_action.h"
 
+#include "base/guid.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "components/autofill_assistant/browser/actions/action_test_utils.h"
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
 #include "components/autofill_assistant/browser/selector.h"
@@ -20,6 +26,7 @@
 using ::testing::InSequence;
 using ::testing::Pointee;
 using ::testing::Property;
+using ::testing::Return;
 
 class SelectOptionActionTest : public testing::Test {
  public:
@@ -29,6 +36,9 @@
 
  protected:
   void Run() {
+    ON_CALL(mock_action_delegate_, GetUserData)
+        .WillByDefault(Return(&user_data_));
+
     ActionProto action_proto;
     *action_proto.mutable_select_option() = proto_;
     SelectOptionAction action(&mock_action_delegate_, action_proto);
@@ -38,9 +48,10 @@
   MockActionDelegate mock_action_delegate_;
   base::MockCallback<Action::ProcessActionCallback> callback_;
   SelectOptionProto proto_;
+  UserData user_data_;
 };
 
-TEST_F(SelectOptionActionTest, EmptyOptionFails) {
+TEST_F(SelectOptionActionTest, NoValueToSelectFails) {
   Selector selector({"#select"});
   *proto_.mutable_element() = selector.proto;
   EXPECT_CALL(
@@ -49,6 +60,26 @@
   Run();
 }
 
+TEST_F(SelectOptionActionTest, EmptySelectedOptionFails) {
+  Selector selector({"#select"});
+  *proto_.mutable_element() = selector.proto;
+  proto_.set_selected_option("");
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
+  Run();
+}
+
+TEST_F(SelectOptionActionTest, EmptyAutofillValueFails) {
+  Selector selector({"#select"});
+  *proto_.mutable_element() = selector.proto;
+  proto_.mutable_autofill_value();
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
+  Run();
+}
+
 TEST_F(SelectOptionActionTest, EmptySelectorFails) {
   proto_.set_selected_option("option");
   EXPECT_CALL(
@@ -82,5 +113,77 @@
   Run();
 }
 
+TEST_F(SelectOptionActionTest, RequestDataFromUnknownProfile) {
+  Selector selector({"#select"});
+  *proto_.mutable_element() = selector.proto;
+  auto* value = proto_.mutable_autofill_value();
+  value->mutable_profile()->set_identifier("none");
+  value->set_value_expression("value");
+  EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+                                              PRECONDITION_FAILED))));
+  Run();
+}
+
+TEST_F(SelectOptionActionTest, RequestUnknownDataFromProfile) {
+  autofill::AutofillProfile contact(base::GenerateGUID(),
+                                    autofill::test::kEmptyOrigin);
+  // Middle name is expected to be empty.
+  autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
+                                 "", "", "", "", "", "", "", "", "");
+  user_data_.selected_addresses_["contact"] =
+      std::make_unique<autofill::AutofillProfile>(contact);
+
+  Selector selector({"#select"});
+  *proto_.mutable_element() = selector.proto;
+  auto* value = proto_.mutable_autofill_value();
+  value->mutable_profile()->set_identifier("contact");
+  value->set_value_expression(
+      base::StrCat({"${",
+                    base::NumberToString(static_cast<int>(
+                        autofill::ServerFieldType::NAME_MIDDLE)),
+                    "}"}));
+
+  EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+                                              AUTOFILL_INFO_NOT_AVAILABLE))));
+  Run();
+}
+
+TEST_F(SelectOptionActionTest, SelectOptionFromProfileValue) {
+  autofill::AutofillProfile contact(base::GenerateGUID(),
+                                    autofill::test::kEmptyOrigin);
+  autofill::test::SetProfileInfo(&contact, "John", "", "Doe", "", "", "", "",
+                                 "", "", "", "", "");
+  user_data_.selected_addresses_["contact"] =
+      std::make_unique<autofill::AutofillProfile>(contact);
+
+  InSequence sequence;
+
+  Selector selector({"#select"});
+  *proto_.mutable_element() = selector.proto;
+  auto* value = proto_.mutable_autofill_value();
+  value->mutable_profile()->set_identifier("contact");
+  value->set_value_expression(
+      base::StrCat({"${",
+                    base::NumberToString(static_cast<int>(
+                        autofill::ServerFieldType::NAME_FIRST)),
+                    "}"}));
+
+  Selector expected_selector = selector;
+  EXPECT_CALL(mock_action_delegate_,
+              OnShortWaitForElement(expected_selector, _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus()));
+  EXPECT_CALL(mock_action_delegate_,
+              SelectOption("John", _,
+                           EqualsElement(test_util::MockFindElement(
+                               mock_action_delegate_, expected_selector)),
+                           _))
+      .WillOnce(RunOnceCallback<3>(OkClientStatus()));
+
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+  Run();
+}
+
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action.cc b/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
index 595b5c8..92d47a8 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
@@ -8,9 +8,11 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill_assistant/browser/actions/action_delegate.h"
 #include "components/autofill_assistant/browser/actions/action_delegate_util.h"
 #include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/field_formatter.h"
 
 namespace autofill_assistant {
 namespace {
@@ -57,6 +59,7 @@
   }
 
   // Check proto fields.
+  int keypress_index = 0;
   for (const auto& keypress : proto_.set_form_value().value()) {
     switch (keypress.keypress_case()) {
       case SetFormFieldValueProto_KeyPress::kKeycode:
@@ -68,7 +71,7 @@
           VLOG(1) << "SetFormFieldValueAction: field `keycode' is deprecated "
                   << "and only supports US-ASCII values (encountered value > "
                      "127). Use field `key' instead.";
-          EndAction(ClientStatus(INVALID_ACTION));
+          FailAction(ClientStatus(INVALID_ACTION), keypress_index);
           return;
         }
         field_inputs_.emplace_back(
@@ -79,7 +82,7 @@
         if (keypress.keyboard_input().empty()) {
           VLOG(1) << "SetFormFieldValueAction: field 'keyboard_input' must be "
                      "non-empty if set.";
-          EndAction(ClientStatus(INVALID_ACTION));
+          FailAction(ClientStatus(INVALID_ACTION), keypress_index);
           return;
         }
         field_inputs_.emplace_back(
@@ -93,7 +96,7 @@
         if (!delegate_->GetUserData()->selected_login_.has_value()) {
           VLOG(1) << "SetFormFieldValueAction: requested login details not "
                      "available in client memory.";
-          EndAction(ClientStatus(PRECONDITION_FAILED));
+          FailAction(ClientStatus(PRECONDITION_FAILED), keypress_index);
           return;
         }
         if (keypress.keypress_case() ==
@@ -112,7 +115,7 @@
       case SetFormFieldValueProto_KeyPress::kClientMemoryKey:
         if (keypress.client_memory_key().empty()) {
           VLOG(1) << "SetFormFieldValueAction: empty |client_memory_key|";
-          EndAction(ClientStatus(INVALID_ACTION));
+          FailAction(ClientStatus(INVALID_ACTION), keypress_index);
           return;
         }
         if (!delegate_->GetUserData()->has_additional_value(
@@ -125,7 +128,7 @@
           VLOG(1) << "SetFormFieldValueAction: requested key '"
                   << keypress.client_memory_key()
                   << "' not available in client memory";
-          EndAction(ClientStatus(PRECONDITION_FAILED));
+          FailAction(ClientStatus(PRECONDITION_FAILED), keypress_index);
           return;
         }
         field_inputs_.emplace_back(
@@ -134,11 +137,43 @@
                 ->strings()
                 .values(0));
         break;
+      case SetFormFieldValueProto_KeyPress::kAutofillValue: {
+        if (keypress.autofill_value().profile().identifier().empty() ||
+            keypress.autofill_value().value_expression().empty()) {
+          VLOG(1) << "SetFormFieldValueAction: |autofill_value| with empty "
+                     "|profile.identifier| or |value_expression|";
+          FailAction(ClientStatus(INVALID_ACTION), keypress_index);
+          return;
+        }
+
+        const autofill::AutofillProfile* address =
+            delegate_->GetUserData()->selected_address(
+                keypress.autofill_value().profile().identifier());
+        if (address == nullptr) {
+          VLOG(1) << "SetFormFieldValueAction: requested unknown address '"
+                  << keypress.autofill_value().profile().identifier() << "'";
+          FailAction(ClientStatus(PRECONDITION_FAILED), keypress_index);
+          return;
+        }
+
+        auto value = field_formatter::FormatString(
+            keypress.autofill_value().value_expression(),
+            field_formatter::CreateAutofillMappings(*address,
+                                                    /* locale= */ "en-US"));
+        if (!value.has_value()) {
+          FailAction(ClientStatus(AUTOFILL_INFO_NOT_AVAILABLE), keypress_index);
+          return;
+        }
+
+        field_inputs_.emplace_back(*value);
+        break;
+      }
       default:
         VLOG(1) << "Unrecognized field for SetFormFieldValueProto_KeyPress";
-        EndAction(ClientStatus(INVALID_ACTION));
+        FailAction(ClientStatus(INVALID_ACTION), keypress_index);
         return;
     }
+    ++keypress_index;
   }
 
   delegate_->ShortWaitForElement(
@@ -278,6 +313,14 @@
   }
 }
 
+void SetFormFieldValueAction::FailAction(const ClientStatus& status,
+                                         int keypress_index) {
+  processed_action_proto_->mutable_status_details()
+      ->mutable_form_field_error_info()
+      ->set_invalid_keypress_index(keypress_index);
+  EndAction(status);
+}
+
 void SetFormFieldValueAction::EndAction(const ClientStatus& status) {
   // Clear immediately, to prevent sensitive information from staying in memory.
   field_inputs_.clear();
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action.h b/components/autofill_assistant/browser/actions/set_form_field_value_action.h
index 6a5b3674..ccdf3ab5 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action.h
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action.h
@@ -70,6 +70,7 @@
 
   void OnGetStoredPassword(int field_index, bool success, std::string password);
 
+  void FailAction(const ClientStatus& status, int keypress_index);
   void EndAction(const ClientStatus& status);
 
   Selector selector_;
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc b/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
index 4e6b98e..74f221d 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action_unittest.cc
@@ -7,8 +7,14 @@
 #include <string>
 #include <utility>
 
+#include "base/guid.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "components/autofill_assistant/browser/actions/action_test_utils.h"
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
 #include "components/autofill_assistant/browser/client_status.h"
@@ -357,4 +363,80 @@
   EXPECT_TRUE(action.field_inputs_.empty());
 }
 
+TEST_F(SetFormFieldValueActionTest, EmptyProfileValueFails) {
+  set_form_field_proto_->add_value()->mutable_autofill_value();
+  SetFormFieldValueAction action(&mock_action_delegate_, proto_);
+
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
+  action.ProcessAction(callback_.Get());
+}
+
+TEST_F(SetFormFieldValueActionTest, RequestDataFromUnknownProfile) {
+  auto* value = set_form_field_proto_->add_value()->mutable_autofill_value();
+  value->mutable_profile()->set_identifier("none");
+  value->set_value_expression("value");
+  SetFormFieldValueAction action(&mock_action_delegate_, proto_);
+
+  EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+                                              PRECONDITION_FAILED))));
+  action.ProcessAction(callback_.Get());
+}
+
+TEST_F(SetFormFieldValueActionTest, RequestUnknownDataFromProfile) {
+  autofill::AutofillProfile contact(base::GenerateGUID(),
+                                    autofill::test::kEmptyOrigin);
+  // Middle name is expected to be empty.
+  autofill::test::SetProfileInfo(&contact, "John", /* middle name */ "", "Doe",
+                                 "", "", "", "", "", "", "", "", "");
+  user_data_.selected_addresses_["contact"] =
+      std::make_unique<autofill::AutofillProfile>(contact);
+
+  auto* value = set_form_field_proto_->add_value()->mutable_autofill_value();
+  value->mutable_profile()->set_identifier("contact");
+  value->set_value_expression(
+      base::StrCat({"${",
+                    base::NumberToString(static_cast<int>(
+                        autofill::ServerFieldType::NAME_MIDDLE)),
+                    "}"}));
+  SetFormFieldValueAction action(&mock_action_delegate_, proto_);
+
+  EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+                                              AUTOFILL_INFO_NOT_AVAILABLE))));
+  action.ProcessAction(callback_.Get());
+}
+
+TEST_F(SetFormFieldValueActionTest, SetFieldFromProfileValue) {
+  autofill::AutofillProfile contact(base::GenerateGUID(),
+                                    autofill::test::kEmptyOrigin);
+  autofill::test::SetProfileInfo(&contact, "John", "", "Doe", "", "", "", "",
+                                 "", "", "", "", "");
+  user_data_.selected_addresses_["contact"] =
+      std::make_unique<autofill::AutofillProfile>(contact);
+
+  auto* value = set_form_field_proto_->add_value()->mutable_autofill_value();
+  value->mutable_profile()->set_identifier("contact");
+  value->set_value_expression(
+      base::StrCat({"${",
+                    base::NumberToString(static_cast<int>(
+                        autofill::ServerFieldType::NAME_FIRST)),
+                    "}"}));
+  SetFormFieldValueAction action(&mock_action_delegate_, proto_);
+
+  ON_CALL(mock_action_delegate_, OnGetFieldValue(_, _))
+      .WillByDefault(RunOnceCallback<1>(OkClientStatus(), "not empty"));
+  EXPECT_CALL(mock_action_delegate_,
+              OnSetFieldValue("John", _, _,
+                              EqualsElement(test_util::MockFindElement(
+                                  mock_action_delegate_, fake_selector_)),
+                              _))
+      .WillOnce(RunOnceCallback<4>(OkClientStatus()));
+
+  EXPECT_CALL(
+      callback_,
+      Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+  action.ProcessAction(callback_.Get());
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 9edb5a1..c489932 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -459,6 +459,21 @@
   CLICK = 3;
 }
 
+message AutofillValue {
+  message Profile { optional string identifier = 1; }
+
+  // The profile to be used. This has to be requested with a
+  // |CollectUserDataAction| first.
+  optional Profile profile = 1;
+
+  // A string containing any number of "${key}" placeholders, where the key is
+  // an integer corresponding to entries from field_types.h or
+  // |AutofillFormatProto::AutofillAssistantCustomField|.
+  // Note that the set of actually available fields are outside of our
+  // control and are retrieved automatically from the provided profile.
+  optional string value_expression = 2;
+}
+
 // An action could be performed.
 message ActionProto {
   // Wait these many milliseconds before executing the action, if set.
@@ -607,6 +622,9 @@
 
   // More information included for autofill related errors.
   optional AutofillErrorInfoProto autofill_error_info = 3;
+
+  // More information included for |SetFormFieldValueProto| related errors.
+  optional SetFormFieldErrorInfoProto form_field_error_info = 4;
 }
 
 message NavigationInfoProto {
@@ -711,6 +729,13 @@
   repeated AutofillFieldError autofill_field_error = 5;
 }
 
+// Message to report |SetFormFieldValueProto| related errors for debugging
+// purposes.
+message SetFormFieldErrorInfoProto {
+  // The index of |keypress| that caused the action to be invalid.
+  optional int32 invalid_keypress_index = 1;
+}
+
 // The pseudo type values come from
 // https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-PseudoType.
 enum PseudoType {
@@ -914,13 +939,20 @@
   // The drop down element on which to select an option.
   optional SelectorProto element = 2;
 
-  // Value of the option to use.
-  optional string selected_option = 3;
+  oneof value {
+    // Value of the option to use.
+    string selected_option = 3;
+    // A value from an Autofill source. Note that this must be proceeded by a
+    // |CollectUserDataAction|.
+    AutofillValue autofill_value = 5;
+  }
 
   // The strategy used to select a value option. This defaults to
   // |LABEL_STARTS_WITH| for the legacy case.
   optional DropdownSelectStrategy select_strategy = 4
       [default = LABEL_STARTS_WITH];
+
+  reserved 1;
 }
 
 // Contain a localized text message from the server.
@@ -993,9 +1025,9 @@
   // Message used to indicate what form fields should be filled with what
   // information coming from the address.
   message RequiredField {
-    // A string containing either a single integer key or multiple "${key}"
-    // placeholders, where the key is an integer corresponding to entries from
-    // field_types.h or AutofillFormatProto::AutofillAssistantCustomField.
+    // A string containing any number of "${key}" placeholders, where the key
+    // is an integer corresponding to entries from field_types.h or
+    // |AutofillFormatProto::AutofillAssistantCustomField|.
     // Example:
     // * "3" -> First name.
     // * "${3}" -> First name.
@@ -1059,9 +1091,9 @@
   // Message used to indicate what form fields should be filled with what
   // information.
   message RequiredField {
-    // A string containing either a single integer key or multiple "${key}"
-    // placeholders, where the key is an integer corresponding to entries from
-    // field_types.h or AutofillFormatProto::AutofillAssistantCustomField.
+    // A string containing any number of "${key}" placeholders, where the key
+    // is an integer corresponding to entries from field_types.h or
+    // |AutofillFormatProto::AutofillAssistantCustomField|.
     // Example:
     // * "51" -> Full name.
     // * "${51}" -> Full Name.
@@ -1918,6 +1950,9 @@
       bool use_password = 5;
       // Use the value stored at the specified memory location.
       string client_memory_key = 6;
+      // A value from an Autofill source. Note that this must be proceeded by a
+      // |CollectUserDataAction|.
+      AutofillValue autofill_value = 8;
     }
 
     reserved 7;
diff --git a/components/content_settings/core/common/content_settings_pattern.cc b/components/content_settings/core/common/content_settings_pattern.cc
index 7e13ce9..2693e1c 100644
--- a/components/content_settings/core/common/content_settings_pattern.cc
+++ b/components/content_settings/core/common/content_settings_pattern.cc
@@ -15,12 +15,14 @@
 #include "base/notreached.h"
 #include "base/optional.h"
 #include "base/stl_util.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "components/content_settings/core/common/content_settings_pattern_parser.h"
 #include "net/base/url_util.h"
 #include "url/gurl.h"
+#include "url/url_constants.h"
 
 namespace {
 
@@ -240,9 +242,18 @@
   parts->scheme = base::ToLowerASCII(parts->scheme);
 
   if (parts->scheme == url::kFileScheme && !parts->is_path_wildcard) {
-    GURL url(std::string(url::kFileScheme) +
-             std::string(url::kStandardSchemeSeparator) + parts->path);
-    parts->path = url.path();
+    // TODO(crbug.com/1132957): Remove this loop once GURL canonicalization is
+    // idempotent (see crbug.com/1128999).
+    while (true) {
+      std::string url_spec = base::StrCat(
+          {url::kFileScheme, url::kStandardSchemeSeparator, parts->path});
+      GURL url(url_spec);
+      if (!url.is_valid())
+        return false;
+      if (parts->path == url.path_piece())
+        break;
+      parts->path = url.path();
+    }
   }
 
   // Canonicalize the host part.
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 26d8a6ef7..b3e128a 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -2,9 +2,17 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/linux/pkg_config.gni")
 import("//build/config/ui.gni")
 import("//chrome/common/features.gni")
 import("//testing/test.gni")
+import("//ui/base/ui_features.gni")
+
+if (use_xkbcommon) {
+  pkg_config("xkbcommon") {
+    packages = [ "xkbcommon" ]
+  }
+}
 
 static_library("exo") {
   sources = [
@@ -160,6 +168,9 @@
       "xkb_tracker.cc",
       "xkb_tracker.h",
     ]
+    if (use_xkbcommon) {
+      configs += [ ":xkbcommon" ]
+    }
   }
 
   if (is_chromecast) {
diff --git a/components/exo/keyboard.cc b/components/exo/keyboard.cc
index 5cd88fae..24b7438d 100644
--- a/components/exo/keyboard.cc
+++ b/components/exo/keyboard.cc
@@ -14,11 +14,13 @@
 #include "components/exo/input_trace.h"
 #include "components/exo/keyboard_delegate.h"
 #include "components/exo/keyboard_device_configuration_delegate.h"
+#include "components/exo/keyboard_modifiers.h"
 #include "components/exo/seat.h"
 #include "components/exo/shell_surface.h"
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/surface.h"
 #include "components/exo/wm_helper.h"
+#include "components/exo/xkb_tracker.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/window.h"
@@ -169,7 +171,7 @@
   ash::ImeControllerImpl* ime_controller = ash::Shell::Get()->ime_controller();
   ime_controller->AddObserver(this);
 
-  delegate_->OnKeyboardLayoutUpdated(ime_controller->keyboard_layout_name());
+  delegate_->OnKeyboardLayoutUpdated(seat_->xkb_tracker()->GetKeymap().get());
   OnSurfaceFocused(seat_->GetFocusedSurface());
   OnKeyRepeatSettingsChanged(
       ash::KeyboardController::Get()->GetKeyRepeatSettings());
@@ -278,7 +280,9 @@
       ConsumedByIme(focus_, event);
 
   // Always update modifiers.
-  delegate_->OnKeyboardModifiers(event->flags());
+  // XkbTracker must be updated in the Seat, before calling this method.
+  // Ensured by the observer registration order.
+  delegate_->OnKeyboardModifiers(seat_->xkb_tracker()->GetModifiers());
 
   // TODO(yhanada): This is a quick fix for https://crbug.com/859071. Remove
   // ARC-specific code path once we can find a way to manage press/release
@@ -401,7 +405,9 @@
 void Keyboard::OnCapsLockChanged(bool enabled) {}
 
 void Keyboard::OnKeyboardLayoutNameChanged(const std::string& layout_name) {
-  delegate_->OnKeyboardLayoutUpdated(layout_name);
+  // XkbTracker must be updated in the Seat, before calling this method.
+  // Ensured by the observer registration order.
+  delegate_->OnKeyboardLayoutUpdated(seat_->xkb_tracker()->GetKeymap().get());
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -416,7 +422,7 @@
   }
   if (surface) {
     pressed_keys_ = seat_->pressed_keys();
-    delegate_->OnKeyboardModifiers(seat_->modifier_flags());
+    delegate_->OnKeyboardModifiers(seat_->xkb_tracker()->GetModifiers());
     delegate_->OnKeyboardEnter(surface, pressed_keys_);
     focus_ = surface;
     focus_->AddSurfaceObserver(this);
diff --git a/components/exo/keyboard_delegate.h b/components/exo/keyboard_delegate.h
index 0470e0d..ff97652 100644
--- a/components/exo/keyboard_delegate.h
+++ b/components/exo/keyboard_delegate.h
@@ -7,6 +7,7 @@
 
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
+#include "base/strings/string_piece.h"
 #include "base/time/time.h"
 
 namespace ui {
@@ -14,6 +15,7 @@
 }
 
 namespace exo {
+struct KeyboardModifiers;
 class Surface;
 
 // Handles events on keyboards in context-specific ways.
@@ -42,7 +44,7 @@
                                  bool pressed) = 0;
 
   // Called when keyboard modifier state changed.
-  virtual void OnKeyboardModifiers(int modifier_flags) = 0;
+  virtual void OnKeyboardModifiers(const KeyboardModifiers& modifiers) = 0;
 
   // Called when key repeat settings are changed.
   virtual void OnKeyRepeatSettingsChanged(bool enabled,
@@ -50,9 +52,7 @@
                                           base::TimeDelta interval) = 0;
 
   // Called when keyboard layout is updated.
-  // TODO(hidehiko): Update the argument to pass the keymap
-  // when XkbTracker is moved out from WaylandKeyboardDelegate.
-  virtual void OnKeyboardLayoutUpdated(const std::string& layout_name) = 0;
+  virtual void OnKeyboardLayoutUpdated(base::StringPiece keymap) = 0;
 };
 
 }  // namespace exo
diff --git a/components/exo/keyboard_unittest.cc b/components/exo/keyboard_unittest.cc
index 0cde39b7..60fd3d9 100644
--- a/components/exo/keyboard_unittest.cc
+++ b/components/exo/keyboard_unittest.cc
@@ -16,6 +16,7 @@
 #include "components/exo/buffer.h"
 #include "components/exo/keyboard_delegate.h"
 #include "components/exo/keyboard_device_configuration_delegate.h"
+#include "components/exo/keyboard_modifiers.h"
 #include "components/exo/keyboard_observer.h"
 #include "components/exo/seat.h"
 #include "components/exo/shell_surface.h"
@@ -35,6 +36,12 @@
 namespace exo {
 namespace {
 
+// XKB mod masks for the default keymap.
+constexpr uint32_t kShiftMask = 1 << 0;
+constexpr uint32_t kControlMask = 1 << 2;
+constexpr uint32_t kAltMask = 1 << 3;
+constexpr uint32_t kNumLockMask = 1 << 4;
+
 using KeyboardTest = test::ExoTestBase;
 
 class MockKeyboardDelegate : public KeyboardDelegate {
@@ -48,11 +55,11 @@
               (Surface*, (const base::flat_map<ui::DomCode, ui::DomCode>&)));
   MOCK_METHOD(void, OnKeyboardLeave, (Surface*));
   MOCK_METHOD(uint32_t, OnKeyboardKey, (base::TimeTicks, ui::DomCode, bool));
-  MOCK_METHOD(void, OnKeyboardModifiers, (int));
+  MOCK_METHOD(void, OnKeyboardModifiers, (const KeyboardModifiers&));
   MOCK_METHOD(void,
               OnKeyRepeatSettingsChanged,
               (bool, base::TimeDelta, base::TimeDelta));
-  MOCK_METHOD(void, OnKeyboardLayoutUpdated, (const std::string&));
+  MOCK_METHOD(void, OnKeyboardLayoutUpdated, (base::StringPiece));
 };
 using NiceMockKeyboardDelegate = ::testing::NiceMock<MockKeyboardDelegate>;
 
@@ -165,9 +172,11 @@
   Keyboard keyboard(std::move(delegate), &seat);
   testing::Mock::VerifyAndClearExpectations(delegate_ptr);
 
+  // Set up expectation for the key release.
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(ui::EF_SHIFT_DOWN));
+  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(KeyboardModifiers{
+                                 kShiftMask | kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>(
@@ -185,7 +194,8 @@
   // Key should no longer be pressed when focus returns.
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(ui::EF_SHIFT_DOWN));
+  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(KeyboardModifiers{
+                                 kShiftMask | kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -213,7 +223,8 @@
   ON_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillByDefault(testing::Return(true));
 
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -224,7 +235,8 @@
   focus_client->FocusWindow(nullptr);
   testing::Mock::VerifyAndClearExpectations(delegate_ptr);
 
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -259,7 +271,8 @@
 
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -288,7 +301,8 @@
   // Test key event rewriting. In this case, ARROW_DOWN is rewritten to KEY_END
   // as a result of ALT being pressed.
   EXPECT_CALL(*delegate_ptr, OnKeyboardKey(testing::_, ui::DomCode::END, true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(ui::EF_ALT_DOWN));
+  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(KeyboardModifiers{
+                                 kAltMask | kNumLockMask, 0, 0, 0}));
   seat.set_physical_code_for_currently_processing_event_for_testing(
       ui::DomCode::ARROW_DOWN);
   generator.PressKey(ui::VKEY_END, ui::EF_ALT_DOWN);
@@ -298,7 +312,8 @@
   // associated with the key press.
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardKey(testing::_, ui::DomCode::END, false));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   generator.ReleaseKey(ui::VKEY_DOWN, 0);
   testing::Mock::VerifyAndClearExpectations(delegate_ptr);
 
@@ -313,7 +328,8 @@
   // Key should be pressed when focus returns.
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(ui::EF_CONTROL_DOWN));
+  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(KeyboardModifiers{
+                                 kControlMask | kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>(
@@ -375,7 +391,8 @@
 
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -459,7 +476,8 @@
 
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -470,7 +488,8 @@
   // This should generate a modifier event.
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardKey(testing::_, ui::DomCode::US_A, true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(ui::EF_SHIFT_DOWN));
+  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(KeyboardModifiers{
+                                 kShiftMask | kNumLockMask, 0, 0, 0}));
   seat.set_physical_code_for_currently_processing_event_for_testing(
       ui::DomCode::US_A);
   generator.PressKey(ui::VKEY_A, ui::EF_SHIFT_DOWN);
@@ -480,7 +499,8 @@
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardKey(testing::_, ui::DomCode::US_B, true));
   EXPECT_CALL(*delegate_ptr,
-              OnKeyboardModifiers(ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN));
+              OnKeyboardModifiers(KeyboardModifiers{
+                  kShiftMask | kAltMask | kNumLockMask, 0, 0, 0}));
   seat.set_physical_code_for_currently_processing_event_for_testing(
       ui::DomCode::US_B);
   generator.PressKey(ui::VKEY_B, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN);
@@ -489,7 +509,8 @@
   // This should generate a third modifier event.
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardKey(testing::_, ui::DomCode::US_B, false));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   generator.ReleaseKey(ui::VKEY_B, 0);
   // Verify before destroying keyboard to make sure the expected call
   // is made on the methods above, rather than in the destructor.
@@ -792,10 +813,12 @@
   auto* delegate_ptr = delegate.get();
   Seat seat;
   Keyboard keyboard(std::move(delegate), &seat);
+  testing::Mock::VerifyAndClearExpectations(delegate_ptr);
 
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -806,7 +829,8 @@
   // to ShellSurface.
   ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
   // Press KEY_W with Ctrl.
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(4));
+  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(KeyboardModifiers{
+                                 kControlMask | kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*shell_surface.get(), AcceleratorPressed(ui::Accelerator(
                                         ui::VKEY_W, ui::EF_CONTROL_DOWN,
                                         ui::Accelerator::KeyState::PRESSED)))
@@ -877,7 +901,8 @@
   testing::Mock::VerifyAndClearExpectations(shell_surface.get());
 
   // Release the key and reset modifier_flags.
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardKey(testing::_, ui::DomCode::US_W, false));
   generator.ReleaseKey(ui::VKEY_W, 0);
@@ -906,7 +931,8 @@
 
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0)).Times(1);
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -917,7 +943,9 @@
   keyboard.SetNeedKeyboardKeyAcks(true);
 
   // Press KEY_W with Ctrl.
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(4)).Times(1);
+  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(KeyboardModifiers{
+                                 kControlMask | kNumLockMask, 0, 0, 0}))
+      .Times(1);
   EXPECT_CALL(*delegate_ptr, OnKeyboardKey(testing::_, ui::DomCode::US_W, true))
       .WillOnce(testing::Return(1));
   seat.set_physical_code_for_currently_processing_event_for_testing(
@@ -954,7 +982,8 @@
 
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -965,7 +994,8 @@
   keyboard.SetNeedKeyboardKeyAcks(true);
 
   // Press KEY_W with Ctrl.
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(4));
+  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(KeyboardModifiers{
+                                 kControlMask | kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr, OnKeyboardKey(testing::_, ui::DomCode::US_W, true))
       .WillOnce(testing::Return(1));
   seat.set_physical_code_for_currently_processing_event_for_testing(
@@ -996,7 +1026,8 @@
   keyboard.AckKeyboardKey(1, false /* handled */);
 
   // Release the key and reset modifier_flags.
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardKey(testing::_, ui::DomCode::US_W, false));
   generator.ReleaseKey(ui::VKEY_W, 0);
@@ -1044,7 +1075,8 @@
 
   EXPECT_CALL(*delegate_ptr, CanAcceptKeyboardEventsForSurface(surface.get()))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(0));
+  EXPECT_CALL(*delegate_ptr,
+              OnKeyboardModifiers(KeyboardModifiers{kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr,
               OnKeyboardEnter(surface.get(),
                               base::flat_map<ui::DomCode, ui::DomCode>()));
@@ -1055,7 +1087,8 @@
   keyboard.SetNeedKeyboardKeyAcks(true);
 
   // Press KEY_W with Ctrl.
-  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(4));
+  EXPECT_CALL(*delegate_ptr, OnKeyboardModifiers(KeyboardModifiers{
+                                 kControlMask | kNumLockMask, 0, 0, 0}));
   EXPECT_CALL(*delegate_ptr, OnKeyboardKey(testing::_, ui::DomCode::US_W, true))
       .WillOnce(testing::Return(1));
   seat.set_physical_code_for_currently_processing_event_for_testing(
diff --git a/components/exo/seat.cc b/components/exo/seat.cc
index c7881a30..6b8c9db 100644
--- a/components/exo/seat.cc
+++ b/components/exo/seat.cc
@@ -25,6 +25,7 @@
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/surface.h"
 #include "components/exo/wm_helper.h"
+#include "components/exo/xkb_tracker.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"
@@ -62,6 +63,14 @@
     ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
 #if defined(OS_CHROMEOS)
   ui_lock_controller_ = std::make_unique<UILockController>(this);
+
+  // Seat needs to be registered as observers before any Keyboard,
+  // because Keyboard expects that the XkbTracker is up-to-date when its
+  // observer method is called.
+  xkb_tracker_ = std::make_unique<XkbTracker>();
+  ash::ImeControllerImpl* ime_controller = ash::Shell::Get()->ime_controller();
+  xkb_tracker_->UpdateKeyboardLayout(ime_controller->keyboard_layout_name());
+  ime_controller->AddObserver(this);
 #endif
 }
 
@@ -74,6 +83,9 @@
     return;
   shutdown_ = true;
   DCHECK(!selection_source_) << "DataSource must be released before Seat";
+#if defined(OS_CHROMEOS)
+  ash::Shell::Get()->ime_controller()->RemoveObserver(this);
+#endif
   WMHelper::GetInstance()->RemoveFocusObserver(this);
   WMHelper::GetInstance()->RemovePreTargetHandler(this);
   ui::ClipboardMonitor::GetInstance()->RemoveObserver(this);
@@ -291,7 +303,9 @@
         break;
     }
   }
-  modifier_flags_ = event->flags();
+#if defined(OS_CHROMEOS)
+  xkb_tracker_->UpdateKeyboardModifiers(event->flags());
+#endif
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -304,6 +318,17 @@
   selection_source_.reset();
 }
 
+#if defined(OS_CHROMEOS)
+////////////////////////////////////////////////////////////////////////////////
+// ash::ImeControllerImpl::Observer overrides:
+
+void Seat::OnCapsLockChanged(bool enabled) {}
+
+void Seat::OnKeyboardLayoutNameChanged(const std::string& layout_name) {
+  xkb_tracker_->UpdateKeyboardLayout(layout_name);
+}
+#endif
+
 ////////////////////////////////////////////////////////////////////////////////
 // DataSourceObserver overrides:
 
diff --git a/components/exo/seat.h b/components/exo/seat.h
index 2a6940e5..348f1f1 100644
--- a/components/exo/seat.h
+++ b/components/exo/seat.h
@@ -19,6 +19,7 @@
 #include "ui/events/platform/platform_event_observer.h"
 
 #if defined(OS_CHROMEOS)
+#include "ash/ime/ime_controller_impl.h"
 #include "components/exo/ui_lock_controller.h"
 #endif
 
@@ -32,6 +33,7 @@
 class ScopedDataSource;
 class SeatObserver;
 class Surface;
+class XkbTracker;
 
 // The maximum number of different data types that we will write to the
 // clipboard (plain text, RTF, HTML, image)
@@ -43,6 +45,9 @@
              public ui::PlatformEventObserver,
              public ui::EventHandler,
              public ui::ClipboardObserver,
+#if defined(OS_CHROMEOS)
+             public ash::ImeControllerImpl::Observer,
+#endif
              public DataSourceObserver {
  public:
   Seat();
@@ -62,8 +67,9 @@
     return pressed_keys_;
   }
 
-  // Returns current set of modifier flags.
-  int modifier_flags() const { return modifier_flags_; }
+#if defined(OS_CHROMEOS)
+  const XkbTracker* xkb_tracker() const { return xkb_tracker_.get(); }
+#endif
 
   // Returns physical code for the currently processing event.
   ui::DomCode physical_code_for_currently_processing_event() const {
@@ -102,6 +108,12 @@
   // Overridden from DataSourceObserver:
   void OnDataSourceDestroying(DataSource* source) override;
 
+#if defined(OS_CHROMEOS)
+  // Overridden from ash::ImeControllerImpl::Observer:
+  void OnCapsLockChanged(bool enabled) override;
+  void OnKeyboardLayoutNameChanged(const std::string& layout_name) override;
+#endif
+
   void set_physical_code_for_currently_processing_event_for_testing(
       ui::DomCode physical_code_for_currently_processing_event) {
     physical_code_for_currently_processing_event_ =
@@ -149,7 +161,6 @@
   // physical key press generated.
   base::flat_map<ui::DomCode, ui::DomCode> pressed_keys_;
   ui::DomCode physical_code_for_currently_processing_event_ = ui::DomCode::NONE;
-  int modifier_flags_ = 0;
 
   // Data source being used as a clipboard content.
   std::unique_ptr<ScopedDataSource> selection_source_;
@@ -165,6 +176,7 @@
 
 #if defined(OS_CHROMEOS)
   std::unique_ptr<UILockController> ui_lock_controller_;
+  std::unique_ptr<XkbTracker> xkb_tracker_;
 #endif  // defined(OS_CHROMEOS)
 
   base::WeakPtrFactory<Seat> weak_ptr_factory_{this};
diff --git a/components/exo/wayland/BUILD.gn b/components/exo/wayland/BUILD.gn
index 34c6897..cb90905 100644
--- a/components/exo/wayland/BUILD.gn
+++ b/components/exo/wayland/BUILD.gn
@@ -2,19 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/linux/pkg_config.gni")
 import("//build/config/ui.gni")
 import("//gpu/vulkan/features.gni")
 import("//testing/test.gni")
 import("//ui/base/ui_features.gni")
 import("//ui/ozone/ozone.gni")
 
-if (use_xkbcommon) {
-  pkg_config("xkbcommon") {
-    packages = [ "xkbcommon" ]
-  }
-}
-
 source_set("wayland") {
   sources = [
     "scoped_wl.cc",
@@ -136,7 +129,6 @@
   }
 
   if (use_xkbcommon) {
-    configs += [ ":xkbcommon" ]
     deps += [ "//ui/events/keycodes:xkb" ]
   }
 
diff --git a/components/exo/wayland/fuzzer/harness_unittest.cc b/components/exo/wayland/fuzzer/harness_unittest.cc
index 446eb5b..d2c8d7fd 100644
--- a/components/exo/wayland/fuzzer/harness_unittest.cc
+++ b/components/exo/wayland/fuzzer/harness_unittest.cc
@@ -5,7 +5,6 @@
 #include "components/exo/wayland/fuzzer/harness.h"
 
 #include "base/files/scoped_temp_dir.h"
-#include "base/macros.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "components/exo/display.h"
@@ -13,20 +12,36 @@
 #include "components/exo/wayland/fuzzer/actions.pb.h"
 #include "components/exo/wayland/server.h"
 
+#if defined(OS_CHROMEOS)
+#include "components/exo/test/exo_test_base.h"
+#endif
+
 namespace exo {
 namespace wayland_fuzzer {
 namespace {
 
-class WaylandFuzzerTest : public test::ExoTestBaseViews {
+// Use ExoTestBase on Chrome OS because Server starts to depends on ash::Shell,
+// which is unavailable on other platforms so then ExoTestBaseViews instead.
+using TestBase =
+#if defined(OS_CHROMEOS)
+    test::ExoTestBase
+#else
+    test::ExoTestBaseViews
+#endif
+    ;
+
+class WaylandFuzzerTest : public TestBase {
  protected:
   WaylandFuzzerTest() = default;
+  WaylandFuzzerTest(const WaylandFuzzerTest&) = delete;
+  WaylandFuzzerTest& operator=(const WaylandFuzzerTest&) = delete;
   ~WaylandFuzzerTest() override = default;
 
   void SetUp() override {
     ASSERT_TRUE(xdg_temp_dir_.CreateUniqueTempDir());
     setenv("XDG_RUNTIME_DIR", xdg_temp_dir_.GetPath().MaybeAsASCII().c_str(),
            1 /* overwrite */);
-    test::ExoTestBaseViews::SetUp();
+    TestBase::SetUp();
     display_ = std::make_unique<exo::Display>();
     server_ = wayland::Server::Create(display_.get());
   }
@@ -34,15 +49,12 @@
   void TearDown() override {
     server_.reset();
     display_.reset();
-    test::ExoTestBaseViews::TearDown();
+    TestBase::TearDown();
   }
 
   base::ScopedTempDir xdg_temp_dir_;
   std::unique_ptr<exo::Display> display_;
   std::unique_ptr<wayland::Server> server_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(WaylandFuzzerTest);
 };
 
 void RunHarness(Harness* harness, base::WaitableEvent* event) {
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index a6ce378..20b98bc 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -215,8 +215,8 @@
   wl_global_create(wl_display_.get(), &zcr_extended_drag_v1_interface, 1,
                    display_, bind_extended_drag);
 
-  zwp_text_manager_data_ =
-      std::make_unique<WaylandTextInputManager>(serial_tracker_.get());
+  zwp_text_manager_data_ = std::make_unique<WaylandTextInputManager>(
+      display_->seat()->xkb_tracker(), serial_tracker_.get());
   wl_global_create(wl_display_.get(), &zwp_text_input_manager_v1_interface, 1,
                    zwp_text_manager_data_.get(), bind_text_input_manager);
 
diff --git a/components/exo/wayland/server_unittest.cc b/components/exo/wayland/server_unittest.cc
index 004daee..ef827b1 100644
--- a/components/exo/wayland/server_unittest.cc
+++ b/components/exo/wayland/server_unittest.cc
@@ -20,6 +20,10 @@
 #include "components/exo/test/exo_test_base_views.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_CHROMEOS)
+#include "components/exo/test/exo_test_base.h"
+#endif
+
 namespace exo {
 namespace wayland {
 namespace {
@@ -31,22 +35,32 @@
                             g_next_socket_id.GetNext());
 }
 
-class ServerTest : public test::ExoTestBaseViews {
+// Use ExoTestBase on Chrome OS because Server starts to depends on ash::Shell,
+// which is unavailable on other platforms so then ExoTestBaseViews instead.
+using TestBase =
+#if defined(OS_CHROMEOS)
+    test::ExoTestBase
+#else
+    test::ExoTestBaseViews
+#endif
+    ;
+
+class ServerTest : public TestBase {
  public:
-  ServerTest() {}
-  ~ServerTest() override {}
+  ServerTest() = default;
+  ServerTest(const ServerTest&) = delete;
+  ServerTest& operator=(const ServerTest&) = delete;
+  ~ServerTest() override = default;
 
   void SetUp() override {
     ASSERT_TRUE(xdg_temp_dir_.CreateUniqueTempDir());
     setenv("XDG_RUNTIME_DIR", xdg_temp_dir_.GetPath().MaybeAsASCII().c_str(),
            1 /* overwrite */);
-    test::ExoTestBaseViews::SetUp();
+    TestBase::SetUp();
   }
 
  private:
   base::ScopedTempDir xdg_temp_dir_;
-
-  DISALLOW_COPY_AND_ASSIGN(ServerTest);
 };
 
 TEST_F(ServerTest, AddSocket) {
diff --git a/components/exo/wayland/wayland_keyboard_delegate.cc b/components/exo/wayland/wayland_keyboard_delegate.cc
index e8d9d38..ffc05a7 100644
--- a/components/exo/wayland/wayland_keyboard_delegate.cc
+++ b/components/exo/wayland/wayland_keyboard_delegate.cc
@@ -10,11 +10,13 @@
 #include <wayland-server-protocol-core.h>
 
 #include "base/containers/flat_map.h"
-#include "components/exo/keyboard_modifiers.h"
 #include "components/exo/wayland/serial_tracker.h"
-#include "components/exo/xkb_tracker.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 
+#if BUILDFLAG(USE_XKBCOMMON)
+#include <xkbcommon/xkbcommon.h>
+#endif
+
 namespace exo {
 namespace wayland {
 
@@ -22,9 +24,7 @@
 
 WaylandKeyboardDelegate::WaylandKeyboardDelegate(wl_resource* keyboard_resource,
                                                  SerialTracker* serial_tracker)
-    : keyboard_resource_(keyboard_resource),
-      serial_tracker_(serial_tracker),
-      xkb_tracker_(std::make_unique<XkbTracker>()) {}
+    : keyboard_resource_(keyboard_resource), serial_tracker_(serial_tracker) {}
 
 WaylandKeyboardDelegate::~WaylandKeyboardDelegate() = default;
 
@@ -88,11 +88,9 @@
   return serial;
 }
 
-void WaylandKeyboardDelegate::OnKeyboardModifiers(int modifier_flags) {
-  xkb_tracker_->UpdateKeyboardModifiers(modifier_flags);
-
+void WaylandKeyboardDelegate::OnKeyboardModifiers(
+    const KeyboardModifiers& modifiers) {
   // Send the update only when they're different.
-  const KeyboardModifiers modifiers = xkb_tracker_->GetModifiers();
   if (current_modifiers_ == modifiers)
     return;
   current_modifiers_ = modifiers;
@@ -100,9 +98,23 @@
 }
 
 void WaylandKeyboardDelegate::OnKeyboardLayoutUpdated(
-    const std::string& layout_name) {
-  xkb_tracker_->UpdateKeyboardLayout(layout_name);
-  SendLayout();
+    base::StringPiece keymap) {
+  // Sent the content of |keymap| with trailing '\0' termination via shared
+  // memory.
+  base::UnsafeSharedMemoryRegion shared_keymap_region =
+      base::UnsafeSharedMemoryRegion::Create(keymap.size() + 1);
+  base::WritableSharedMemoryMapping shared_keymap = shared_keymap_region.Map();
+  base::subtle::PlatformSharedMemoryRegion platform_shared_keymap =
+      base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
+          std::move(shared_keymap_region));
+  DCHECK(shared_keymap.IsValid());
+
+  std::memcpy(shared_keymap.memory(), keymap.data(), keymap.size());
+  static_cast<uint8_t*>(shared_keymap.memory())[keymap.size()] = '\0';
+  wl_keyboard_send_keymap(keyboard_resource_, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+                          platform_shared_keymap.GetPlatformHandle().fd,
+                          keymap.size() + 1);
+  wl_client_flush(client());
 }
 
 uint32_t WaylandKeyboardDelegate::DomCodeToKey(ui::DomCode code) const {
@@ -124,25 +136,6 @@
   wl_client_flush(client());
 }
 
-void WaylandKeyboardDelegate::SendLayout() {
-  auto keymap = xkb_tracker_->GetKeymap();
-  size_t keymap_size = strlen(keymap.get()) + 1;
-
-  base::UnsafeSharedMemoryRegion shared_keymap_region =
-      base::UnsafeSharedMemoryRegion::Create(keymap_size);
-  base::WritableSharedMemoryMapping shared_keymap = shared_keymap_region.Map();
-  base::subtle::PlatformSharedMemoryRegion platform_shared_keymap =
-      base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
-          std::move(shared_keymap_region));
-  DCHECK(shared_keymap.IsValid());
-
-  std::memcpy(shared_keymap.memory(), keymap.get(), keymap_size);
-  wl_keyboard_send_keymap(keyboard_resource_, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
-                          platform_shared_keymap.GetPlatformHandle().fd,
-                          keymap_size);
-  wl_client_flush(client());
-}
-
 // Convert from ChromeOS's key repeat interval to Wayland's key repeat rate.
 // For example, an interval of 500ms is a rate of 1000/500 = 2 Hz.
 //
diff --git a/components/exo/wayland/wayland_keyboard_delegate.h b/components/exo/wayland/wayland_keyboard_delegate.h
index 98be676c..fd112ed 100644
--- a/components/exo/wayland/wayland_keyboard_delegate.h
+++ b/components/exo/wayland/wayland_keyboard_delegate.h
@@ -16,18 +16,10 @@
 #include "ui/base/buildflags.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 
-#if BUILDFLAG(USE_XKBCOMMON)
-#include <xkbcommon/xkbcommon.h>
-#include "ui/events/keycodes/scoped_xkb.h"  // nogncheck
-#endif
-
 struct wl_client;
 struct wl_resource;
 
 namespace exo {
-
-class XkbTracker;
-
 namespace wayland {
 class SerialTracker;
 
@@ -50,11 +42,11 @@
   uint32_t OnKeyboardKey(base::TimeTicks time_stamp,
                          ui::DomCode key,
                          bool pressed) override;
-  void OnKeyboardModifiers(int modifier_flags) override;
+  void OnKeyboardModifiers(const KeyboardModifiers& modifiers) override;
   void OnKeyRepeatSettingsChanged(bool enabled,
                                   base::TimeDelta delay,
                                   base::TimeDelta interval) override;
-  void OnKeyboardLayoutUpdated(const std::string& layout_name) override;
+  void OnKeyboardLayoutUpdated(base::StringPiece keymap) override;
 
  private:
   // Returns the corresponding key given a dom code.
@@ -63,9 +55,6 @@
   // Sends the current modifiers to the client.
   void SendKeyboardModifiers();
 
-  // Send the current keyboard layout to the client.
-  void SendLayout();
-
   // The client who own this keyboard instance.
   wl_client* client() const;
 
@@ -75,10 +64,6 @@
   // Owned by Server, which always outlives this delegate.
   SerialTracker* const serial_tracker_;
 
-  // TODO(hidehiko): Move this to the server in order to share it with
-  // zwp_text_input.
-  std::unique_ptr<XkbTracker> xkb_tracker_;
-
   // Tracks the latest modifiers.
   KeyboardModifiers current_modifiers_{};
 
diff --git a/components/exo/wayland/zwp_text_input_manager.cc b/components/exo/wayland/zwp_text_input_manager.cc
index b9b420d..927c060 100644
--- a/components/exo/wayland/zwp_text_input_manager.cc
+++ b/components/exo/wayland/zwp_text_input_manager.cc
@@ -14,6 +14,7 @@
 #include "components/exo/text_input.h"
 #include "components/exo/wayland/serial_tracker.h"
 #include "components/exo/wayland/server_util.h"
+#include "components/exo/xkb_tracker.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 
@@ -29,8 +30,11 @@
 class WaylandTextInputDelegate : public TextInput::Delegate {
  public:
   WaylandTextInputDelegate(wl_resource* text_input,
+                           const XkbTracker* xkb_tracker,
                            SerialTracker* serial_tracker)
-      : text_input_(text_input), serial_tracker_(serial_tracker) {}
+      : text_input_(text_input),
+        xkb_tracker_(xkb_tracker),
+        serial_tracker_(serial_tracker) {}
   ~WaylandTextInputDelegate() override = default;
 
   void set_surface(wl_resource* surface) { surface_ = surface; }
@@ -113,7 +117,8 @@
   }
 
   void SendKey(const ui::KeyEvent& event) override {
-    uint32_t code = ui::KeycodeConverter::DomCodeToNativeKeycode(event.code());
+    uint32_t keysym = xkb_tracker_->GetKeysym(
+        ui::KeycodeConverter::DomCodeToNativeKeycode(event.code()));
     bool pressed = (event.type() == ui::ET_KEY_PRESSED);
     // TODO(mukai): consolidate the definition of this modifiers_mask with other
     // similar ones in components/exo/keyboard.cc or arc_ime_service.cc.
@@ -127,7 +132,7 @@
     zwp_text_input_v1_send_keysym(
         text_input_, TimeTicksToMilliseconds(event.time_stamp()),
         serial_tracker_->GetNextSerial(SerialTracker::EventType::OTHER_EVENT),
-        code,
+        keysym,
         pressed ? WL_KEYBOARD_KEY_STATE_PRESSED
                 : WL_KEYBOARD_KEY_STATE_RELEASED,
         modifiers);
@@ -156,10 +161,12 @@
   wl_resource* text_input_;
   wl_resource* surface_ = nullptr;
 
+  // Owned by Seat, which is updated before calling the callbacks of this
+  // class.
+  const XkbTracker* const xkb_tracker_;
+
   // Owned by Server, which always outlives this delegate.
   SerialTracker* const serial_tracker_;
-
-  DISALLOW_COPY_AND_ASSIGN(WaylandTextInputDelegate);
 };
 
 void text_input_activate(wl_client* client,
@@ -353,7 +360,7 @@
   SetImplementation(
       text_input_resource, &text_input_v1_implementation,
       std::make_unique<TextInput>(std::make_unique<WaylandTextInputDelegate>(
-          text_input_resource, data->serial_tracker)));
+          text_input_resource, data->xkb_tracker, data->serial_tracker)));
 }
 
 const struct zwp_text_input_manager_v1_interface
diff --git a/components/exo/wayland/zwp_text_input_manager.h b/components/exo/wayland/zwp_text_input_manager.h
index 1cfd994..5578cdcc 100644
--- a/components/exo/wayland/zwp_text_input_manager.h
+++ b/components/exo/wayland/zwp_text_input_manager.h
@@ -7,22 +7,26 @@
 
 #include <stdint.h>
 
-#include "base/macros.h"
-
 struct wl_client;
 
 namespace exo {
+class XkbTracker;
+
 namespace wayland {
 class SerialTracker;
 
 struct WaylandTextInputManager {
-  WaylandTextInputManager(SerialTracker* serial_tracker)
-      : serial_tracker(serial_tracker) {}
+  WaylandTextInputManager(const XkbTracker* xkb_tracker,
+                          SerialTracker* serial_tracker)
+      : xkb_tracker(xkb_tracker), serial_tracker(serial_tracker) {}
+  WaylandTextInputManager(const WaylandTextInputManager&) = delete;
+  WaylandTextInputManager& operator=(const WaylandTextInputManager&) = delete;
+
+  // Owned by Seat, which also always outlives zwp_text_input_manager.
+  const XkbTracker* const xkb_tracker;
 
   // Owned by Server, which always outlives zwp_text_input_manager.
   SerialTracker* const serial_tracker;
-
-  DISALLOW_COPY_AND_ASSIGN(WaylandTextInputManager);
 };
 
 void bind_text_input_manager(wl_client* client,
diff --git a/components/exo/xkb_tracker.cc b/components/exo/xkb_tracker.cc
index a8d98237..5358f83 100644
--- a/components/exo/xkb_tracker.cc
+++ b/components/exo/xkb_tracker.cc
@@ -46,6 +46,10 @@
   UpdateKeyboardModifiersInternal();
 }
 
+uint32_t XkbTracker::GetKeysym(uint32_t xkb_keycode) const {
+  return xkb_state_key_get_one_sym(xkb_state_.get(), xkb_keycode);
+}
+
 std::unique_ptr<char, base::FreeDeleter> XkbTracker::GetKeymap() const {
   return std::unique_ptr<char, base::FreeDeleter>(
       xkb_keymap_get_as_string(xkb_keymap_.get(), XKB_KEYMAP_FORMAT_TEXT_V1));
diff --git a/components/exo/xkb_tracker.h b/components/exo/xkb_tracker.h
index bef65a8..74d4a09 100644
--- a/components/exo/xkb_tracker.h
+++ b/components/exo/xkb_tracker.h
@@ -41,6 +41,10 @@
   // ui::EventFlags.
   void UpdateKeyboardModifiers(int modifier_flags);
 
+  // Returns the keysym for the given XKB keycode, based on the current
+  // keymap and its modifier state.
+  uint32_t GetKeysym(uint32_t xkb_keycode) const;
+
   // Returns the XKB keymap data.
   std::unique_ptr<char, base::FreeDeleter> GetKeymap() const;
 
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.cc b/components/password_manager/core/browser/password_manager_metrics_util.cc
index a9d424ee..c33cc4c8 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.cc
+++ b/components/password_manager/core/browser/password_manager_metrics_util.cc
@@ -336,6 +336,22 @@
 void LogProtectedPasswordReuse(PasswordType reused_password_type) {}
 #endif
 
+void LogPasswordEditResult(IsUsernameChanged username_changed,
+                           IsPasswordChanged password_changed) {
+  PasswordEditUpdatedValues values;
+  if (username_changed && password_changed) {
+    values = PasswordEditUpdatedValues::kBoth;
+  } else if (username_changed) {
+    values = PasswordEditUpdatedValues::kUsername;
+  } else if (password_changed) {
+    values = PasswordEditUpdatedValues::kPassword;
+  } else {
+    values = PasswordEditUpdatedValues::kNone;
+  }
+  base::UmaHistogramEnumeration("PasswordManager.PasswordEditUpdatedValues",
+                                values);
+}
+
 }  // namespace metrics_util
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager_metrics_util.h b/components/password_manager/core/browser/password_manager_metrics_util.h
index 9f70069..2cfe214 100644
--- a/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -17,6 +17,9 @@
 
 namespace metrics_util {
 
+using IsUsernameChanged = util::StrongAlias<class IsUsernameChangedTag, bool>;
+using IsPasswordChanged = util::StrongAlias<class IsPasswordChangedTag, bool>;
+
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
 // Metrics: "PasswordBubble.DisplayDisposition"
@@ -473,6 +476,20 @@
   kMaxValue = kGroupUrlOverrideUsed,
 };
 
+// Used to record what exactly was updated during password editing flow.
+// Entries should not be renumbered and numeric values should never be reused.
+enum class PasswordEditUpdatedValues {
+  // Nothing was updated.
+  kNone = 0,
+  // Only username was changed.
+  kUsername = 1,
+  // Only password was changed.
+  kPassword = 2,
+  // Both password and username were updated.
+  kBoth = 3,
+  kMaxValue = kBoth,
+};
+
 std::string GetPasswordAccountStorageUserStateHistogramSuffix(
     PasswordAccountStorageUserState user_state);
 
@@ -619,6 +636,10 @@
 
 #endif
 
+// Log the result of the password edit action.
+void LogPasswordEditResult(IsUsernameChanged password_changed,
+                           IsPasswordChanged username_changed);
+
 }  // namespace metrics_util
 
 }  // namespace password_manager
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index 07e15b07..f3959c7 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -223,7 +223,7 @@
   if (event.GetType() == blink::WebInputEvent::Type::kContextMenu) {
     if (delegate_) {
       const WebMouseEvent& mouse_event =
-          reinterpret_cast<const WebMouseEvent&>(event);
+          static_cast<const WebMouseEvent&>(event);
       delegate_->ShowContextMenu(mouse_event);
     }
     return blink::WebInputEventResult::kHandledSuppressed;
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 65f28da..f8b9ee2 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -9348,14 +9348,9 @@
         'admin-sharing',
         'google-sharing',
       ],
-      'desc': '''Controls whether usage metrics and diagnostic data, including crash reports, are reported back to Google.
+      'desc': '''Setting the policy to Enabled has <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> report usage metrics and diagnostic data, including crash reports, back to Google. Setting the policy to Disabled turns off metrics and diagnostic data reporting.
 
-      If set to true, <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> will report usage metrics and diagnostic data.
-
-      If set to false, metrics and diagnostic data reporting will be disabled.
-
-      If not configured, metrics and diagnostic data reporting will be disabled on unmanaged devices and enabled on managed devices.''',
-
+       Leaving the policy unset keeps metrics and diagnostic data reporting off on unmanaged devices and on for managed devices.''',
       'arc_support': 'This policy also controls Android usage and diagnostic data collection.',
     },
     {
@@ -23415,7 +23410,29 @@
       - Format the URL patterns according to this format ( https://www.chromium.org/administrators/url-blacklist-filter-format ).
 
       If the policy is left not set, no restrictions will be applied.''',
-    }
+    },
+    {
+      'name': 'WebRtcAllowLegacyTLSProtocols',
+      'owners': ['hta@chromium.org', 'guidou@chromium.org'],
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome.*:87-', 'chrome_os:87-'],
+      'features': {
+        'dynamic_refresh': False,
+        'per_profile': False,
+      },
+      'example_value': False,
+      'id': 787,
+      'caption': '''Allow legacy TLS/DTLS downgrade in WebRTC''',
+      'tags': [],
+      'desc': '''If enabled, WebRTC peer connections can downgrade to obsolete
+      versions of the TLS/DTLS (DTLS 1.0, TLS 1.0 and TLS 1.1) protocols.
+      When this policy is disabled or not set, these TLS/DTLS versions are
+      disabled.
+
+      This policy is temporary and will be removed in a future version
+      of <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph>.''',
+    },
   ],
 
   'messages': {
@@ -24340,6 +24357,6 @@
   ],
   'placeholders': [],
   'deleted_policy_ids': [114, 115, 412, 476, 544, 546, 562, 569, 578],
-  'highest_id_currently_used': 786,
+  'highest_id_currently_used': 787,
   'highest_atomic_group_id_currently_used': 40
 }
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index 0f639fdb..c93f5ecf 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -571,13 +571,16 @@
 
   <!-- Strings for Data Leak Prevention -->
   <message name="IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE" desc="A toast informing the user that paste is blocked.">
-    Pasting to this location is blocked by your administrator
+    Pasting from <ph name="ORIGIN_NAME">$1<ex>corp.google.com</ex></ph> to this location is blocked by your administrator
   </message>
   <message name="IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM" desc="A toast informing the user that sharing clipboard data to VMs is blocked.">
-    Your administrator has blocked sharing this content to <ph name="VM_NAME">$1<ex>Linux</ex></ph>
+    Your administrator has blocked sharing from <ph name="ORIGIN_NAME">$1<ex>corp.google.com</ex></ph> to <ph name="VM_NAME">$2<ex>Linux</ex></ph>
   </message>
   <message name="IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_TWO_VMS" desc="A toast informing the user that sharing clipboard data to VMs is blocked.">
-    Your administrator has blocked sharing this content to <ph name="VM_NAME_1">$1<ex>Linux</ex></ph> and <ph name="VM_NAME_2">$2<ex>Parallels</ex></ph>
+    Your administrator has blocked sharing from <ph name="ORIGIN_NAME">$1<ex>corp.google.com</ex></ph> to <ph name="VM_NAME_1">$2<ex>Linux</ex></ph> and <ph name="VM_NAME_2">$3<ex>Parallels</ex></ph>
+  </message>
+  <message name="IDS_POLICY_DLP_ANDROID_APPS" desc="Name shown for ARC in data leak prevention toasts.">
+    Android apps
   </message>
   <message name="IDS_POLICY_DLP_PRINTING_BLOCKED" desc="A toast informing the user that printing is blocked.">
     Printing of this content is blocked by your administrator
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_ANDROID_APPS.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_ANDROID_APPS.png.sha1
new file mode 100644
index 0000000..1deee24
--- /dev/null
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_ANDROID_APPS.png.sha1
@@ -0,0 +1 @@
+c8b41368266afc8b1d606cea145ddc2c5ab62527
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_TWO_VMS.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_TWO_VMS.png.sha1
index 7118f95..bd19021 100644
--- a/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_TWO_VMS.png.sha1
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_TWO_VMS.png.sha1
@@ -1 +1 @@
-ba7801e163005f543316c314426956e16845fc59
\ No newline at end of file
+022ba1ffbe4205b99e454b5f24bbef05ba3d7d9e
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM.png.sha1
index ad4d6cdd..61838f2 100644
--- a/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM.png.sha1
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_COPY_VM.png.sha1
@@ -1 +1 @@
-4515755cb0f170f6853402d1950084b03ddd0af2
\ No newline at end of file
+dc8420bbab243a1ccc2442778128a5ff7ae2fa9c
\ No newline at end of file
diff --git a/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE.png.sha1 b/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE.png.sha1
index 5a473a2..d5d99c9e 100644
--- a/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE.png.sha1
+++ b/components/policy_strings_grdp/IDS_POLICY_DLP_CLIPBOARD_BLOCKED_ON_PASTE.png.sha1
@@ -1 +1 @@
-dafd5167bf4927eefb41f21f0457e9b1591f78de
\ No newline at end of file
+311127f5b9c8e964067c9805ae7f86d559ec2a6d
\ No newline at end of file
diff --git a/components/signin/ios/browser/account_consistency_service.mm b/components/signin/ios/browser/account_consistency_service.mm
index e6440c33..f321946f 100644
--- a/components/signin/ios/browser/account_consistency_service.mm
+++ b/components/signin/ios/browser/account_consistency_service.mm
@@ -26,6 +26,8 @@
 #include "ios/web/common/web_view_creation_util.h"
 #include "ios/web/public/browser_state.h"
 #import "ios/web/public/navigation/web_state_policy_decider.h"
+#import "ios/web/public/web_state.h"
+#include "ios/web/public/web_state_observer.h"
 #include "net/base/mac/url_conversions.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/cookies/canonical_cookie.h"
@@ -63,14 +65,22 @@
 // reacting on the X-Chrome-Manage-Accounts header and notifying its delegate.
 // It also notifies the AccountConsistencyService of domains it should add the
 // CHROME_CONNECTED cookie to.
-class AccountConsistencyHandler : public web::WebStatePolicyDecider {
+class AccountConsistencyHandler : public web::WebStatePolicyDecider,
+                                  public web::WebStateObserver {
  public:
   AccountConsistencyHandler(web::WebState* web_state,
                             AccountConsistencyService* service,
                             AccountReconcilor* account_reconcilor,
                             id<ManageAccountsDelegate> delegate);
 
+  void WebStateDestroyed(web::WebState* web_state) override;
+
  private:
+  // web::WebStateObserver override.
+  void PageLoaded(
+      web::WebState* web_state,
+      web::PageLoadCompletionStatus load_completion_status) override;
+
   // web::WebStatePolicyDecider override.
   // Decides on navigation corresponding to |response| whether the navigation
   // should continue and updates authentication cookies on Google domains.
@@ -80,6 +90,7 @@
       base::OnceCallback<void(PolicyDecision)> callback) override;
   void WebStateDestroyed() override;
 
+  bool show_consistency_promo_ = false;
   AccountConsistencyService* account_consistency_service_;  // Weak.
   AccountReconcilor* account_reconcilor_;                   // Weak.
   __weak id<ManageAccountsDelegate> delegate_;
@@ -94,7 +105,9 @@
     : web::WebStatePolicyDecider(web_state),
       account_consistency_service_(service),
       account_reconcilor_(account_reconcilor),
-      delegate_(delegate) {}
+      delegate_(delegate) {
+  web_state->AddObserver(this);
+}
 
 void AccountConsistencyHandler::ShouldAllowResponse(
     NSURLResponse* response,
@@ -134,6 +147,11 @@
       base::SysNSStringToUTF8(manage_accounts_header));
 
   account_reconcilor_->OnReceivedManageAccountsResponse(params.service_type);
+  // Reset boolean that tracks displaying the sign-in consistency promo. This
+  // ensures that the promo is cancelled once navigation has started and the
+  // WKWebView is cancelling previous navigations.
+  show_consistency_promo_ = false;
+
   switch (params.service_type) {
     case signin::GAIA_SERVICE_TYPE_INCOGNITO: {
       GURL continue_url = GURL(params.continue_url);
@@ -145,7 +163,12 @@
     case signin::GAIA_SERVICE_TYPE_SIGNUP:
     case signin::GAIA_SERVICE_TYPE_ADDSESSION:
       if (params.show_consistency_promo) {
-        [delegate_ onShowConsistencyPromo];
+        show_consistency_promo_ = true;
+        // Allows the URL response to load before showing the consistency promo.
+        // The promo should always be displayed in the foreground of Gaia
+        // sign-on.
+        std::move(callback).Run(PolicyDecision::Allow());
+        return;
       } else {
         [delegate_ onAddAccount];
       }
@@ -169,6 +192,20 @@
   std::move(callback).Run(PolicyDecision::Cancel());
 }
 
+void AccountConsistencyHandler::PageLoaded(
+    web::WebState* web_state,
+    web::PageLoadCompletionStatus load_completion_status) {
+  if (!show_consistency_promo_ ||
+      !gaia::IsGaiaSignonRealm(web_state->GetLastCommittedURL().GetOrigin()) ||
+      load_completion_status == web::PageLoadCompletionStatus::FAILURE) {
+    return;
+  }
+  [delegate_ onShowConsistencyPromo];
+  show_consistency_promo_ = false;
+}
+
+void AccountConsistencyHandler::WebStateDestroyed(web::WebState* web_state) {}
+
 void AccountConsistencyHandler::WebStateDestroyed() {
   account_consistency_service_->RemoveWebStateHandler(web_state());
 }
@@ -222,6 +259,8 @@
 void AccountConsistencyService::RemoveWebStateHandler(
     web::WebState* web_state) {
   DCHECK_LT(0u, web_state_handlers_.count(web_state));
+  web_state->RemoveObserver(
+      (AccountConsistencyHandler*)web_state_handlers_[web_state].get());
   web_state_handlers_.erase(web_state);
 }
 
diff --git a/components/signin/ios/browser/account_consistency_service_unittest.mm b/components/signin/ios/browser/account_consistency_service_unittest.mm
index d256525..e3645053 100644
--- a/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -276,6 +276,13 @@
                        /*domain=*/std::string()));
   }
 
+  // Simulate navigating to a URL with the given page load completion status.
+  void SimulateNavigateToUrl(web::PageLoadCompletionStatus status,
+                             const GURL& url) {
+    web_state_.SetCurrentURL(url);
+    web_state_.OnPageLoaded(status);
+  }
+
   // Simulate the action of the action GaiaCookieManagerService to cleanup
   // the cookies once the sign-out is done.
   void SimulateGaiaCookieManagerServiceLogout() {
@@ -467,8 +474,111 @@
   EXPECT_CALL(*account_reconcilor_, OnReceivedManageAccountsResponse(
                                         signin::GAIA_SERVICE_TYPE_ADDSESSION))
       .Times(1);
-  EXPECT_FALSE(
+  EXPECT_TRUE(
       web_state_.ShouldAllowResponse(response, /* for_main_frame = */ true));
+  SimulateNavigateToUrl(web::PageLoadCompletionStatus::SUCCESS,
+                        GURL("https://accounts.google.com/"));
+  web_state_.WebStateDestroyed();
+
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that the consistency promo is not displayed when a page fails to load.
+TEST_F(AccountConsistencyServiceTest,
+       ChromeManageAccountsNotShowConsistencyPromoOnPageLoadFailure) {
+  id delegate =
+      [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
+  [[delegate reject] onShowConsistencyPromo];
+
+  NSDictionary* headers = [NSDictionary
+      dictionaryWithObject:@"action=ADDSESSION,show_consistency_promo=true"
+                    forKey:@"X-Chrome-Manage-Accounts"];
+  NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
+       initWithURL:[NSURL URLWithString:@"https://accounts.google.com/"]
+        statusCode:200
+       HTTPVersion:@"HTTP/1.1"
+      headerFields:headers];
+  account_consistency_service_->SetWebStateHandler(&web_state_, delegate);
+  EXPECT_CALL(*account_reconcilor_, OnReceivedManageAccountsResponse(
+                                        signin::GAIA_SERVICE_TYPE_ADDSESSION))
+      .Times(1);
+  EXPECT_TRUE(
+      web_state_.ShouldAllowResponse(response, /* for_main_frame = */ true));
+  SimulateNavigateToUrl(web::PageLoadCompletionStatus::FAILURE,
+                        GURL("https://accounts.google.com/"));
+  web_state_.WebStateDestroyed();
+
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that the consistency promo is not displayed when a page fails to load
+// and user chooses another action.
+TEST_F(AccountConsistencyServiceTest,
+       ChromeManageAccountsNotShowConsistencyPromoOnPageLoadFailureRedirect) {
+  id delegate =
+      [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
+  [[delegate expect] onAddAccount];
+  [[delegate reject] onShowConsistencyPromo];
+
+  NSDictionary* headers = [NSDictionary
+      dictionaryWithObject:@"action=ADDSESSION,show_consistency_promo=true"
+                    forKey:@"X-Chrome-Manage-Accounts"];
+  account_consistency_service_->SetWebStateHandler(&web_state_, delegate);
+  EXPECT_CALL(*account_reconcilor_, OnReceivedManageAccountsResponse(
+                                        signin::GAIA_SERVICE_TYPE_ADDSESSION))
+      .Times(2);
+
+  NSHTTPURLResponse* responseSignin = [[NSHTTPURLResponse alloc]
+       initWithURL:[NSURL URLWithString:@"https://accounts.google.com/"]
+        statusCode:200
+       HTTPVersion:@"HTTP/1.1"
+      headerFields:headers];
+  EXPECT_TRUE(web_state_.ShouldAllowResponse(responseSignin,
+                                             /* for_main_frame = */ true));
+  const GURL accountsUrl = GURL("https://accounts.google.com/");
+  SimulateNavigateToUrl(web::PageLoadCompletionStatus::FAILURE, accountsUrl);
+
+  NSDictionary* headersAddAccount =
+      [NSDictionary dictionaryWithObject:@"action=ADDSESSION"
+                                  forKey:@"X-Chrome-Manage-Accounts"];
+  NSHTTPURLResponse* responseAddAccount = [[NSHTTPURLResponse alloc]
+       initWithURL:[NSURL URLWithString:@"https://accounts.google.com/"]
+        statusCode:200
+       HTTPVersion:@"HTTP/1.1"
+      headerFields:headersAddAccount];
+  EXPECT_FALSE(web_state_.ShouldAllowResponse(responseAddAccount,
+                                              /* for_main_frame = */ true));
+  SimulateNavigateToUrl(web::PageLoadCompletionStatus::SUCCESS, accountsUrl);
+
+  web_state_.WebStateDestroyed();
+
+  EXPECT_OCMOCK_VERIFY(delegate);
+}
+
+// Tests that the consistency promo is not displayed when a non GAIA URL is
+// committed.
+TEST_F(AccountConsistencyServiceTest,
+       ChromeManageAccountsNotShowConsistencyPromoOnNonGaiaURL) {
+  id delegate =
+      [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
+  [[delegate reject] onShowConsistencyPromo];
+
+  NSDictionary* headers = [NSDictionary
+      dictionaryWithObject:@"action=ADDSESSION,show_consistency_promo=true"
+                    forKey:@"X-Chrome-Manage-Accounts"];
+  NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
+       initWithURL:[NSURL URLWithString:@"https://accounts.google.com/"]
+        statusCode:200
+       HTTPVersion:@"HTTP/1.1"
+      headerFields:headers];
+  account_consistency_service_->SetWebStateHandler(&web_state_, delegate);
+  EXPECT_CALL(*account_reconcilor_, OnReceivedManageAccountsResponse(
+                                        signin::GAIA_SERVICE_TYPE_ADDSESSION))
+      .Times(1);
+  EXPECT_TRUE(
+      web_state_.ShouldAllowResponse(response, /* for_main_frame = */ true));
+  SimulateNavigateToUrl(web::PageLoadCompletionStatus::SUCCESS,
+                        GURL("https://youtube.com/"));
   web_state_.WebStateDestroyed();
 
   EXPECT_OCMOCK_VERIFY(delegate);
@@ -680,5 +790,6 @@
       headerFields:headers];
   EXPECT_TRUE(web_state_.ShouldAllowResponse(responseGaia,
                                              /* for_main_frame = */ true));
+  web_state_.WebStateDestroyed();
   CheckDomainHasChromeConnectedCookie("google.com");
 }
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
index b98601d..779139e7 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
@@ -42,10 +42,11 @@
 // within a given WebContents. It contains a mapping of all activated
 // RenderFrameHosts, along with their associated DocumentSubresourceFilters.
 //
-// The class is designed to be used by a Delegate, which shares lifetime with
-// this class (aka the typical lifetime of a WebContentsObserver). The delegate
-// will be notified of the first disallowed subresource load for a top level
-// navgation, and has veto power for frame activation.
+// The class is designed to be used by a SubresourceFilterClient instance that
+// shares lifetime with this class (aka the typical lifetime of a
+// WebContentsObserver). The client will be notified of the first disallowed
+// subresource load for a top level navgation, and has veto power for frame
+// activation.
 class ContentSubresourceFilterThrottleManager
     : public content::WebContentsObserver,
       public mojom::SubresourceFilterHost,
diff --git a/components/sync/driver/glue/sync_engine_impl.cc b/components/sync/driver/glue/sync_engine_impl.cc
index 126ffacc..b5f0f89 100644
--- a/components/sync/driver/glue/sync_engine_impl.cc
+++ b/components/sync/driver/glue/sync_engine_impl.cc
@@ -31,6 +31,7 @@
 #include "components/sync/engine/sync_manager_factory.h"
 #include "components/sync/engine/sync_string_conversions.h"
 #include "components/sync/invalidations/fcm_handler.h"
+#include "components/sync/invalidations/switches.h"
 #include "components/sync/invalidations/sync_invalidations_service.h"
 
 namespace syncer {
@@ -44,9 +45,29 @@
     : name_(name),
       sync_prefs_(sync_prefs),
       invalidator_(invalidator),
-      sync_invalidations_service_(sync_invalidations_service) {
+      sync_invalidations_service_(sync_invalidations_service),
+#if defined(OS_ANDROID)
+      sessions_invalidation_enabled_(false) {
+#else
+      sessions_invalidation_enabled_(true) {
+#endif
   backend_ = base::MakeRefCounted<SyncEngineBackend>(
       name_, sync_data_folder, weak_ptr_factory_.GetWeakPtr());
+
+  // If the new invalidations system (SyncInvalidationsService) is fully
+  // enabled, then the SyncService doesn't need to communicate with the old
+  // InvalidationService anymore.
+  if (invalidator_ &&
+      base::FeatureList::IsEnabled(switches::kSyncSendInterestedDataTypes) &&
+      base::FeatureList::IsEnabled(switches::kUseSyncInvalidations) &&
+      base::FeatureList::IsEnabled(
+          switches::kUseSyncInvalidationsForWalletAndOffer)) {
+    invalidator_->RegisterInvalidationHandler(this);
+    bool success = invalidator_->UpdateInterestedTopics(this, /*topics=*/{});
+    DCHECK(success);
+    invalidator_->UnregisterInvalidationHandler(this);
+    invalidator_ = nullptr;
+  }
 }
 
 SyncEngineImpl::~SyncEngineImpl() {
@@ -285,19 +306,7 @@
     const ModelTypeSet failed_configuration_types,
     base::OnceCallback<void(ModelTypeSet, ModelTypeSet)> ready_task) {
   last_enabled_types_ = enabled_types;
-  if (invalidator_) {
-    // No need to register invalidations for CommitOnlyTypes().
-    ModelTypeSet invalidation_enabled_types(
-        Difference(enabled_types, CommitOnlyTypes()));
-#if defined(OS_ANDROID)
-    if (!sessions_invalidation_enabled_) {
-      invalidation_enabled_types.Remove(syncer::SESSIONS);
-    }
-#endif
-    bool success = invalidator_->UpdateInterestedTopics(
-        this, ModelTypeSetToTopicSet(invalidation_enabled_types));
-    DCHECK(success);
-  }
+  SendInterestedTopicsToInvalidator();
 
   if (!ready_task.is_null()) {
     std::move(ready_task)
@@ -324,6 +333,7 @@
 
     // Fake a state change to initialize the SyncManager's cached invalidator
     // state.
+    // TODO(crbug.com/1132868): Do this for the new invalidations as well.
     OnInvalidatorStateChange(invalidator_->GetInvalidatorState());
   }
 
@@ -445,20 +455,7 @@
 
 void SyncEngineImpl::SetInvalidationsForSessionsEnabled(bool enabled) {
   sessions_invalidation_enabled_ = enabled;
-  // TODO(crbug.com/1050970): unify logic here and in
-  // FinishConfigureDataTypesOnFrontedLoop() and factor it out.
-  // |last_enabled_types_| contains all datatypes, for which user
-  // has enabled Sync. There is no need to register invalidations for
-  // CommitOnlyTypes(), so they are filtered out.
-  ModelTypeSet enabled_for_invalidation(
-      Difference(last_enabled_types_, CommitOnlyTypes()));
-  if (!enabled) {
-    enabled_for_invalidation.Remove(syncer::SESSIONS);
-  }
-  bool success = invalidator_->UpdateInterestedTopics(
-      this, ModelTypeSetToTopicSet(enabled_for_invalidation));
-  DCHECK(success);
-  // TODO(crbug.com/1102312): update enabled data types for sync invalidations.
+  SendInterestedTopicsToInvalidator();
 }
 
 void SyncEngineImpl::GetNigoriNodeForDebugging(AllNodesCallback callback) {
@@ -490,4 +487,28 @@
   std::move(callback).Run();
 }
 
+void SyncEngineImpl::SendInterestedTopicsToInvalidator() {
+  if (!invalidator_) {
+    return;
+  }
+
+  // No need to register invalidations for CommitOnlyTypes().
+  ModelTypeSet invalidation_enabled_types(
+      Difference(last_enabled_types_, CommitOnlyTypes()));
+  if (!sessions_invalidation_enabled_) {
+    invalidation_enabled_types.Remove(syncer::SESSIONS);
+  }
+  // switches::kUseSyncInvalidations means that the new invalidations system is
+  // used for all data types except Wallet and Offer, so only keep these types.
+  if (base::FeatureList::IsEnabled(switches::kSyncSendInterestedDataTypes) &&
+      base::FeatureList::IsEnabled(switches::kUseSyncInvalidations)) {
+    invalidation_enabled_types.RetainAll(
+        {AUTOFILL_WALLET_DATA, AUTOFILL_WALLET_OFFER});
+  }
+
+  bool success = invalidator_->UpdateInterestedTopics(
+      this, ModelTypeSetToTopicSet(invalidation_enabled_types));
+  DCHECK(success);
+}
+
 }  // namespace syncer
diff --git a/components/sync/driver/glue/sync_engine_impl.h b/components/sync/driver/glue/sync_engine_impl.h
index c753a98..bd33225 100644
--- a/components/sync/driver/glue/sync_engine_impl.h
+++ b/components/sync/driver/glue/sync_engine_impl.h
@@ -186,6 +186,8 @@
 
   void OnCookieJarChangedDoneOnFrontendLoop(base::OnceClosure callback);
 
+  void SendInterestedTopicsToInvalidator();
+
   // The task runner where all the sync engine operations happen.
   scoped_refptr<base::SequencedTaskRunner> sync_task_runner_;
 
@@ -222,7 +224,7 @@
   SyncInvalidationsService* sync_invalidations_service_ = nullptr;
 
   ModelTypeSet last_enabled_types_;
-  bool sessions_invalidation_enabled_ = false;
+  bool sessions_invalidation_enabled_;
 
   SyncStatus cached_status_;
 
diff --git a/components/sync/driver/glue/sync_engine_impl_unittest.cc b/components/sync/driver/glue/sync_engine_impl_unittest.cc
index dd3eab87..9eecc10 100644
--- a/components/sync/driver/glue/sync_engine_impl_unittest.cc
+++ b/components/sync/driver/glue/sync_engine_impl_unittest.cc
@@ -340,6 +340,21 @@
   NiceMock<MockSyncInvalidationsService> mock_instance_id_driver_;
 };
 
+class SyncEngineImplWithSyncInvalidationsForWalletAndOfferTest
+    : public SyncEngineImplTest {
+ public:
+  SyncEngineImplWithSyncInvalidationsForWalletAndOfferTest() {
+    override_features_.InitWithFeatures(
+        /*enabled_features=*/{switches::kSyncSendInterestedDataTypes,
+                              switches::kUseSyncInvalidations,
+                              switches::kUseSyncInvalidationsForWalletAndOffer},
+        /*disabled_features=*/{});
+  }
+
+ protected:
+  base::test::ScopedFeatureList override_features_;
+};
+
 // Test basic initialization with no initial types (first time initialization).
 // Only the nigori should be configured.
 TEST_F(SyncEngineImplTest, InitShutdown) {
@@ -678,6 +693,32 @@
   EXPECT_EQ(1, fake_manager_->GetInvalidationCount(ModelType::PREFERENCES));
 }
 
+TEST_F(SyncEngineImplWithSyncInvalidationsTest,
+       UseOldInvalidationsOnlyForWalletAndOffer) {
+  enabled_types_.PutAll({AUTOFILL_WALLET_DATA, AUTOFILL_WALLET_OFFER});
+
+  InitializeBackend(/*expect_success=*/true);
+  EXPECT_CALL(
+      invalidator_,
+      UpdateInterestedTopics(
+          backend_.get(), ModelTypeSetToTopicSet(
+                              {AUTOFILL_WALLET_DATA, AUTOFILL_WALLET_OFFER})));
+  ConfigureDataTypes();
+
+  // At shutdown, we clear the registered invalidation ids.
+  EXPECT_CALL(invalidator_, UpdateInterestedTopics(backend_.get(), TopicSet()));
+}
+
+TEST_F(SyncEngineImplWithSyncInvalidationsForWalletAndOfferTest,
+       DoNotUseOldInvalidationsAtAll) {
+  enabled_types_.PutAll({AUTOFILL_WALLET_DATA, AUTOFILL_WALLET_OFFER});
+
+  InitializeBackend(/*expect_success=*/true);
+  EXPECT_CALL(invalidator_, UpdateInterestedTopics(testing::_, testing::_))
+      .Times(0);
+  ConfigureDataTypes();
+}
+
 }  // namespace
 
 }  // namespace syncer
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index ca6816a..127b899 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -1459,8 +1459,9 @@
     return;
   }
 
-  // No need to register invalidations for commit-only types.
-  ModelTypeSet types = Difference(GetDataTypesToConfigure(), CommitOnlyTypes());
+  // No need to register invalidations for non-protocol or commit-only types.
+  ModelTypeSet types = Intersection(GetDataTypesToConfigure(), ProtocolTypes());
+  types.RemoveAll(CommitOnlyTypes());
   if (!sessions_invalidations_enabled_) {
     types.Remove(SESSIONS);
   }
diff --git a/components/sync/invalidations/switches.h b/components/sync/invalidations/switches.h
index 26e27d3..75f3074 100644
--- a/components/sync/invalidations/switches.h
+++ b/components/sync/invalidations/switches.h
@@ -16,12 +16,15 @@
 // If enabled, the device will register with FCM and listen to new
 // invalidations. Also, FCM token will be set in DeviceInfo, which signals to
 // the server that device listens to new invalidations.
+// The device will not subscribe to old invalidations for any data types except
+// Wallet and Offer, since that will be covered by the new system.
 // SyncSendInterestedDataTypes must be enabled for this to take effect.
 extern const base::Feature kUseSyncInvalidations;
 
 // If enabled, types related to Wallet and Offer will be included in interested
 // data types, and the device will listen to new invalidations for those types
 // (if they are enabled).
+// The device will not register for old invalidations at all.
 // UseSyncInvalidations must be enabled for this to take effect.
 extern const base::Feature kUseSyncInvalidationsForWalletAndOffer;
 
diff --git a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index 4c8cf3f..ff551d5f 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -263,10 +263,9 @@
   }
 
   sync_pb::BookmarkModelMetadata BuildBookmarkModelMetadataWithoutFullTitles() {
-    base::test::ScopedFeatureList features;
-    features.InitAndDisableFeature(switches::kSyncReuploadBookmarkFullTitles);
     sync_pb::BookmarkModelMetadata model_metadata =
         processor()->GetTrackerForTest()->BuildBookmarkModelMetadata();
+    model_metadata.clear_bookmarks_full_title_reuploaded();
     return model_metadata;
   }
 
diff --git a/components/sync_bookmarks/switches.cc b/components/sync_bookmarks/switches.cc
index 12e7704..16812cc 100644
--- a/components/sync_bookmarks/switches.cc
+++ b/components/sync_bookmarks/switches.cc
@@ -10,7 +10,7 @@
     "SyncDoNotCommitBookmarksWithoutFavicon", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kSyncReuploadBookmarkFullTitles{
-    "SyncReuploadBookmarkFullTitles", base::FEATURE_DISABLED_BY_DEFAULT};
+    "SyncReuploadBookmarkFullTitles", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kSyncDeduplicateAllBookmarksWithSameGUID{
     "SyncDeduplicateAllBookmarksWithSameGUID",
diff --git a/components/url_formatter/url_fixer.cc b/components/url_formatter/url_fixer.cc
index 70aedd34..125a2f1 100644
--- a/components/url_formatter/url_fixer.cc
+++ b/components/url_formatter/url_fixer.cc
@@ -394,6 +394,9 @@
 
   // We need to fix up the segmentation for "www.example.com:/".  For this
   // case, we guess that schemes with a "." are not actually schemes.
+  //
+  // Note: This logic deviates from GURL, where "www.example.com:" would be
+  // parsed as having "www.example.com" as the scheme with an empty hostname.
   if (canon_scheme->find('.') != std::string::npos)
     return false;
 
diff --git a/components/url_formatter/url_fixer.h b/components/url_formatter/url_fixer.h
index b7c592d39..8e3e5fd 100644
--- a/components/url_formatter/url_fixer.h
+++ b/components/url_formatter/url_fixer.h
@@ -19,10 +19,13 @@
 struct Parsed;
 }
 
-// This object is designed to convert various types of input into URLs that we
-// know are valid. For example, user typing in the URL bar or command line
-// options. This is NOT the place for converting between different types of URLs
-// or parsing them, see net_util.h for that.
+// These methods process user typed input that is meant to be a URL - like user
+// typing in the URL bar or command line switches. The output is NOT guaranteed
+// to be a valid URL.
+//
+// This is NOT the place for converting between different types of URLs or
+// parsing them, see net_util.h for that. These methods should only be used on
+// user typed input, NOT untrusted strings sourced from the web or elsewhere.
 namespace url_formatter {
 
 // Segments the given text string into parts of a URL. This is most useful for
@@ -33,13 +36,15 @@
 std::string SegmentURL(const std::string& text, url::Parsed* parts);
 base::string16 SegmentURL(const base::string16& text, url::Parsed* parts);
 
-// Converts |text| to a fixed-up URL and returns it. Attempts to make some
-// "smart" adjustments to obviously-invalid input where possible.
-// |text| may be an absolute path to a file, which will get converted to a
-// "file:" URL.
+// Attempts to fix common problems in user-typed text, making some "smart"
+// adjustments to obviously-invalid input where possible.
 //
-// The result will be a "more" valid URL than the input. It may still not be
-// valid, so check the return value's validity or use possibly_invalid_spec().
+// The result can still be invalid, so check the return value's validity or
+// use possibly_invalid_spec(). DO NOT USE this method on untrusted strings
+// from the web or elsewhere. Only use this for user-typed input.
+//
+// If |text| may be an absolute path to a file, it will get converted to a
+// "file:" URL.
 //
 // Schemes "about" and "chrome" are normalized to "chrome://", with slashes.
 // "about:blank" is unaltered, as Webkit allows frames to access about:blank.
diff --git a/components/variations/net/variations_http_headers.cc b/components/variations/net/variations_http_headers.cc
index 5ff5a3db..e71505f9 100644
--- a/components/variations/net/variations_http_headers.cc
+++ b/components/variations/net/variations_http_headers.cc
@@ -196,8 +196,7 @@
     const network::ResourceRequest& resource_request) {
   bool use_first_party_visibility =
       IsFirstPartyContext(owner, resource_request) &&
-      VariationsIdsProvider::GetInstance()
-          ->IsRestrictGoogleWebVisibilityEnabled();
+      base::FeatureList::IsEnabled(internal::kRestrictGoogleWebVisibility);
 
   return use_first_party_visibility
              ? variations::mojom::GoogleWebVisibility::FIRST_PARTY
diff --git a/components/variations/variations_ids_provider.cc b/components/variations/variations_ids_provider.cc
index b0a531d..9752559 100644
--- a/components/variations/variations_ids_provider.cc
+++ b/components/variations/variations_ids_provider.cc
@@ -215,13 +215,8 @@
   if (variation_ids_cache_initialized_)
     return;
 
-  // Must be done before AddObserver() to avoid deadlock in
-  // OnFieldTrialGroupFinalized().
-  is_restrict_google_web_visibility_enabled_ =
-      base::FeatureList::IsEnabled(internal::kRestrictGoogleWebVisibility);
-
-  // Register for additional cache updates. This is done before initializing the
-  // cache to avoid a race that could cause registered FieldTrials to be missed.
+  // Register for additional cache updates. This is done first to avoid a race
+  // that could cause registered FieldTrials to be missed.
   bool success = base::FieldTrialList::AddObserver(this);
   DCHECK(success);
 
@@ -295,7 +290,8 @@
         proto.add_variation_id(entry.first);
         break;
       case GOOGLE_WEB_PROPERTIES_FIRST_PARTY:
-        if (IsRestrictGoogleWebVisibilityEnabled()) {
+        if (base::FeatureList::IsEnabled(
+                internal::kRestrictGoogleWebVisibility)) {
           if (is_first_party_context)
             proto.add_variation_id(entry.first);
         } else {
@@ -309,7 +305,8 @@
         proto.add_trigger_variation_id(entry.first);
         break;
       case GOOGLE_WEB_PROPERTIES_TRIGGER_FIRST_PARTY:
-        if (IsRestrictGoogleWebVisibilityEnabled()) {
+        if (base::FeatureList::IsEnabled(
+                internal::kRestrictGoogleWebVisibility)) {
           if (is_first_party_context)
             proto.add_trigger_variation_id(entry.first);
         } else {
diff --git a/components/variations/variations_ids_provider.h b/components/variations/variations_ids_provider.h
index 14afd29..0dbfc80 100644
--- a/components/variations/variations_ids_provider.h
+++ b/components/variations/variations_ids_provider.h
@@ -126,12 +126,6 @@
   // Resets any cached state for tests.
   void ResetForTesting();
 
-  // Returns true if kRestrictGoogleWebVisibility is enabled and false
-  // otherwise.
-  bool IsRestrictGoogleWebVisibilityEnabled() {
-    return is_restrict_google_web_visibility_enabled_;
-  }
-
  private:
   friend struct base::DefaultSingletonTraits<VariationsIdsProvider>;
 
@@ -227,9 +221,6 @@
   // Whether or not we've initialized the caches.
   bool variation_ids_cache_initialized_;
 
-  // Denotes whether kRestrictGoogleWebVisibility is enabled.
-  bool is_restrict_google_web_visibility_enabled_ = false;
-
   // Keep a cache of variation IDs that are transmitted in headers to Google.
   // This consists of a list of valid IDs, and the actual transmitted header.
   std::set<VariationIDEntry> variation_ids_set_;
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index 3324da8..e237e42 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -352,12 +352,11 @@
 
     // If we promote any quad to an underlay then the main plane must support
     // alpha.
-    // TODO(ccameron): We should update |frame_color_space|, and
+    // TODO(ccameron): We should update
+    // |root_render_pass->has_transparent_background|, |frame_color_space|, and
     // |frame_buffer_format| based on the change in |frame_has_alpha|.
-    if (current_frame()->output_surface_plane) {
+    if (current_frame()->output_surface_plane)
       frame_has_alpha |= current_frame()->output_surface_plane->enable_blending;
-      root_render_pass->has_transparent_background = frame_has_alpha;
-    }
 
     overlay_processor_->AdjustOutputSurfaceOverlay(
         &(current_frame()->output_surface_plane));
diff --git a/components/viz/service/display_embedder/output_presenter.cc b/components/viz/service/display_embedder/output_presenter.cc
index be04b31..a1ea3f8 100644
--- a/components/viz/service/display_embedder/output_presenter.cc
+++ b/components/viz/service/display_embedder/output_presenter.cc
@@ -115,14 +115,4 @@
   }
 }
 
-std::unique_ptr<OutputPresenter::Image>
-OutputPresenter::AllocateBackgroundImage(gfx::ColorSpace color_space,
-                                         gfx::Size image_size) {
-  return nullptr;
-}
-
-void OutputPresenter::ScheduleBackground(Image* image) {
-  NOTREACHED();
-}
-
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/output_presenter.h b/components/viz/service/display_embedder/output_presenter.h
index 7916c94..52b9ed3 100644
--- a/components/viz/service/display_embedder/output_presenter.h
+++ b/components/viz/service/display_embedder/output_presenter.h
@@ -86,9 +86,6 @@
       gfx::ColorSpace color_space,
       gfx::Size image_size,
       size_t num_images) = 0;
-  virtual std::unique_ptr<Image> AllocateBackgroundImage(
-      gfx::ColorSpace color_space,
-      gfx::Size image_size);
   virtual void SwapBuffers(SwapCompletionCallback completion_callback,
                            BufferPresentedCallback presentation_callback) = 0;
   virtual void PostSubBuffer(const gfx::Rect& rect,
@@ -105,7 +102,6 @@
       gpu::SharedImageRepresentationOverlay::ScopedReadAccess;
   virtual void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
                                 std::vector<ScopedOverlayAccess*> accesses) = 0;
-  virtual void ScheduleBackground(Image* image);
 };
 
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/output_presenter_gl.cc b/components/viz/service/display_embedder/output_presenter_gl.cc
index d1ef91a..d587bf4 100644
--- a/components/viz/service/display_embedder/output_presenter_gl.cc
+++ b/components/viz/service/display_embedder/output_presenter_gl.cc
@@ -17,7 +17,6 @@
 #include "ui/display/types/display_snapshot.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/overlay_transform.h"
 #include "ui/gl/gl_fence.h"
 #include "ui/gl/gl_surface.h"
 
@@ -283,20 +282,6 @@
   return images;
 }
 
-std::unique_ptr<OutputPresenter::Image>
-OutputPresenterGL::AllocateBackgroundImage(gfx::ColorSpace color_space,
-                                           gfx::Size image_size) {
-  auto image = std::make_unique<PresenterImageGL>();
-  if (!image->Initialize(shared_image_factory_,
-                         shared_image_representation_factory_, image_size,
-                         color_space, image_format_, dependency_,
-                         shared_image_usage_)) {
-    DLOG(ERROR) << "Failed to initialize image.";
-    return nullptr;
-  }
-  return image;
-}
-
 void OutputPresenterGL::SwapBuffers(
     SwapCompletionCallback completion_callback,
     BufferPresentedCallback presentation_callback) {
@@ -344,22 +329,6 @@
                                     plane.enable_blending, std::move(fence));
 }
 
-void OutputPresenterGL::ScheduleBackground(Image* image) {
-  // Background is not seen by user, and is created before buffer queue buffers.
-  // So fence is not needed.
-  auto* gl_image =
-      reinterpret_cast<PresenterImageGL*>(image)->GetGLImage(nullptr);
-
-  // Background is also z-order 0.
-  constexpr int kPlaneZOrder = INT32_MIN;
-  // Background always uses the full texture.
-  constexpr gfx::RectF kUVRect(0.f, 0.f, 1.0f, 1.0f);
-  gl_surface_->ScheduleOverlayPlane(
-      kPlaneZOrder, gfx::OVERLAY_TRANSFORM_NONE, gl_image, gfx::Rect(),
-      /*crop_rect=*/kUVRect,
-      /*enable_blend=*/false, /*gpu_fence=*/nullptr);
-}
-
 void OutputPresenterGL::CommitOverlayPlanes(
     SwapCompletionCallback completion_callback,
     BufferPresentedCallback presentation_callback) {
diff --git a/components/viz/service/display_embedder/output_presenter_gl.h b/components/viz/service/display_embedder/output_presenter_gl.h
index 7bf8c8b7..4cb0ef9a 100644
--- a/components/viz/service/display_embedder/output_presenter_gl.h
+++ b/components/viz/service/display_embedder/output_presenter_gl.h
@@ -49,8 +49,6 @@
       gfx::ColorSpace color_space,
       gfx::Size image_size,
       size_t num_images) final;
-  std::unique_ptr<Image> AllocateBackgroundImage(gfx::ColorSpace color_space,
-                                                 gfx::Size image_size) final;
   void SwapBuffers(SwapCompletionCallback completion_callback,
                    BufferPresentedCallback presentation_callback) final;
   void PostSubBuffer(const gfx::Rect& rect,
@@ -64,7 +62,6 @@
       bool is_submitted) final;
   void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
                         std::vector<ScopedOverlayAccess*> accesses) final;
-  void ScheduleBackground(Image* image) final;
 
  private:
   scoped_refptr<gl::GLSurface> gl_surface_;
diff --git a/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc b/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
index fc8a0df62..ce891e94 100644
--- a/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
+++ b/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
@@ -102,15 +102,13 @@
     SkiaOutputSurfaceDependency* deps,
     gpu::SharedImageRepresentationFactory* representation_factory,
     gpu::MemoryTracker* memory_tracker,
-    const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
-    bool needs_background_image)
+    const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback)
     : SkiaOutputDevice(deps->GetSharedContextState()->gr_context(),
                        memory_tracker,
                        did_swap_buffer_complete_callback),
       presenter_(std::move(presenter)),
       dependency_(deps),
-      representation_factory_(representation_factory),
-      needs_background_image_(needs_background_image) {
+      representation_factory_(representation_factory) {
   capabilities_.uses_default_gl_framebuffer = false;
   capabilities_.preserve_buffer_content = true;
   capabilities_.only_invalidates_damage_rect = false;
@@ -192,21 +190,6 @@
 void SkiaOutputDeviceBufferQueue::SchedulePrimaryPlane(
     const base::Optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane>&
         plane) {
-  if (background_image_) {
-    if (!background_image_is_scheduled_)
-      background_image_->BeginPresent();
-
-    // WaylandWindow can attach a null wl_buffer to its surface to hide its
-    // content so needs to reschedule |background_image_| so that
-    // the wl_surface has a non-null wl_buffer when the window re-appears.
-    //
-    // TODO(fangzhoug): It should not be necessary to schedule
-    // |background_image_| every frame. Make this a responsibility of
-    // WaylandWindow instead.
-    presenter_->ScheduleBackground(background_image_.get());
-    background_image_is_scheduled_ = true;
-  }
-
   if (plane) {
     // If the current_image_ is nullptr, it means there is no change on the
     // primary plane. So we just need to schedule the last submitted image.
@@ -437,12 +420,6 @@
   image_size_ = size;
   FreeAllSurfaces();
 
-  if (needs_background_image_ && !background_image_) {
-    background_image_ =
-        presenter_->AllocateBackgroundImage(color_space_, gfx::Size(4, 4));
-    background_image_is_scheduled_ = false;
-  }
-
   images_ = presenter_->AllocateImages(color_space_, image_size_,
                                        capabilities_.number_of_buffers);
   if (images_.empty())
diff --git a/components/viz/service/display_embedder/skia_output_device_buffer_queue.h b/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
index 9b439107..cf1e7604 100644
--- a/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
+++ b/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
@@ -30,8 +30,7 @@
       SkiaOutputSurfaceDependency* deps,
       gpu::SharedImageRepresentationFactory* representation_factory,
       gpu::MemoryTracker* memory_tracker,
-      const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
-      bool needs_background_image);
+      const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback);
 
   ~SkiaOutputDeviceBufferQueue() override;
 
@@ -124,13 +123,6 @@
 
   // Set to true if no image is to be used for the primary plane of this frame.
   bool current_frame_has_no_primary_plane_ = false;
-  // Whether the platform needs an occluded background image. Wayland needs it
-  // for opaque accelerated widgets and event wiring.
-  bool needs_background_image_ = false;
-  // A 4x4 small image that will be scaled to cover an opaque region.
-  std::unique_ptr<OutputPresenter::Image> background_image_ = nullptr;
-  // Set to true if background has been scheduled in a frame.
-  bool background_image_is_scheduled_ = false;
 };
 
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc b/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
index d4edc49..981986d9 100644
--- a/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
+++ b/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
@@ -237,7 +237,7 @@
             gl_surface_, dependency_.get(), shared_image_factory_.get(),
             shared_image_representation_factory_.get(), shared_image_usage),
         dependency_.get(), shared_image_representation_factory_.get(),
-        memory_tracker_.get(), present_callback, false);
+        memory_tracker_.get(), present_callback);
 
     output_device_ = std::move(onscreen_device);
   }
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 5073e2e6..30a8812 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -1126,26 +1126,16 @@
 
     if (MakeCurrent(true /* need_fbo0 */)) {
       if (gl_surface_->IsSurfaceless()) {
-#if defined(USE_OZONE)
-        bool needs_background_image = ui::OzonePlatform::GetInstance()
-                                          ->GetPlatformProperties()
-                                          .needs_background_image;
-#else   // defined(USE_OZONE)
-        bool needs_background_image = false;
-#endif  // !defined(USE_OZONE)
-
 #if !defined(OS_WIN)
         output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
             std::make_unique<OutputPresenterGL>(
                 gl_surface_, dependency_, shared_image_factory_.get(),
                 shared_image_representation_factory_.get()),
             dependency_, shared_image_representation_factory_.get(),
-            memory_tracker_, GetDidSwapBuffersCompleteCallback(),
-            needs_background_image);
-#else   // !defined(OS_WIN)
+            memory_tracker_, GetDidSwapBuffersCompleteCallback());
+#else
         NOTIMPLEMENTED();
-        (void)needs_background_image;
-#endif  // defined(OS_WIN)
+#endif
       } else {
         if (dependency_->NeedsSupportForExternalStencil()) {
           output_device_ = std::make_unique<SkiaOutputDeviceWebView>(
@@ -1197,14 +1187,6 @@
   }
 #endif  // defined(USE_X11)
 
-#if defined(USE_OZONE)
-  bool needs_background_image = ui::OzonePlatform::GetInstance()
-                                    ->GetPlatformProperties()
-                                    .needs_background_image;
-#else   // defined(USE_OZONE)
-  bool needs_background_image = false;
-#endif  // !defined(USE_OZONE)
-
 #if !defined(OS_WIN)
 #if defined(OS_FUCHSIA)
   auto output_presenter = OutputPresenterFuchsia::Create(
@@ -1223,11 +1205,10 @@
     output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
         std::move(output_presenter), dependency_,
         shared_image_representation_factory_.get(), memory_tracker_,
-        GetDidSwapBuffersCompleteCallback(), needs_background_image);
+        GetDidSwapBuffersCompleteCallback());
     return true;
   }
 #endif  // !defined(OS_WIN)
-  (void)needs_background_image;
 
   auto output_device = SkiaOutputDeviceVulkan::Create(
       vulkan_context_provider_, dependency_->GetSurfaceHandle(),
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 394ad03..3a0f7d0 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -203,6 +203,8 @@
   new_request->trusted_params = network::ResourceRequest::TrustedParams();
   new_request->trusted_params->isolation_info = request_info->isolation_info;
   new_request->trusted_params->cookie_observer = std::move(cookie_observer);
+  new_request->trusted_params->client_security_state =
+      request_info->client_security_state.Clone();
   new_request->is_main_frame = request_info->is_main_frame;
 
   net::RequestPriority net_priority = net::HIGHEST;
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.cc b/content/browser/renderer_host/agent_scheduling_group_host.cc
index 9e6ab8648..e773a359 100644
--- a/content/browser/renderer_host/agent_scheduling_group_host.cc
+++ b/content/browser/renderer_host/agent_scheduling_group_host.cc
@@ -127,6 +127,11 @@
   return absl::visit([](auto& remote) { return remote.is_bound(); }, remote_);
 }
 
+mojom::AgentSchedulingGroup*
+AgentSchedulingGroupHost::MaybeAssociatedRemote::get() {
+  return absl::visit([](auto& r) { return r.get(); }, remote_);
+}
+
 // AgentSchedulingGroupHost:
 
 // static
@@ -236,16 +241,30 @@
 
 void AgentSchedulingGroupHost::CreateFrame(mojom::CreateFrameParamsPtr params) {
   SetUpMojoIfNeeded();
-  process_.GetRendererInterface()->CreateFrame(std::move(params));
+  mojo_remote_.get()->CreateFrame(std::move(params));
 }
 
 void AgentSchedulingGroupHost::CreateView(mojom::CreateViewParamsPtr params) {
   SetUpMojoIfNeeded();
-  process_.GetRendererInterface()->CreateView(std::move(params));
+  mojo_remote_.get()->CreateView(std::move(params));
 }
 
 void AgentSchedulingGroupHost::DestroyView(int32_t routing_id) {
-  process_.GetRendererInterface()->DestroyView(routing_id);
+  if (mojo_remote_.is_bound())
+    mojo_remote_.get()->DestroyView(routing_id);
+}
+
+void AgentSchedulingGroupHost::CreateFrameProxy(
+    int32_t routing_id,
+    int32_t render_view_routing_id,
+    const base::Optional<base::UnguessableToken>& opener_frame_token,
+    int32_t parent_routing_id,
+    const FrameReplicationState& replicated_state,
+    const base::UnguessableToken& frame_token,
+    const base::UnguessableToken& devtools_frame_token) {
+  mojo_remote_.get()->CreateFrameProxy(
+      routing_id, render_view_routing_id, opener_frame_token, parent_routing_id,
+      replicated_state, frame_token, devtools_frame_token);
 }
 
 void AgentSchedulingGroupHost::GetRoute(
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.h b/content/browser/renderer_host/agent_scheduling_group_host.h
index e9902ccc..4d13d699 100644
--- a/content/browser/renderer_host/agent_scheduling_group_host.h
+++ b/content/browser/renderer_host/agent_scheduling_group_host.h
@@ -81,6 +81,14 @@
   void CreateFrame(mojom::CreateFrameParamsPtr params);
   void CreateView(mojom::CreateViewParamsPtr params);
   void DestroyView(int32_t routing_id);
+  void CreateFrameProxy(
+      int32_t routing_id,
+      int32_t render_view_routing_id,
+      const base::Optional<base::UnguessableToken>& opener_frame_token,
+      int32_t parent_routing_id,
+      const FrameReplicationState& replicated_state,
+      const base::UnguessableToken& frame_token,
+      const base::UnguessableToken& devtools_frame_token);
 
  private:
   // `MaybeAssociatedReceiver` and `MaybeAssociatedRemote` are temporary helper
@@ -136,6 +144,7 @@
 
     void reset();
     bool is_bound();
+    mojom::AgentSchedulingGroup* get();
 
    private:
     absl::variant<mojo::Remote<mojom::AgentSchedulingGroup>,
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 136d721c..6881841 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -2791,6 +2791,31 @@
     interceptor.push_back(web_bundle_handle_->TakeInterceptor());
   net::HttpRequestHeaders cors_exempt_headers;
   std::swap(cors_exempt_headers, cors_exempt_request_headers_);
+
+  // For subresource requests the ClientSecurityState is passed through
+  // URLLoaderFactoryParams. That does not work for navigation requests
+  // because they all share a common factory, so each request is tagged with
+  // a ClientSecurityState to use instead.
+  //
+  // We currently define the client of the fetch as the parent frame, if any.
+  // This is probably incorrect: frames can cause others in the same browsing
+  // context group to navigate to pages, without being the parent. Additionally
+  // there is no client security state for top-level navigations, which mainly
+  // means that CORS-RFC1918 checks are skipped for such requests.
+  //
+  // TODO(https://crbug.com/1129326): Figure out the UX story for top-level
+  // navigations and spooky-action-at-a-distance navigations, then revisit this.
+  // The client security state might need to be that of the initiator of the
+  // navigation, or we might need to take into account both the parent frame and
+  // the initiator's client security states. In any case, we should probably
+  // always provide a client security state.
+  network::mojom::ClientSecurityStatePtr client_security_state = nullptr;
+  RenderFrameHostImpl* parent = GetParentFrame();
+  if (parent) {
+    client_security_state =
+        parent->last_committed_client_security_state().Clone();
+  }
+
   loader_ = NavigationURLLoader::Create(
       browser_context, partition,
       std::make_unique<NavigationRequestInfo>(
@@ -2806,7 +2831,7 @@
                                    : nullptr,
           devtools_navigation_token(), frame_tree_node_->devtools_frame_token(),
           OriginPolicyThrottle::ShouldRequestOriginPolicy(common_params_->url),
-          std::move(cors_exempt_headers), nullptr /* client_security_state */),
+          std::move(cors_exempt_headers), std::move(client_security_state)),
       std::move(navigation_ui_data), service_worker_handle_.get(),
       appcache_handle_.get(), std::move(prefetched_signed_exchange_cache_),
       this, IsServedFromBackForwardCache(), CreateCookieAccessObserver(),
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index ba4804c..b5a7d2c 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -1113,6 +1113,7 @@
   // In that case, the caller must immediately return.
   bool MaybeCancelFailedNavigation();
 
+  // Never null. The pointee node owns this navigation request instance.
   FrameTreeNode* const frame_tree_node_;
 
   // Value of |is_for_commit| supplied to the constructor.
diff --git a/content/browser/renderer_host/navigation_request_info.h b/content/browser/renderer_host/navigation_request_info.h
index ea285de..c52014a94 100644
--- a/content/browser/renderer_host/navigation_request_info.h
+++ b/content/browser/renderer_host/navigation_request_info.h
@@ -95,6 +95,9 @@
 
   // Specifies the security state applying to the navigation. For iframes, this
   // is the security state of their parent. Nullptr otherwise.
+  //
+  // TODO(https://crbug.com/1129326): Set this for top-level navigation requests
+  // too once the UX story is sorted out.
   const network::mojom::ClientSecurityStatePtr client_security_state;
 };
 
diff --git a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
index 712b33a..3fe3daa 100644
--- a/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_impl_browsertest.cc
@@ -87,7 +87,6 @@
 namespace content {
 namespace {
 
-using ::testing::EndsWith;
 using ::testing::NotNull;
 
 // Implementation of ContentBrowserClient that overrides
@@ -3938,11 +3937,8 @@
   // Check that the child iframe failed to fetch.
   ASSERT_EQ(1ul, root_frame_host()->child_count());
   auto* child_frame = root_frame_host()->child_at(0)->current_frame_host();
-  // TODO(crbug.com/1124346): Expect 0 once the load fails.
-  EXPECT_EQ(200, child_frame->last_http_status_code());
-  // TODO(crbug.com/1124346): Expect an empty URL once the load fails.
-  EXPECT_THAT(child_frame->last_successful_url().spec(),
-              EndsWith("/empty.html"));
+  EXPECT_EQ(0, child_frame->last_http_status_code());
+  EXPECT_EQ(GURL(), child_frame->last_successful_url());
 }
 
 namespace {
diff --git a/content/browser/renderer_host/render_frame_proxy_host.cc b/content/browser/renderer_host/render_frame_proxy_host.cc
index ea76464..7aacc0e 100644
--- a/content/browser/renderer_host/render_frame_proxy_host.cc
+++ b/content/browser/renderer_host/render_frame_proxy_host.cc
@@ -253,10 +253,12 @@
   }
 
   int view_routing_id = GetRenderViewHost()->GetRoutingID();
-  GetProcess()->GetRendererInterface()->CreateFrameProxy(
-      routing_id_, view_routing_id, opener_frame_token, parent_routing_id,
-      frame_tree_node_->current_replication_state(), frame_token_,
-      frame_tree_node_->devtools_frame_token());
+  static_cast<SiteInstanceImpl*>(site_instance_.get())
+      ->GetAgentSchedulingGroup()
+      .CreateFrameProxy(routing_id_, view_routing_id, opener_frame_token,
+                        parent_routing_id,
+                        frame_tree_node_->current_replication_state(),
+                        frame_token_, frame_tree_node_->devtools_frame_token());
 
   SetRenderFrameProxyCreated(true);
 
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 56c0213..b76139eb 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -52,6 +52,7 @@
 #include "components/viz/common/features.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/gpu/compositor_util.h"
+#include "content/browser/renderer_host/agent_scheduling_group_host.h"
 #include "content/browser/renderer_host/cross_process_frame_connector.h"
 #include "content/browser/renderer_host/frame_navigation_entry.h"
 #include "content/browser/renderer_host/frame_tree.h"
@@ -6193,6 +6194,8 @@
   SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
   RenderProcessHost* process_a =
       root->render_manager()->current_frame_host()->GetProcess();
+  AgentSchedulingGroupHost* agent_scheduling_group_a =
+      AgentSchedulingGroupHost::Get(*site_instance_a, *process_a);
   int new_routing_id = process_a->GetNextRoutingID();
   int view_routing_id =
       root->frame_tree()->GetRenderViewHost(site_instance_a)->GetRoutingID();
@@ -6207,7 +6210,7 @@
   // Send the message to create a proxy for B's new child frame in A.  This
   // used to crash, as parent_routing_id refers to a proxy that doesn't exist
   // anymore.
-  process_a->GetRendererInterface()->CreateFrameProxy(
+  agent_scheduling_group_a->CreateFrameProxy(
       new_routing_id, view_routing_id, base::nullopt, parent_routing_id,
       FrameReplicationState(), base::UnguessableToken::Create(),
       base::UnguessableToken::Create());
@@ -6252,6 +6255,10 @@
   // attempted.
   RenderProcessHost* process =
       node->render_manager()->speculative_frame_host()->GetProcess();
+  AgentSchedulingGroupHost* agent_scheduling_group =
+      AgentSchedulingGroupHost::Get(
+          *node->render_manager()->speculative_frame_host()->GetSiteInstance(),
+          *process);
   RenderProcessHostWatcher watcher(
       process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
   int frame_routing_id =
@@ -6282,7 +6289,7 @@
     params->frame_owner_properties = blink::mojom::FrameOwnerProperties::New();
     params->frame_token = frame_token;
     params->devtools_frame_token = base::UnguessableToken::Create();
-    process->GetRendererInterface()->CreateFrame(std::move(params));
+    agent_scheduling_group->CreateFrame(std::move(params));
   }
 
   // Disable the BackForwardCache to ensure the old process is going to be
@@ -6322,6 +6329,9 @@
   // observer to ensure there is no crash when a new RenderFrame creation is
   // attempted.
   RenderProcessHost* process = node->current_frame_host()->GetProcess();
+  AgentSchedulingGroupHost* agent_scheduling_group =
+      AgentSchedulingGroupHost::Get(
+          *node->current_frame_host()->GetSiteInstance(), *process);
   RenderProcessHostWatcher watcher(
       process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
   int frame_routing_id = node->current_frame_host()->GetRoutingID();
@@ -6372,7 +6382,7 @@
     params->replication_state.unique_name = "name";
     params->frame_token = frame_token;
     params->devtools_frame_token = base::UnguessableToken::Create();
-    process->GetRendererInterface()->CreateFrame(std::move(params));
+    agent_scheduling_group->CreateFrame(std::move(params));
   }
 
   // The test must wait for the process to exit, but if there is no leak, the
diff --git a/content/common/agent_scheduling_group.mojom b/content/common/agent_scheduling_group.mojom
index df10b27..e5aa8aa 100644
--- a/content/common/agent_scheduling_group.mojom
+++ b/content/common/agent_scheduling_group.mojom
@@ -4,12 +4,236 @@
 
 module content.mojom;
 
-// Interface for general communication between AgentSchedulingGroup and
-// AgentSchedulingGroupHost.
+import "content/common/document_scoped_interface_bundle.mojom";
+import "content/common/native_types.mojom";
+import "content/public/common/web_preferences.mojom";
+import "ipc/constants.mojom";
+import "mojo/public/mojom/base/generic_pending_receiver.mojom";
+import "mojo/public/mojom/base/unguessable_token.mojom";
+import "third_party/blink/public/mojom/frame/frame_owner_properties.mojom";
+import "third_party/blink/public/mojom/page/page.mojom";
+import "third_party/blink/public/mojom/page/widget.mojom";
+import "third_party/blink/public/mojom/renderer_preferences.mojom";
+import "third_party/blink/public/mojom/widget/visual_properties.mojom";
+
+// A View (i.e. a "main frame") can be created for a few different cases, these
+// values are used to specify which it is.
+enum ViewWidgetType {
+  // A standard view that's the top-level widget in a frame hierarchy.
+  kTopLevel,
+  // A GuestView used to render contents inside a <webview> element.
+  kGuestView,
+  // A view used to render contents inside a <portal> element.
+  kPortal
+};
+
+struct CreateViewParams {
+  // Renderer-wide preferences.
+  blink.mojom.RendererPreferences renderer_preferences;
+
+  // Preferences for this view.
+  WebPreferences web_preferences;
+
+  // The ID of the view to be created.
+  int32 view_id = IPC.mojom.kRoutingIdNone;
+
+  // The ID of the main frame hosted in the view, or None if creating a view to
+  // host a main frame proxy. If this is None, then |proxy_routing_id| should be
+  // set to something other than None. The |main_frame_widget_routing_id| is
+  // None if this is None.
+  int32 main_frame_routing_id = IPC.mojom.kRoutingIdNone;
+
+  // The ID of the widget for the main frame. The |main_frame_routing_id| is
+  // None if this is None.
+  int32 main_frame_widget_routing_id = IPC.mojom.kRoutingIdNone;
+
+  // This is null precisely when |main_frame_routing_id| is MSG_ROUTING_NONE,
+  // that is, when creating a RenderView for a remote main frame.
+  DocumentScopedInterfaceBundle? main_frame_interface_bundle;
+
+  // The communication interfaces for the WebFrameWidget in blink. All should
+  // be set if there is a |main_frame_routing_id|.
+  pending_associated_remote<blink.mojom.FrameWidgetHost>? frame_widget_host;
+  pending_associated_receiver<blink.mojom.FrameWidget>? frame_widget;
+  pending_associated_remote<blink.mojom.WidgetHost>? widget_host;
+  pending_associated_receiver<blink.mojom.Widget>? widget;
+
+  // The session storage namespace ID this view should use.
+  string session_storage_namespace_id;
+
+  // The frame token of the opener RenderFrame or RenderFrameProxy, if we need
+  // to set one (base::nullopt otherwise).
+  mojo_base.mojom.UnguessableToken? opener_frame_token;
+
+  // Carries replicated information, such as frame name and sandbox flags, for
+  // this view's main frame, which will be a proxy when |main_frame_routing_id|
+  // is None (due to site isolation), or a RenderFrame in all other cases.
+  FrameReplicationState replicated_frame_state;
+
+  // This represents the frame token for the MainFrame. It will be always set.
+  // If |main_frame_routing_id| is set, it will store a unique identifier for
+  // the  LocalFrame<-->RenderFrameHostImpl mapping.
+  // If |proxy_routing_id| is set, it will store a unique identifier for
+  // the RemoteFrame<-->RenderFrameProxyHost mapping.
+  mojo_base.mojom.UnguessableToken main_frame_frame_token;
+
+  // Used for devtools instrumentation and trace-ability. The token is
+  // propagated to Blink's LocalFrame and both Blink and content/
+  // can tag calls and requests with this instrumentation token in order to
+  // attribute them to the context frame.
+  // |devtools_main_frame_token| is only defined by the browser and is never
+  // sent back from the renderer in the control calls.
+  mojo_base.mojom.UnguessableToken devtools_main_frame_token;
+
+  // The ID of the proxy object for the main frame in this view. It is only
+  // used if |main_frame_routing_id| is None, and exactly one of the two
+  // should be set to an id other than None at any time.
+  int32 proxy_routing_id = IPC.mojom.kRoutingIdNone;
+
+  // Whether the RenderView should initially be hidden.
+  bool hidden;
+
+  // When true, all RenderWidgets under this RenderView will never be shown to
+  // the user, and thus never composited, and will not need to produce pixels
+  // for display. This allows the renderer to optimize and avoid resources used
+  // for displaying graphical output.
+  bool never_composited;
+
+  // Whether the window associated with this view was created with an opener.
+  bool window_was_created_with_opener;
+
+  // Whether or not the frame has previously committed a real load.
+  bool has_committed_real_load;
+
+  // Initial state for the main frame RenderWidget.
+  // TODO(danakj): This should be optional and not included when there is no
+  // main_frame_widget_routing_id.
+  blink.mojom.VisualProperties visual_properties;
+
+  // Whether lookup of frames in the created RenderView (e.g. lookup via
+  // window.open or via <a target=...>) should be renderer-wide (i.e. going
+  // beyond the usual opener-relationship-based BrowsingInstance boundaries).
+  bool renderer_wide_named_frame_lookup;
+
+  // Indicates whether the view is a regular top-level widget or some other
+  // nested "main frame" widget type.
+  ViewWidgetType type;
+
+  // Endpoint for any messages that are broadcast to all views in a WebContents.
+  pending_associated_receiver<blink.mojom.PageBroadcast> blink_page_broadcast;
+};
+
+struct CreateFrameWidgetParams {
+  // Gives the routing ID for the RenderWidget that will be attached to the
+  // new RenderFrame.
+  int32 routing_id;
+
+  // The communication interfaces for the WebFrameWidget in blink.
+  pending_associated_remote<blink.mojom.FrameWidgetHost> frame_widget_host;
+  pending_associated_receiver<blink.mojom.FrameWidget> frame_widget;
+  pending_associated_remote<blink.mojom.WidgetHost> widget_host;
+  pending_associated_receiver<blink.mojom.Widget> widget;
+
+  // The initial visual properties of the widget.
+  blink.mojom.VisualProperties visual_properties;
+};
+
+struct CreateFrameParams {
+  // Specifies the routing ID of the new RenderFrame object.
+  int32 routing_id;
+
+  // If a valid |previous_routing_id| is provided, the new frame will be
+  // configured to replace either the previous frame or the previous proxy on
+  // commit.
+  int32 previous_routing_id;
+
+  // The frame token. It is a unique identifier for
+  // the LocalFrame<-->RenderFrameHostImpl mapping.
+  mojo_base.mojom.UnguessableToken frame_token;
+
+  // Specifies the new frame's opener.  The opener will be null if this is
+  // base::nullopt.
+  mojo_base.mojom.UnguessableToken? opener_frame_token;
+
+  // The new frame should be created as a child of the object
+  // identified by |parent_routing_id| or as top level if that is
+  // MSG_ROUTING_NONE.
+  int32 parent_routing_id;
+
+  // Identifies the previous sibling of the new frame, so that the new frame is
+  // inserted into the correct place in the frame tree.  If this is
+  // MSG_ROUTING_NONE, the frame will be created as the leftmost child of its
+  // parent frame, in front of any other children.
+  int32 previous_sibling_routing_id;
+
+  DocumentScopedInterfaceBundle interface_bundle;
+
+  // When the new frame has a parent, |replication_state| holds the new frame's
+  // properties replicated from the process rendering the parent frame, such as
+  // the new frame's sandbox flags.
+  FrameReplicationState replication_state;
+
+  // Used for devtools instrumentation and trace-ability. The token is
+  // propagated to Blink's LocalFrame and both Blink and content/
+  // can tag calls and requests with this instrumentation token in order to
+  // attribute them to the context frame.
+  // |devtools_frame_token| is only defined by the browser and is never
+  // sent back from the renderer in the control calls.
+  mojo_base.mojom.UnguessableToken devtools_frame_token;
+
+  // When the new frame has a parent, |frame_owner_properties| holds the
+  // properties of the HTMLFrameOwnerElement from the parent process.
+  // Note that unlike FrameReplicationState, this is not replicated for remote
+  // frames.
+  blink.mojom.FrameOwnerProperties frame_owner_properties;
+
+  // Specifies properties for a new RenderWidget that will be attached to the
+  // new RenderFrame (if one is needed).
+  CreateFrameWidgetParams? widget_params;
+
+  // Whether or not the frame has previously committed a real load.
+  bool has_committed_real_load;
+};
+
+
+// Interface for general communication between the renderer process's
+// AgentSchedulingGroup and the browser process's AgentSchedulingGroupHost.
+// Implemented by AgentSchedulingGroupHost (in the browser process).
 interface AgentSchedulingGroupHost {
 };
 
-// Interface for general communication between AgentSchedulingGroupHost and
-// AgentSchedulingGroup.
+// Interface for general communication between the browser process's
+// AgentSchedulingGroupHost and the renderer process's AgentSchedulingGroup.
+// Implemented by content::AgentSchedulingGroup (in the renderer process).
 interface AgentSchedulingGroup {
+  // Tells the renderer to create a new view.
+  CreateView(CreateViewParams params);
+
+  // Tells the renderer to destroy an existing view. This method must be called
+  // exactly once for each invocation of CreateView. |view_id| is synonymous
+  // with |routing_id|.
+  DestroyView(int32 view_id);
+
+  // Tells the renderer to create a new RenderFrame.
+  CreateFrame(CreateFrameParams params);
+
+  // Tells the renderer to create a new RenderFrameProxy object with
+  // |routing_id|.  |render_view_routing_id| identifies the
+  // RenderView to be associated with this proxy. The new proxy's opener should
+  // be set to the object identified by |opener_frame_token|, or to null if that
+  // is base::nullopt.  The new proxy should be created as a child of the
+  // object identified by |parent_routing_id| or as top level if that is
+  // MSG_ROUTING_NONE.
+  // |proxy_frame_token| is used uniquely identify the
+  // RemoteFrame <--> RenderFrameProxyHost mapping.
+  // |devtools_frame_token| is used for devtools instrumentation
+  // and trace-ability. It is defined by the browser and is never
+  // sent back from the renderer in the control calls.
+  CreateFrameProxy(int32 routing_id, int32 render_view_routing_id,
+                   mojo_base.mojom.UnguessableToken? opener_frame_token,
+                   int32 parent_routing_id,
+                   FrameReplicationState replication_state,
+                   mojo_base.mojom.UnguessableToken proxy_frame_token,
+                   mojo_base.mojom.UnguessableToken devtools_frame_token);
+
 };
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom
index 5515b7cf..e73b879 100644
--- a/content/common/renderer.mojom
+++ b/content/common/renderer.mojom
@@ -5,202 +5,13 @@
 module content.mojom;
 
 import "content/common/agent_scheduling_group.mojom";
-import "content/common/document_scoped_interface_bundle.mojom";
 import "content/common/native_types.mojom";
-import "content/public/common/web_preferences.mojom";
-import "ipc/constants.mojom";
 import "mojo/public/mojom/base/generic_pending_receiver.mojom";
 import "mojo/public/mojom/base/time.mojom";
-import "mojo/public/mojom/base/unguessable_token.mojom";
 import "services/network/public/mojom/network_types.mojom";
-import "third_party/blink/public/mojom/frame/frame_owner_properties.mojom";
-import "third_party/blink/public/mojom/manifest/manifest.mojom";
-import "third_party/blink/public/mojom/page/page.mojom";
-import "third_party/blink/public/mojom/page/widget.mojom";
-import "third_party/blink/public/mojom/renderer_preferences.mojom";
-import "third_party/blink/public/mojom/widget/visual_properties.mojom";
 import "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 
-// A View (i.e. a "main frame") can be created for a few different cases, these
-// values are used to specify which it is.
-enum ViewWidgetType {
-  // A standard view that's the top-level widget in a frame hierarchy.
-  kTopLevel,
-  // A GuestView used to render contents inside a <webview> element.
-  kGuestView,
-  // A view used to render contents inside a <portal> element.
-  kPortal
-};
-
-struct CreateViewParams {
-  // Renderer-wide preferences.
-  blink.mojom.RendererPreferences renderer_preferences;
-
-  // Preferences for this view.
-  WebPreferences web_preferences;
-
-  // The ID of the view to be created.
-  int32 view_id = IPC.mojom.kRoutingIdNone;
-
-  // The ID of the main frame hosted in the view, or None if creating a view to
-  // host a main frame proxy. If this is None, then |proxy_routing_id| should be
-  // set to something other than None. The |main_frame_widget_routing_id| is
-  // None if this is None.
-  int32 main_frame_routing_id = IPC.mojom.kRoutingIdNone;
-
-  // The ID of the widget for the main frame. The |main_frame_routing_id| is
-  // None if this is None.
-  int32 main_frame_widget_routing_id = IPC.mojom.kRoutingIdNone;
-
-  // This is null precisely when |main_frame_routing_id| is MSG_ROUTING_NONE,
-  // that is, when creating a RenderView for a remote main frame.
-  DocumentScopedInterfaceBundle? main_frame_interface_bundle;
-
-  // The communication interfaces for the WebFrameWidget in blink. All should
-  // be set if there is a |main_frame_routing_id|.
-  pending_associated_remote<blink.mojom.FrameWidgetHost>? frame_widget_host;
-  pending_associated_receiver<blink.mojom.FrameWidget>? frame_widget;
-  pending_associated_remote<blink.mojom.WidgetHost>? widget_host;
-  pending_associated_receiver<blink.mojom.Widget>? widget;
-
-  // The session storage namespace ID this view should use.
-  string session_storage_namespace_id;
-
-  // The frame token of the opener RenderFrame or RenderFrameProxy, if we need
-  // to set one (base::nullopt otherwise).
-  mojo_base.mojom.UnguessableToken? opener_frame_token;
-
-  // Carries replicated information, such as frame name and sandbox flags, for
-  // this view's main frame, which will be a proxy when |main_frame_routing_id|
-  // is None (due to site isolation), or a RenderFrame in all other cases.
-  FrameReplicationState replicated_frame_state;
-
-  // This represents the frame token for the MainFrame. It will be always set.
-  // If |main_frame_routing_id| is set, it will store a unique identifier for
-  // the  LocalFrame<-->RenderFrameHostImpl mapping.
-  // If |proxy_routing_id| is set, it will store a unique identifier for
-  // the RemoteFrame<-->RenderFrameProxyHost mapping.
-  mojo_base.mojom.UnguessableToken main_frame_frame_token;
-
-  // Used for devtools instrumentation and trace-ability. The token is
-  // propagated to Blink's LocalFrame and both Blink and content/
-  // can tag calls and requests with this instrumentation token in order to
-  // attribute them to the context frame.
-  // |devtools_main_frame_token| is only defined by the browser and is never
-  // sent back from the renderer in the control calls.
-  mojo_base.mojom.UnguessableToken devtools_main_frame_token;
-
-  // The ID of the proxy object for the main frame in this view. It is only
-  // used if |main_frame_routing_id| is None, and exactly one of the two
-  // should be set to an id other than None at any time.
-  int32 proxy_routing_id = IPC.mojom.kRoutingIdNone;
-
-  // Whether the RenderView should initially be hidden.
-  bool hidden;
-
-  // When true, all RenderWidgets under this RenderView will never be shown to
-  // the user, and thus never composited, and will not need to produce pixels
-  // for display. This allows the renderer to optimize and avoid resources used
-  // for displaying graphical output.
-  bool never_composited;
-
-  // Whether the window associated with this view was created with an opener.
-  bool window_was_created_with_opener;
-
-  // Whether or not the frame has previously committed a real load.
-  bool has_committed_real_load;
-
-  // Initial state for the main frame RenderWidget.
-  // TODO(danakj): This should be optional and not included when there is no
-  // main_frame_widget_routing_id.
-  blink.mojom.VisualProperties visual_properties;
-
-  // Whether lookup of frames in the created RenderView (e.g. lookup via
-  // window.open or via <a target=...>) should be renderer-wide (i.e. going
-  // beyond the usual opener-relationship-based BrowsingInstance boundaries).
-  bool renderer_wide_named_frame_lookup;
-
-  // Indicates whether the view is a regular top-level widget or some other
-  // nested "main frame" widget type.
-  ViewWidgetType type;
-
-  // Endpoint for any messages that are broadcast to all views in a WebContents.
-  pending_associated_receiver<blink.mojom.PageBroadcast> blink_page_broadcast;
-};
-
-struct CreateFrameWidgetParams {
-  // Gives the routing ID for the RenderWidget that will be attached to the
-  // new RenderFrame.
-  int32 routing_id;
-
-  // The communication interfaces for the WebFrameWidget in blink.
-  pending_associated_remote<blink.mojom.FrameWidgetHost> frame_widget_host;
-  pending_associated_receiver<blink.mojom.FrameWidget> frame_widget;
-  pending_associated_remote<blink.mojom.WidgetHost> widget_host;
-  pending_associated_receiver<blink.mojom.Widget> widget;
-
-  // The initial visual properties of the widget.
-  blink.mojom.VisualProperties visual_properties;
-};
-
-struct CreateFrameParams {
-  // Specifies the routing ID of the new RenderFrame object.
-  int32 routing_id;
-
-  // If a valid |previous_routing_id| is provided, the new frame will be
-  // configured to replace either the previous frame or the previous proxy on
-  // commit.
-  int32 previous_routing_id;
-
-  // The frame token. It is a unique identifier for
-  // the LocalFrame<-->RenderFrameHostImpl mapping.
-  mojo_base.mojom.UnguessableToken frame_token;
-
-  // Specifies the new frame's opener.  The opener will be null if this is
-  // base::nullopt.
-  mojo_base.mojom.UnguessableToken? opener_frame_token;
-
-  // The new frame should be created as a child of the object
-  // identified by |parent_routing_id| or as top level if that is
-  // MSG_ROUTING_NONE.
-  int32 parent_routing_id;
-
-  // Identifies the previous sibling of the new frame, so that the new frame is
-  // inserted into the correct place in the frame tree.  If this is
-  // MSG_ROUTING_NONE, the frame will be created as the leftmost child of its
-  // parent frame, in front of any other children.
-  int32 previous_sibling_routing_id;
-
-  DocumentScopedInterfaceBundle interface_bundle;
-
-  // When the new frame has a parent, |replication_state| holds the new frame's
-  // properties replicated from the process rendering the parent frame, such as
-  // the new frame's sandbox flags.
-  FrameReplicationState replication_state;
-
-  // Used for devtools instrumentation and trace-ability. The token is
-  // propagated to Blink's LocalFrame and both Blink and content/
-  // can tag calls and requests with this instrumentation token in order to
-  // attribute them to the context frame.
-  // |devtools_frame_token| is only defined by the browser and is never
-  // sent back from the renderer in the control calls.
-  mojo_base.mojom.UnguessableToken devtools_frame_token;
-
-  // When the new frame has a parent, |frame_owner_properties| holds the
-  // properties of the HTMLFrameOwnerElement from the parent process.
-  // Note that unlike FrameReplicationState, this is not replicated for remote
-  // frames.
-  blink.mojom.FrameOwnerProperties frame_owner_properties;
-
-  // Specifies properties for a new RenderWidget that will be attached to the
-  // new RenderFrame (if one is needed).
-  CreateFrameWidgetParams? widget_params;
-
-  // Whether or not the frame has previously committed a real load.
-  bool has_committed_real_load;
-};
-
 struct UpdateScrollbarThemeParams {
   // TODO(avi): Update these to optional values when optional numeric types are
   // allowed. (https://crbug.com/657632)
@@ -247,17 +58,6 @@
 // This should be used for implementing browser-to-renderer control messages
 // which need to retain FIFO with respect to legacy IPC messages.
 interface Renderer {
-  // Tells the renderer to create a new view.
-  CreateView(CreateViewParams params);
-
-  // Tells the renderer to destroy an existing view. This method must be called
-  // exactly once for each invocation of CreateView. |view_id| is synonymous
-  // with |routing_id|.
-  DestroyView(int32 view_id);
-
-  // Tells the renderer to create a new RenderFrame.
-  CreateFrame(CreateFrameParams params);
-
   // Tells the renderer to create a new AgentSchedulingGroup, that will
   // communicate via the pending |agent_scheduling_group_host| and
   // |agent_scheduling_group|. This will create "independent" interfaces that
@@ -278,25 +78,6 @@
     pending_associated_receiver<AgentSchedulingGroup> agent_scheduling_group
   );
 
-  // Tells the renderer to create a new RenderFrameProxy object with
-  // |routing_id|.  |render_view_routing_id| identifies the
-  // RenderView to be associated with this proxy. The new proxy's opener should
-  // be set to the object identified by |opener_frame_token|, or to null if that
-  // is base::nullopt.  The new proxy should be created as a child of the
-  // object identified by |parent_routing_id| or as top level if that is
-  // MSG_ROUTING_NONE.
-  // |proxy_frame_token| is used uniquely identify the
-  // RemoteFrame <--> RenderFrameProxyHost mapping.
-  // |devtools_frame_token| is used for devtools instrumentation
-  // and trace-ability. It is defined by the browser and is never
-  // sent back from the renderer in the control calls.
-  CreateFrameProxy(int32 routing_id, int32 render_view_routing_id,
-                   mojo_base.mojom.UnguessableToken? opener_frame_token,
-                   int32 parent_routing_id,
-                   FrameReplicationState replication_state,
-                   mojo_base.mojom.UnguessableToken proxy_frame_token,
-                   mojo_base.mojom.UnguessableToken devtools_frame_token);
-
   // Tells the renderer that the network type has changed so that
   // navigator.onLine and navigator.connection can be updated.
   OnNetworkConnectionChanged(NetworkConnectionType connection_type,
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java
index f0d153f..fa8864b 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeActivityTestRule.java
@@ -9,8 +9,6 @@
 import org.junit.runners.model.Statement;
 
 import org.chromium.base.Log;
-import org.chromium.base.test.SetUpStatement;
-import org.chromium.base.test.SetUpTestRule;
 import org.chromium.base.test.params.ParameterProvider;
 import org.chromium.base.test.params.ParameterSet;
 import org.chromium.base.test.util.UrlUtils;
@@ -28,8 +26,10 @@
 /**
  * ActivityTestRule with common functionality for testing the Java Bridge.
  */
-public class JavaBridgeActivityTestRule
-        extends ContentShellActivityTestRule implements SetUpTestRule<JavaBridgeActivityTestRule> {
+public class JavaBridgeActivityTestRule extends ContentShellActivityTestRule {
+    /** Shared name for batched JavaBridge tests. */
+    public static final String BATCH = "JavaBridgeActivityTestRule";
+
     /**
      * {@link ParameterProvider} used for parameterized test that provides the Mojo usage state.
      */
@@ -58,7 +58,6 @@
     }
 
     private TestCallbackHelperContainer mTestCallbackHelperContainer;
-    private boolean mSetup;
     private boolean mUseMojo;
 
     public static class Controller {
@@ -183,18 +182,7 @@
 
     @Override
     public Statement apply(Statement base, Description desc) {
-        SetUpStatement setUpBase = new SetUpStatement(base, this, mSetup);
-        return super.apply(setUpBase, desc);
-    }
-
-    @Override
-    public JavaBridgeActivityTestRule shouldSetUp(boolean runSetUp) {
-        mSetup = runSetUp;
-        return this;
-    }
-
-    @Override
-    public void setUp() {
         setUpContentView();
+        return super.apply(base, desc);
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java
index f942e47..61af28f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayCoercionTest.java
@@ -17,6 +17,7 @@
 import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore;
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller;
 
@@ -33,12 +34,12 @@
  */
 @RunWith(ParameterizedRunner.class)
 @UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
+@Batch(JavaBridgeActivityTestRule.BATCH)
 public class JavaBridgeArrayCoercionTest {
     private static final double ASSERTION_DELTA = 0;
 
     @Rule
-    public JavaBridgeActivityTestRule mActivityTestRule =
-            new JavaBridgeActivityTestRule().shouldSetUp(true);
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
 
     private static class TestObject extends Controller {
         private final Object mObjectInstance;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java
index 3c1b3476..24a0d0a 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeArrayTest.java
@@ -17,6 +17,7 @@
 import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore;
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller;
 
@@ -32,10 +33,10 @@
  */
 @RunWith(ParameterizedRunner.class)
 @UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
+@Batch(JavaBridgeActivityTestRule.BATCH)
 public class JavaBridgeArrayTest {
     @Rule
-    public JavaBridgeActivityTestRule mActivityTestRule =
-            new JavaBridgeActivityTestRule().shouldSetUp(true);
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
 
     private static class TestObject extends Controller {
         private boolean mBooleanValue;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java
index 660140fd..c89009f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBareboneTest.java
@@ -7,7 +7,6 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -17,22 +16,21 @@
 import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore;
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnEvaluateJavaScriptResultHelper;
-import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
 
 /**
  * Common functionality for testing the Java Bridge.
  */
 @RunWith(ParameterizedRunner.class)
 @UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
+@Batch(JavaBridgeActivityTestRule.BATCH)
 public class JavaBridgeBareboneTest {
     @Rule
-    public JavaBridgeActivityTestRule mActivityTestRule =
-            new JavaBridgeActivityTestRule().shouldSetUp(false);
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
 
     private TestCallbackHelperContainer mTestCallbackHelperContainer;
     private boolean mUseMojo;
@@ -43,15 +41,6 @@
         mActivityTestRule.setupMojoTest(useMojo);
     }
 
-    @Before
-    public void setUp() {
-        mActivityTestRule.launchContentShellWithUrl(
-                UrlUtils.encodeHtmlDataUri("<html><head></head><body>test</body></html>"));
-        mActivityTestRule.waitForActiveShellToBeDoneLoading();
-        mTestCallbackHelperContainer =
-                new TestCallbackHelperContainer(mActivityTestRule.getWebContents());
-    }
-
     private void injectDummyObject(final String name) throws Throwable {
         mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
@@ -69,19 +58,6 @@
         return javascriptHelper.getJsonResultAndClear();
     }
 
-    private void reloadSync() throws Throwable {
-        OnPageFinishedHelper pageFinishedHelper =
-                mTestCallbackHelperContainer.getOnPageFinishedHelper();
-        int currentCallCount = pageFinishedHelper.getCallCount();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivityTestRule.getWebContents().getNavigationController().reload(true);
-            }
-        });
-        pageFinishedHelper.waitForCallback(currentCallCount);
-    }
-
     // If inection happens before evaluating any JS code, then the first evaluation
     // triggers the same condition as page reload, which causes Java Bridge to add
     // a JS wrapper.
@@ -121,7 +97,7 @@
     @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class)
     @DisabledTest(message = "Flaky - https://crbug.com/1117003")
     public void testImmediateAdditionAfterReload(boolean useMojo) throws Throwable {
-        reloadSync();
+        mActivityTestRule.synchronousPageReload();
         injectDummyObject("testObject");
         Assert.assertEquals("\"object\"", evaluateJsSync("typeof testObject"));
     }
@@ -132,7 +108,7 @@
     @UseMethodParameter(JavaBridgeActivityTestRule.MojoTestParams.class)
     public void testReloadAfterAddition(boolean useMojo) throws Throwable {
         injectDummyObject("testObject");
-        reloadSync();
+        mActivityTestRule.synchronousPageReload();
         Assert.assertEquals("\"object\"", evaluateJsSync("typeof testObject"));
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
index a0e5ad47e..f031f11 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
@@ -10,7 +10,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -51,11 +50,10 @@
  */
 @RunWith(ParameterizedRunner.class)
 @UseRunnerDelegate(ContentJUnit4RunnerDelegate.class)
-@Batch(Batch.PER_CLASS)
+@Batch(JavaBridgeActivityTestRule.BATCH)
 public class JavaBridgeBasicsTest {
     @Rule
-    public JavaBridgeActivityTestRule mActivityTestRule =
-            new JavaBridgeActivityTestRule().shouldSetUp(false);
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
 
     private static class TestController extends Controller {
         private int mIntValue;
@@ -117,18 +115,10 @@
 
     @Before
     public void setUp() {
-        mActivityTestRule.setUpContentView();
         mTestController = new TestController();
         mActivityTestRule.injectObjectAndReload(mTestController, "testController");
     }
 
-    @After
-    public void tearDown() throws Exception {
-        // TODO(yfriedman): Instead of finishing the activity, re-use it and launch a new Shell to
-        // minimize overhead.
-        mActivityTestRule.getActivity().finish();
-    }
-
     // Note that this requires that we can pass a JavaScript string to Java.
     protected String executeJavaScriptAndGetStringResult(String script) throws Throwable {
         mActivityTestRule.executeJavaScript("testController.setStringValue(" + script + ");");
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
index fd43eca..d1e4612 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeChildFrameTest.java
@@ -18,6 +18,7 @@
 import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore;
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
@@ -41,10 +42,10 @@
  */
 @RunWith(ParameterizedRunner.class)
 @UseRunnerDelegate(ContentJUnit4RunnerDelegate.class)
+@Batch(JavaBridgeActivityTestRule.BATCH)
 public class JavaBridgeChildFrameTest {
     @Rule
-    public JavaBridgeActivityTestRule mActivityTestRule =
-            new JavaBridgeActivityTestRule().shouldSetUp(true);
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
 
     private static class TestController extends Controller {
         private String mStringValue;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java
index 4c617c9..13fdaa3 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeCoercionTest.java
@@ -19,6 +19,7 @@
 import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore;
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller;
@@ -39,12 +40,12 @@
  */
 @RunWith(ParameterizedRunner.class)
 @UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
+@Batch(JavaBridgeActivityTestRule.BATCH)
 public class JavaBridgeCoercionTest {
     private static final double ASSERTION_DELTA = 0;
 
     @Rule
-    public JavaBridgeActivityTestRule mActivityTestRule =
-            new JavaBridgeActivityTestRule().shouldSetUp(true);
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
 
     private static class TestObject extends Controller {
         private Object mObjectInstance;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java
index b978ece..6a9fdfb 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeFieldsTest.java
@@ -17,6 +17,7 @@
 import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore;
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller;
 
@@ -26,10 +27,10 @@
  */
 @RunWith(ParameterizedRunner.class)
 @UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
+@Batch(JavaBridgeActivityTestRule.BATCH)
 public class JavaBridgeFieldsTest {
     @Rule
-    public JavaBridgeActivityTestRule mActivityTestRule =
-            new JavaBridgeActivityTestRule().shouldSetUp(true);
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
 
     private static class TestObject extends Controller {
         private String mStringValue;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java
index e0ab9f5..a5e30dee 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeReturnValuesTest.java
@@ -17,6 +17,7 @@
 import org.chromium.base.test.params.ParameterAnnotations.UseMethodParameterBefore;
 import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
 import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.JavaBridgeActivityTestRule.Controller;
 
@@ -33,10 +34,10 @@
  */
 @RunWith(ParameterizedRunner.class)
 @UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
+@Batch(JavaBridgeActivityTestRule.BATCH)
 public class JavaBridgeReturnValuesTest {
     @Rule
-    public JavaBridgeActivityTestRule mActivityTestRule =
-            new JavaBridgeActivityTestRule().shouldSetUp(true);
+    public JavaBridgeActivityTestRule mActivityTestRule = new JavaBridgeActivityTestRule();
 
     // An instance of this class is injected into the page to test returning
     // Java values to JavaScript.
diff --git a/content/renderer/agent_scheduling_group.cc b/content/renderer/agent_scheduling_group.cc
index 849b1bc..ec818b5 100644
--- a/content/renderer/agent_scheduling_group.cc
+++ b/content/renderer/agent_scheduling_group.cc
@@ -5,8 +5,8 @@
 #include "content/renderer/agent_scheduling_group.h"
 
 #include "base/feature_list.h"
+#include "base/util/type_safety/pass_key.h"
 #include "content/public/common/content_features.h"
-#include "content/public/renderer/render_thread.h"
 #include "content/renderer/render_thread_impl.h"
 
 namespace content {
@@ -21,6 +21,8 @@
 using ::mojo::Receiver;
 using ::mojo::Remote;
 
+using PassKey = ::util::PassKey<AgentSchedulingGroup>;
+
 namespace {
 RenderThreadImpl& ToImpl(RenderThread& render_thread) {
   DCHECK(RenderThreadImpl::current());
@@ -137,6 +139,32 @@
   RenderThread::Get()->RemoveRoute(routing_id);
 }
 
+void AgentSchedulingGroup::CreateView(mojom::CreateViewParamsPtr params) {
+  ToImpl(render_thread_).CreateView(std::move(params), PassKey());
+}
+
+void AgentSchedulingGroup::DestroyView(int32_t view_id) {
+  ToImpl(render_thread_).DestroyView(view_id, PassKey());
+}
+
+void AgentSchedulingGroup::CreateFrame(mojom::CreateFrameParamsPtr params) {
+  ToImpl(render_thread_).CreateFrame(std::move(params), PassKey());
+}
+
+void AgentSchedulingGroup::CreateFrameProxy(
+    int32_t routing_id,
+    int32_t render_view_routing_id,
+    const base::Optional<base::UnguessableToken>& opener_frame_token,
+    int32_t parent_routing_id,
+    const FrameReplicationState& replicated_state,
+    const base::UnguessableToken& frame_token,
+    const base::UnguessableToken& devtools_frame_token) {
+  ToImpl(render_thread_)
+      .CreateFrameProxy(routing_id, render_view_routing_id, opener_frame_token,
+                        parent_routing_id, replicated_state, frame_token,
+                        devtools_frame_token, PassKey());
+}
+
 void AgentSchedulingGroup::GetRoute(
     int32_t routing_id,
     mojo::PendingAssociatedReceiver<blink::mojom::AssociatedInterfaceProvider>
diff --git a/content/renderer/agent_scheduling_group.h b/content/renderer/agent_scheduling_group.h
index 4be0122e..658ef85dd 100644
--- a/content/renderer/agent_scheduling_group.h
+++ b/content/renderer/agent_scheduling_group.h
@@ -104,6 +104,19 @@
         remote_;
   };
 
+  // mojom::AgentSchedulingGroup:
+  void CreateView(mojom::CreateViewParamsPtr params) override;
+  void DestroyView(int32_t view_id) override;
+  void CreateFrame(mojom::CreateFrameParamsPtr params) override;
+  void CreateFrameProxy(
+      int32_t routing_id,
+      int32_t render_view_routing_id,
+      const base::Optional<base::UnguessableToken>& opener_frame_token,
+      int32_t parent_routing_id,
+      const FrameReplicationState& replicated_state,
+      const base::UnguessableToken& frame_token,
+      const base::UnguessableToken& devtools_frame_token) override;
+
   // mojom::RouteProvider
   void GetRoute(
       int32_t routing_id,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index c1e18ed..b2bd0e0e 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4973,6 +4973,10 @@
   return web_media_stream_device_observer_.get();
 }
 
+bool RenderFrameImpl::AllowRTCLegacyTLSProtocols() {
+  return GetRendererPreferences().webrtc_allow_legacy_tls_protocols;
+}
+
 blink::WebEncryptedMediaClient* RenderFrameImpl::EncryptedMediaClient() {
   return media_factory_.EncryptedMediaClient();
 }
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 1e22885..a880d8b 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -707,6 +707,7 @@
                                 int world_id) override;
   void DidChangeScrollOffset() override;
   blink::WebMediaStreamDeviceObserver* MediaStreamDeviceObserver() override;
+  bool AllowRTCLegacyTLSProtocols() override;
   blink::WebEncryptedMediaClient* EncryptedMediaClient() override;
   blink::WebString UserAgentOverride() override;
   base::Optional<blink::UserAgentMetadata> UserAgentMetadataOverride() override;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 0352f127..6e646c9 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -158,8 +158,8 @@
 #endif
 
 #if defined(OS_WIN)
-#include <windows.h>
 #include <objbase.h>
+#include <windows.h>
 #endif
 
 #ifdef ENABLE_VTUNE_JIT_INTERFACE
@@ -181,20 +181,21 @@
 #include "base/test/clang_profiling.h"
 #endif
 
-using base::ThreadRestrictions;
-using blink::WebDocument;
-using blink::WebFrame;
-using blink::WebNetworkStateNotifier;
-using blink::WebRuntimeFeatures;
-using blink::WebScriptController;
-using blink::WebSecurityPolicy;
-using blink::WebString;
-using blink::WebView;
-
 namespace content {
 
 namespace {
 
+using ::base::ThreadRestrictions;
+using ::blink::WebDocument;
+using ::blink::WebFrame;
+using ::blink::WebNetworkStateNotifier;
+using ::blink::WebRuntimeFeatures;
+using ::blink::WebScriptController;
+using ::blink::WebSecurityPolicy;
+using ::blink::WebString;
+using ::blink::WebView;
+using ::util::PassKey;
+
 #if defined(OS_ANDROID)
 // Unique identifier for each output surface created.
 uint32_t g_next_layer_tree_frame_sink_id = 1;
@@ -218,14 +219,19 @@
 
 // v8::MemoryPressureLevel should correspond to base::MemoryPressureListener.
 static_assert(static_cast<v8::MemoryPressureLevel>(
-    base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) ==
-        v8::MemoryPressureLevel::kNone, "none level not align");
-static_assert(static_cast<v8::MemoryPressureLevel>(
-    base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) ==
-        v8::MemoryPressureLevel::kModerate, "moderate level not align");
-static_assert(static_cast<v8::MemoryPressureLevel>(
-    base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) ==
-        v8::MemoryPressureLevel::kCritical, "critical level not align");
+                  base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) ==
+                  v8::MemoryPressureLevel::kNone,
+              "none level not align");
+static_assert(
+    static_cast<v8::MemoryPressureLevel>(
+        base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) ==
+        v8::MemoryPressureLevel::kModerate,
+    "moderate level not align");
+static_assert(
+    static_cast<v8::MemoryPressureLevel>(
+        base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) ==
+        v8::MemoryPressureLevel::kCritical,
+    "critical level not align");
 
 // WebMemoryPressureLevel should correspond to base::MemoryPressureListener.
 static_assert(static_cast<blink::WebMemoryPressureLevel>(
@@ -243,21 +249,20 @@
         blink::kWebMemoryPressureLevelCritical,
     "blink::WebMemoryPressureLevelCritical not align");
 
-void* CreateHistogram(
-    const char *name, int min, int max, size_t buckets) {
+void* CreateHistogram(const char* name, int min, int max, size_t buckets) {
   if (min <= 0)
     min = 1;
   std::string histogram_name;
   RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
   if (render_thread_impl) {  // Can be null in tests.
-    histogram_name = render_thread_impl->
-        histogram_customizer()->ConvertToCustomHistogramName(name);
+    histogram_name = render_thread_impl->histogram_customizer()
+                         ->ConvertToCustomHistogramName(name);
   } else {
     histogram_name = std::string(name);
   }
-  base::HistogramBase* histogram = base::Histogram::FactoryGet(
-      histogram_name, min, max, buckets,
-      base::Histogram::kUmaTargetedHistogramFlag);
+  base::HistogramBase* histogram =
+      base::Histogram::FactoryGet(histogram_name, min, max, buckets,
+                                  base::Histogram::kUmaTargetedHistogramFlag);
   return histogram;
 }
 
@@ -390,7 +395,8 @@
 RenderThreadImpl::HistogramCustomizer::~HistogramCustomizer() {}
 
 void RenderThreadImpl::HistogramCustomizer::RenderViewNavigatedToHost(
-    const std::string& host, size_t view_count) {
+    const std::string& host,
+    size_t view_count) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableHistogramCustomizer)) {
     return;
@@ -1380,7 +1386,7 @@
   // more informative stack, since we will otherwise just crash later when we
   // try to restart it.
   CHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSingleProcess));
+      switches::kSingleProcess));
   ChildThreadImpl::OnChannelError();
 }
 
@@ -1821,7 +1827,8 @@
   return gpu_->GetGpuChannel().get();
 }
 
-void RenderThreadImpl::CreateView(mojom::CreateViewParamsPtr params) {
+void RenderThreadImpl::CreateView(mojom::CreateViewParamsPtr params,
+                                  PassKey<AgentSchedulingGroup>) {
   CompositorDependencies* compositor_deps = this;
   is_scroll_animator_enabled_ = params->web_preferences.enable_scroll_animator;
   // TODO(crbug.com/1111231): For as long as views are created via the
@@ -1836,7 +1843,8 @@
                          GetWebMainThreadScheduler()->DefaultTaskRunner());
 }
 
-void RenderThreadImpl::DestroyView(int32_t view_id) {
+void RenderThreadImpl::DestroyView(int32_t view_id,
+                                   PassKey<AgentSchedulingGroup>) {
   RenderViewImpl* view = RenderViewImpl::FromRoutingID(view_id);
   DCHECK(view);
 
@@ -1850,7 +1858,8 @@
       base::BindOnce(&RenderViewImpl::Destroy, base::Unretained(view)));
 }
 
-void RenderThreadImpl::CreateFrame(mojom::CreateFrameParamsPtr params) {
+void RenderThreadImpl::CreateFrame(mojom::CreateFrameParamsPtr params,
+                                   PassKey<AgentSchedulingGroup>) {
   CompositorDependencies* compositor_deps = this;
   mojo::PendingRemote<service_manager::mojom::InterfaceProvider>
       interface_provider(
@@ -1912,7 +1921,8 @@
     int32_t parent_routing_id,
     const FrameReplicationState& replicated_state,
     const base::UnguessableToken& frame_token,
-    const base::UnguessableToken& devtools_frame_token) {
+    const base::UnguessableToken& devtools_frame_token,
+    PassKey<AgentSchedulingGroup>) {
   // TODO(crbug.com/1111231): For as long as frame proxies are created via the
   // `Renderer` interface (as opposed to `AgentSchedulingGroup`), we will always
   // have *exactly one* `AgentSchedulingGroup` in the process.
@@ -2330,8 +2340,7 @@
 
 // Called on the listener thread.
 void RenderThreadImpl::UnfreezableMessageFilter::
-    RemoveListenerUnfreezableTaskRunner(
-        int32_t routing_id) {
+    RemoveListenerUnfreezableTaskRunner(int32_t routing_id) {
   base::AutoLock lock(unfreezable_task_runners_lock_);
   unfreezable_task_runners_.erase(routing_id);
 }
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 05bd7da62..b8ec7807 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -27,6 +27,7 @@
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
+#include "base/util/type_safety/pass_key.h"
 #include "build/build_config.h"
 #include "cc/mojom/render_frame_metadata.mojom.h"
 #include "content/child/child_thread_impl.h"
@@ -214,6 +215,22 @@
   // viz::mojom::CompositingModeWatcher implementation.
   void CompositingModeFallbackToSoftware() override;
 
+  // Formerly in mojom::Renderer (moved to mojom::AgentSchedulingGroup):
+  void CreateView(mojom::CreateViewParamsPtr params,
+                  util::PassKey<AgentSchedulingGroup>);
+  void DestroyView(int32_t view_id, util::PassKey<AgentSchedulingGroup>);
+  void CreateFrame(mojom::CreateFrameParamsPtr params,
+                   util::PassKey<AgentSchedulingGroup>);
+  void CreateFrameProxy(
+      int32_t routing_id,
+      int32_t render_view_routing_id,
+      const base::Optional<base::UnguessableToken>& opener_frame_token,
+      int32_t parent_routing_id,
+      const FrameReplicationState& replicated_state,
+      const base::UnguessableToken& frame_token,
+      const base::UnguessableToken& devtools_frame_token,
+      util::PassKey<AgentSchedulingGroup>);
+
   // Whether gpu compositing is being used or is disabled for software
   // compositing. Clients of the compositor should give resources that match
   // the appropriate mode.
@@ -439,9 +456,6 @@
   void OnGetAccessibilityTree();
 
   // mojom::Renderer:
-  void CreateView(mojom::CreateViewParamsPtr params) override;
-  void DestroyView(int32_t view_id) override;
-  void CreateFrame(mojom::CreateFrameParamsPtr params) override;
   void CreateAgentSchedulingGroup(
       mojo::PendingRemote<mojom::AgentSchedulingGroupHost>
           agent_scheduling_group_host,
@@ -452,14 +466,6 @@
           agent_scheduling_group_host,
       mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup>
           agent_scheduling_group) override;
-  void CreateFrameProxy(
-      int32_t routing_id,
-      int32_t render_view_routing_id,
-      const base::Optional<base::UnguessableToken>& opener_frame_token,
-      int32_t parent_routing_id,
-      const FrameReplicationState& replicated_state,
-      const base::UnguessableToken& frame_token,
-      const base::UnguessableToken& devtools_frame_token) override;
   void OnNetworkConnectionChanged(
       net::NetworkChangeNotifier::ConnectionType type,
       double max_bandwidth_mbps) override;
diff --git a/content/test/fuzzer/BUILD.gn b/content/test/fuzzer/BUILD.gn
index 6a8f1117..a24d572d 100644
--- a/content/test/fuzzer/BUILD.gn
+++ b/content/test/fuzzer/BUILD.gn
@@ -187,6 +187,24 @@
   ]
 }
 
+mojolpm_fuzzer_test("file_system_manager_mojolpm_fuzzer") {
+  sources = [ "file_system_manager_mojolpm_fuzzer.cc" ]
+
+  proto_source = "file_system_manager_mojolpm_fuzzer.proto"
+
+  deps = [
+    "//base/test:test_support",
+    "//content/browser:for_content_tests",
+    "//content/public/browser:browser_sources",
+    "//content/test:test_support",
+    "//services/network:test_support",
+    "//storage/browser:test_support",
+    "//third_party/icu:icudata",
+  ]
+
+  proto_deps = [ "//third_party/blink/public/mojom:mojom_platform_mojolpm" ]
+}
+
 fuzzer_test("speech_audio_encoder_fuzzer") {
   sources = [
     "../../browser/speech/audio_buffer.cc",
diff --git a/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.cc b/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.cc
new file mode 100644
index 0000000..6334f54
--- /dev/null
+++ b/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.cc
@@ -0,0 +1,418 @@
+// 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 <stdint.h>
+#include <utility>
+
+#include "base/at_exit.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/i18n/icu_util.h"
+#include "base/task/post_task.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "content/browser/blob_storage/chrome_blob_storage_context.h"  // nogncheck
+#include "content/browser/file_system/file_system_manager_impl.h"  // nogncheck
+#include "content/browser/storage_partition_impl_map.h"            // nogncheck
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_content_client_initializer.h"
+#include "content/test/fuzzer/file_system_manager_mojolpm_fuzzer.pb.h"
+#include "mojo/core/embedder/embedder.h"
+#include "storage/browser/quota/special_storage_policy.h"
+#include "storage/browser/test/mock_special_storage_policy.h"
+#include "storage/browser/test/test_file_system_context.h"
+#include "third_party/blink/public/mojom/filesystem/file_system.mojom-mojolpm.h"
+#include "third_party/libprotobuf-mutator/src/src/libfuzzer/libfuzzer_macro.h"
+#include "url/origin.h"
+
+using url::Origin;
+
+namespace content {
+
+const size_t kNumRenderers = 2;
+const char* cmdline[] = {"file_system_manager_mojolpm_fuzzer", nullptr};
+
+// Global environment needed to run the interface being tested.
+//
+// This will be created once, before fuzzing starts, and will be shared between
+// all testcases. It is created on the main thread.
+//
+// At a minimum, we should always be able to set up the command line, i18n and
+// mojo, and create the thread on which the fuzzer will be run. We want to avoid
+// (as much as is reasonable) any state being preserved between testcases.
+//
+// For FileSystemManager, we can also safely re-use a single
+// BrowserTaskEnvironment and the TestContentClientInitializer between
+// testcases. We try to create an environment that matches the real browser
+// process as much as possible, so we use real platform threads in the task
+// environment.
+class ContentFuzzerEnvironment {
+ public:
+  ContentFuzzerEnvironment()
+      : fuzzer_thread_("fuzzer_thread"),
+        task_environment_(
+            (base::CommandLine::Init(1, cmdline),
+             TestTimeouts::Initialize(),
+             base::test::TaskEnvironment::MainThreadType::DEFAULT),
+            base::test::TaskEnvironment::ThreadPoolExecutionMode::ASYNC,
+            base::test::TaskEnvironment::ThreadingMode::MULTIPLE_THREADS,
+            content::BrowserTaskEnvironment::REAL_IO_THREAD) {
+    logging::SetMinLogLevel(logging::LOG_FATAL);
+    mojo::core::Init();
+    base::i18n::InitializeICU();
+    fuzzer_thread_.StartAndWaitForTesting();
+  }
+
+  scoped_refptr<base::SequencedTaskRunner> fuzzer_task_runner() {
+    return fuzzer_thread_.task_runner();
+  }
+
+ private:
+  base::AtExitManager at_exit_manager_;
+  base::Thread fuzzer_thread_;
+  content::BrowserTaskEnvironment task_environment_;
+  content::TestContentClientInitializer content_client_initializer_;
+};
+
+ContentFuzzerEnvironment& GetEnvironment() {
+  static base::NoDestructor<ContentFuzzerEnvironment> environment;
+  return *environment;
+}
+
+scoped_refptr<base::SequencedTaskRunner> GetFuzzerTaskRunner() {
+  return GetEnvironment().fuzzer_task_runner();
+}
+
+// Per-testcase state needed to run the interface being tested.
+//
+// The lifetime of this is scoped to a single testcase, and it is created and
+// destroyed from the fuzzer sequence.
+//
+// For FileSystemManager, this needs the basic common Browser process state
+// provided by TestBrowserContext, and to set up the storage contexts that will
+// be used. The filesystem APIs also depend on the Blob subsystem, so in
+// addition to the FileSystemContext we also need a BlobStorageContext.
+//
+// Since the Browser process will host one FileSystemManagerImpl per
+// RenderProcessHost, we emulate this by allowing the fuzzer to create (and
+// destroy) multiple FileSystemManagerImpl instances.
+class FileSystemManagerTestcase {
+ public:
+  explicit FileSystemManagerTestcase(
+      const content::fuzzing::file_system_manager::proto::Testcase& testcase);
+
+  // Returns true once either all of the actions in the testcase have been
+  // performed, or the per-testcase action limit has been exceeded.
+  //
+  // This should only be called from the fuzzer sequence.
+  bool IsFinished();
+
+  // If there are still actions remaining in the testcase, this will perform the
+  // next sequence of actions before returning.
+  //
+  // If IsFinished() would return true, then calling this function is a no-op.
+  //
+  // This should only be called from the fuzzer sequence.
+  void NextAction();
+
+  void SetUp();
+  void TearDown();
+
+ private:
+  using Action = content::fuzzing::file_system_manager::proto::Action;
+
+  void SetUpOnIOThread();
+  void SetUpOnUIThread();
+  void TearDownOnIOThread();
+  void TearDownOnUIThread();
+
+  // Used by AddFileSystemManager to create and bind FileSystemManagerImpl on the
+  // UI thread.
+  void AddFileSystemManagerImpl(
+      uint32_t id,
+      content::fuzzing::file_system_manager::proto::NewFileSystemManagerAction::
+          RenderProcessId render_process_id,
+      mojo::PendingReceiver<::blink::mojom::FileSystemManager>&& receiver);
+
+  // Create and bind a new instance for fuzzing. This needs to  make sure that
+  // the new instance has been created and bound on the correct sequence before
+  // returning.
+  void AddFileSystemManager(
+      uint32_t id,
+      content::fuzzing::file_system_manager::proto::NewFileSystemManagerAction::
+          RenderProcessId render_process_id);
+
+  // The proto message describing the test actions to perform.
+  const content::fuzzing::file_system_manager::proto::Testcase& testcase_;
+
+  // Apply a reasonable upper-bound on testcase complexity to avoid timeouts.
+  const int max_action_count_ = 512;
+
+  // Count of total actions performed in this testcase.
+  int action_count_ = 0;
+
+  // The index of the next sequence of actions to execute.
+  int next_sequence_idx_ = 0;
+
+  // Prerequisite state
+  TestBrowserContext browser_context_;
+  base::ScopedTempDir temp_dir_;
+  scoped_refptr<storage::FileSystemContext> file_system_context_;
+  scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
+
+  // Mapping from renderer id to FileSystemManagerImpl instances being fuzzed.
+  // Access only from UI thread.
+  std::unique_ptr<FileSystemManagerImpl>
+      file_system_manager_impls_[kNumRenderers];
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+FileSystemManagerTestcase::FileSystemManagerTestcase(
+    const content::fuzzing::file_system_manager::proto::Testcase& testcase)
+    : testcase_(testcase), browser_context_() {
+  // FileSystemManagerTestcase is created on the main thread, but the actions
+  // that we want to validate the sequencing of take place on the fuzzer
+  // sequence.
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+void FileSystemManagerTestcase::SetUp() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  base::RunLoop io_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  base::PostTaskAndReply(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(&FileSystemManagerTestcase::SetUpOnIOThread,
+                     base::Unretained(this)),
+      io_run_loop.QuitClosure());
+  io_run_loop.Run();
+
+  base::RunLoop ui_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  base::PostTaskAndReply(
+      FROM_HERE, {BrowserThread::UI},
+      base::BindOnce(&FileSystemManagerTestcase::SetUpOnUIThread,
+                     base::Unretained(this)),
+      ui_run_loop.QuitClosure());
+  ui_run_loop.Run();
+}
+
+void FileSystemManagerTestcase::SetUpOnIOThread() {
+  CHECK(temp_dir_.CreateUniqueTempDir());
+  file_system_context_ =
+      storage::CreateFileSystemContextForTesting(nullptr, temp_dir_.GetPath());
+
+  blob_storage_context_ = base::MakeRefCounted<ChromeBlobStorageContext>();
+  blob_storage_context_->InitializeOnIOThread(
+      temp_dir_.GetPath(), temp_dir_.GetPath(),
+      base::CreateSingleThreadTaskRunner({BrowserThread::IO}));
+}
+
+void FileSystemManagerTestcase::SetUpOnUIThread() {
+  ChildProcessSecurityPolicyImpl* p =
+      ChildProcessSecurityPolicyImpl::GetInstance();
+  p->RegisterFileSystemPermissionPolicy(storage::kFileSystemTypeTest,
+                                        storage::FILE_PERMISSION_SANDBOX);
+  p->RegisterFileSystemPermissionPolicy(storage::kFileSystemTypeTemporary,
+                                        storage::FILE_PERMISSION_SANDBOX);
+
+  // Note - FileSystemManagerImpl must be constructed on the UI thread, but all
+  // other methods are expected to be called on the IO thread - see comments in
+  // content/browser/file_system/file_system_manager_impl.h
+  for (size_t i = 0; i < kNumRenderers; i++) {
+    file_system_manager_impls_[i] = std::make_unique<FileSystemManagerImpl>(
+        i, file_system_context_, blob_storage_context_);
+    p->Add(i, &browser_context_);
+  }
+}
+
+void FileSystemManagerTestcase::TearDown() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  base::RunLoop ui_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  base::PostTaskAndReply(
+      FROM_HERE, {content::BrowserThread::UI},
+      base::BindOnce(&FileSystemManagerTestcase::TearDownOnUIThread,
+                     base::Unretained(this)),
+      ui_run_loop.QuitClosure());
+  ui_run_loop.Run();
+
+  base::RunLoop io_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  base::PostTaskAndReply(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::BindOnce(&FileSystemManagerTestcase::TearDownOnIOThread,
+                     base::Unretained(this)),
+      io_run_loop.QuitClosure());
+  io_run_loop.Run();
+}
+
+void FileSystemManagerTestcase::TearDownOnIOThread() {
+  for (size_t i = 0; i < kNumRenderers; i++) {
+    file_system_manager_impls_[i].reset();
+  }
+}
+
+void FileSystemManagerTestcase::TearDownOnUIThread() {
+  ChildProcessSecurityPolicyImpl* p =
+      ChildProcessSecurityPolicyImpl::GetInstance();
+  for (size_t i = 0; i < kNumRenderers; i++) {
+    p->Remove(i);
+  }
+}
+
+bool FileSystemManagerTestcase::IsFinished() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return next_sequence_idx_ >= testcase_.sequence_indexes_size();
+}
+
+void FileSystemManagerTestcase::NextAction() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (next_sequence_idx_ < testcase_.sequence_indexes_size()) {
+    auto sequence_idx = testcase_.sequence_indexes(next_sequence_idx_++);
+    const auto& sequence =
+        testcase_.sequences(sequence_idx % testcase_.sequences_size());
+    for (auto action_idx : sequence.action_indexes()) {
+      if (!testcase_.actions_size() || ++action_count_ > max_action_count_) {
+        return;
+      }
+      const auto& action =
+          testcase_.actions(action_idx % testcase_.actions_size());
+      switch (action.action_case()) {
+        case Action::kNewFileSystemManager:
+          AddFileSystemManager(
+              action.new_file_system_manager().id(),
+              action.new_file_system_manager().render_process_id());
+          break;
+
+        case Action::kRunThread:
+          if (action.run_thread().id()) {
+            base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+            base::PostTask(FROM_HERE, {BrowserThread::UI},
+                           run_loop.QuitClosure());
+            run_loop.Run();
+          } else {
+            base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+            base::PostTask(FROM_HERE, {BrowserThread::IO},
+                           run_loop.QuitClosure());
+            run_loop.Run();
+          }
+          break;
+
+        case Action::kFileSystemManagerRemoteAction:
+          mojolpm::HandleRemoteAction(
+              action.file_system_manager_remote_action());
+          break;
+
+        case Action::kFileSystemCancellableOperationRemoteAction:
+          mojolpm::HandleRemoteAction(
+              action.file_system_cancellable_operation_remote_action());
+          break;
+
+        case Action::ACTION_NOT_SET:
+          break;
+      }
+    }
+  }
+}
+
+void FileSystemManagerTestcase::AddFileSystemManagerImpl(
+    uint32_t id,
+    content::fuzzing::file_system_manager::proto::NewFileSystemManagerAction::
+        RenderProcessId render_process_id,
+    mojo::PendingReceiver<::blink::mojom::FileSystemManager>&& receiver) {
+  size_t offset = render_process_id ==
+                          content::fuzzing::file_system_manager::proto::
+                              NewFileSystemManagerAction_RenderProcessId_ZERO
+                      ? 0
+                      : 1;
+  file_system_manager_impls_[offset]->BindReceiver(std::move(receiver));
+}
+
+void FileSystemManagerTestcase::AddFileSystemManager(
+    uint32_t id,
+    content::fuzzing::file_system_manager::proto::NewFileSystemManagerAction::
+        RenderProcessId render_process_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  mojo::Remote<::blink::mojom::FileSystemManager> remote;
+  auto receiver = remote.BindNewPipeAndPassReceiver();
+
+  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  base::PostTaskAndReply(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::BindOnce(&FileSystemManagerTestcase::AddFileSystemManagerImpl,
+                     base::Unretained(this), id, render_process_id,
+                     std::move(receiver)),
+      run_loop.QuitClosure());
+  run_loop.Run();
+
+  mojolpm::GetContext()->AddInstance(id, std::move(remote));
+}
+}  // namespace content
+
+// Helper function to keep scheduling fuzzer actions on the current runloop
+// until the testcase has completed, and then quit the runloop.
+void NextAction(content::FileSystemManagerTestcase* testcase,
+                base::RepeatingClosure quit_closure) {
+  if (!testcase->IsFinished()) {
+    testcase->NextAction();
+    content::GetFuzzerTaskRunner()->PostTask(
+        FROM_HERE, base::BindOnce(NextAction, base::Unretained(testcase),
+                                  std::move(quit_closure)));
+  } else {
+    content::GetFuzzerTaskRunner()->PostTask(FROM_HERE,
+                                             std::move(quit_closure));
+  }
+}
+
+// Helper function to setup and run the testcase, since we need to do that from
+// the fuzzer sequence rather than the main thread.
+void RunTestcase(content::FileSystemManagerTestcase* testcase) {
+  mojo::Message message;
+  auto dispatch_context =
+      std::make_unique<mojo::internal::MessageDispatchContext>(&message);
+
+  testcase->SetUp();
+
+  mojolpm::GetContext()->StartTestcase();
+
+  base::RunLoop fuzzer_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  content::GetFuzzerTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(NextAction, base::Unretained(testcase),
+                                fuzzer_run_loop.QuitClosure()));
+  fuzzer_run_loop.Run();
+
+  mojolpm::GetContext()->EndTestcase();
+
+  testcase->TearDown();
+}
+
+DEFINE_BINARY_PROTO_FUZZER(
+    const content::fuzzing::file_system_manager::proto::Testcase&
+        proto_testcase) {
+  if (!proto_testcase.actions_size() || !proto_testcase.sequences_size() ||
+      !proto_testcase.sequence_indexes_size()) {
+    return;
+  }
+
+  // Make sure that the environment is initialized before we do anything else.
+  content::GetEnvironment();
+
+  content::FileSystemManagerTestcase testcase(proto_testcase);
+
+  base::RunLoop ui_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+
+  // Unretained is safe here, because ui_run_loop has to finish before testcase
+  // goes out of scope.
+  content::GetFuzzerTaskRunner()->PostTaskAndReply(
+      FROM_HERE, base::BindOnce(RunTestcase, base::Unretained(&testcase)),
+      ui_run_loop.QuitClosure());
+
+  ui_run_loop.Run();
+}
diff --git a/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.proto b/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.proto
new file mode 100644
index 0000000..ce269768
--- /dev/null
+++ b/content/test/fuzzer/file_system_manager_mojolpm_fuzzer.proto
@@ -0,0 +1,59 @@
+// 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.
+
+// Message format for the MojoLPM fuzzer for the FileSystemManager interface.
+
+syntax = "proto2";
+
+package content.fuzzing.file_system_manager.proto;
+
+import "third_party/blink/public/mojom/filesystem/file_system.mojom.mojolpm.proto";
+
+// Bind a new FileSystemManager remote
+message NewFileSystemManagerAction {
+  enum RenderProcessId {
+    ZERO = 0;
+    ONE = 1;
+  }
+
+  required uint32 id = 1;
+  required RenderProcessId render_process_id = 2;
+}
+
+// Run the specific sequence for (an indeterminate) period. This is not
+// intended to create a specific ordering, but to allow the fuzzer to delay a
+// later task until previous tasks have completed.
+message RunThreadAction {
+  enum ThreadId {
+    IO = 0;
+    UI = 1;
+  }
+
+  required ThreadId id = 1;
+}
+
+// Actions that can be performed by the fuzzer.
+message Action {
+  oneof action {
+    NewFileSystemManagerAction new_file_system_manager = 1;
+    RunThreadAction run_thread = 2;
+    mojolpm.blink.mojom.FileSystemManager.RemoteAction
+        file_system_manager_remote_action = 3;
+    mojolpm.blink.mojom.FileSystemCancellableOperation.RemoteAction
+        file_system_cancellable_operation_remote_action = 4;
+  }
+}
+
+// Sequence provides a level of indirection which allows Testcase to compactly
+// express repeated sequences of actions.
+message Sequence {
+  repeated uint32 action_indexes = 1 [packed = true];
+}
+
+// Testcase is the top-level message type interpreted by the fuzzer.
+message Testcase {
+  repeated Action actions = 1;
+  repeated Sequence sequences = 2;
+  repeated uint32 sequence_indexes = 3 [packed = true];
+}
\ No newline at end of file
diff --git a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt
index f1ac381..9909a20 100644
--- a/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/screenshot_sync_expectations.txt
@@ -22,7 +22,3 @@
 crbug.com/1006045 [ android android-nexus-5x skia-renderer ] ScreenshotSync_GPURasterWithDivs [ Failure ]
 crbug.com/1006045 [ android android-nexus-5x skia-renderer ] ScreenshotSync_SWRasterWithCanvas [ Failure ]
 crbug.com/1006045 [ android android-nexus-5x skia-renderer ] ScreenshotSync_SWRasterWithDivs [ Failure ]
-
-# Fuchsia
-crbug.com/1097962 [ fuchsia ] ScreenshotSync_SWRasterWithCanvas [ RetryOnFailure ]
-crbug.com/1097962 [ fuchsia ] ScreenshotSync_GPURasterWithCanvas [ RetryOnFailure ]
diff --git a/device/gamepad/gamepad_provider.cc b/device/gamepad/gamepad_provider.cc
index 89439c77..ecc5837 100644
--- a/device/gamepad/gamepad_provider.cc
+++ b/device/gamepad/gamepad_provider.cc
@@ -29,6 +29,8 @@
 
 namespace device {
 
+constexpr int64_t kPollingIntervalMilliseconds = 4;  // ~250 Hz
+
 GamepadProvider::GamepadProvider(
     GamepadConnectionChangeClient* connection_change_client)
     : gamepad_shared_buffer_(std::make_unique<GamepadSharedBuffer>()),
@@ -139,7 +141,7 @@
 
 void GamepadProvider::Initialize(std::unique_ptr<GamepadDataFetcher> fetcher) {
   sampling_interval_delta_ =
-      base::TimeDelta::FromMilliseconds(features::GetGamepadPollingInterval());
+      base::TimeDelta::FromMilliseconds(kPollingIntervalMilliseconds);
 
   base::SystemMonitor* monitor = base::SystemMonitor::Get();
   if (monitor)
diff --git a/device/gamepad/public/cpp/gamepad_features.cc b/device/gamepad/public/cpp/gamepad_features.cc
index c74ddbb2..d942501 100644
--- a/device/gamepad/public/cpp/gamepad_features.cc
+++ b/device/gamepad/public/cpp/gamepad_features.cc
@@ -15,24 +15,6 @@
 
 namespace features {
 
-namespace {
-
-const size_t kPollingIntervalMillisecondsMin = 4;   // ~250 Hz
-const size_t kPollingIntervalMillisecondsMax = 16;  // ~62.5 Hz
-
-size_t OverrideIntervalIfValid(base::StringPiece param_value,
-                               size_t default_interval) {
-  size_t interval;
-  if (param_value.empty() || !base::StringToSizeT(param_value, &interval))
-    return default_interval;
-  // Clamp interval duration to valid range.
-  interval = std::max(interval, kPollingIntervalMillisecondsMin);
-  interval = std::min(interval, kPollingIntervalMillisecondsMax);
-  return interval;
-}
-
-}  // namespace
-
 // Enables gamepadbuttondown, gamepadbuttonup, gamepadbuttonchange,
 // gamepadaxismove non-standard gamepad events.
 const base::Feature kEnableGamepadButtonAxisEvents{
@@ -42,15 +24,9 @@
 const base::Feature kEnableWindowsGamingInputDataFetcher{
     "EnableWindowsGamingInputDataFetcher", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Overrides the gamepad polling interval.
-const base::Feature kGamepadPollingInterval{"GamepadPollingInterval",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kRestrictGamepadAccess{"RestrictGamepadAccess",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
-const char kGamepadPollingIntervalParamKey[] = "interval-ms";
-
 bool AreGamepadButtonAxisEventsEnabled() {
   // Check if button and axis events are enabled by a field trial.
   if (base::FeatureList::IsEnabled(kEnableGamepadButtonAxisEvents))
@@ -66,27 +42,4 @@
   return false;
 }
 
-size_t GetGamepadPollingInterval() {
-  // Default to the minimum polling interval.
-  size_t polling_interval = kPollingIntervalMillisecondsMin;
-
-  // Check if the polling interval is overridden by a field trial.
-  if (base::FeatureList::IsEnabled(kGamepadPollingInterval)) {
-    std::string param_value = base::GetFieldTrialParamValueByFeature(
-        kGamepadPollingInterval, kGamepadPollingIntervalParamKey);
-    polling_interval = OverrideIntervalIfValid(param_value, polling_interval);
-  }
-
-  // Check if the polling interval is overridden by a command-line flag.
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line &&
-      command_line->HasSwitch(switches::kGamepadPollingInterval)) {
-    std::string switch_value =
-        command_line->GetSwitchValueASCII(switches::kGamepadPollingInterval);
-    polling_interval = OverrideIntervalIfValid(switch_value, polling_interval);
-  }
-
-  return polling_interval;
-}
-
 }  // namespace features
diff --git a/device/gamepad/public/cpp/gamepad_features.h b/device/gamepad/public/cpp/gamepad_features.h
index d5fc29c7..12e8576 100644
--- a/device/gamepad/public/cpp/gamepad_features.h
+++ b/device/gamepad/public/cpp/gamepad_features.h
@@ -14,12 +14,9 @@
     kEnableGamepadButtonAxisEvents;
 GAMEPAD_FEATURES_EXPORT extern const base::Feature
     kEnableWindowsGamingInputDataFetcher;
-GAMEPAD_FEATURES_EXPORT extern const base::Feature kGamepadPollingInterval;
 GAMEPAD_FEATURES_EXPORT extern const base::Feature kRestrictGamepadAccess;
-GAMEPAD_FEATURES_EXPORT extern const char kGamepadPollingIntervalParamKey[];
 
 GAMEPAD_FEATURES_EXPORT bool AreGamepadButtonAxisEventsEnabled();
-GAMEPAD_FEATURES_EXPORT size_t GetGamepadPollingInterval();
 
 }  // namespace features
 
diff --git a/docs/memory/debugging_memory_issues.md b/docs/memory/debugging_memory_issues.md
index 892abe7..db23edd 100644
--- a/docs/memory/debugging_memory_issues.md
+++ b/docs/memory/debugging_memory_issues.md
@@ -78,7 +78,7 @@
   This interface surfaces all available information, but can be overwhelming and
   is usually unnecessary for investigating heap dumps.
     * Important note: Heap profiling in the field uses
-      [poison process sampling](https://bugs.chromium.org/p/chromium/issues/detail?id=810748)
+      [Poisson process sampling](https://bugs.chromium.org/p/chromium/issues/detail?id=810748)
       with a rate parameter of 10000. This means that for large/frequent allocations
       [e.g. >100 MB], the noise will be quite small [much less than 1%]. But
       there is noise so counts will not be exact.
diff --git a/docs/no_sources_assignment_filter.md b/docs/no_sources_assignment_filter.md
index 7b9087b..428cc9c2 100644
--- a/docs/no_sources_assignment_filter.md
+++ b/docs/no_sources_assignment_filter.md
@@ -10,8 +10,9 @@
 that will be used to filter names every time a variable named "sources" is
 assigned a value.
 
-As Chromium calls this function in build/BUILDCONFIG.gn, the patterns are
-applied to every BUILD.gn file in the project. This has multiple drawbacks:
+Historically, Chromium used to call this function in build/BUILDCONFIG.gn thus
+causing the patterns to be applied to every BUILD.gn file in the project. This
+had multiple drawbacks:
 
 1.  the configuration of the list of patterns is located far from the point
     where they are applied and developer are usually confused when a file
@@ -26,6 +27,9 @@
     in the whole project, thus it has significant negative impact on the
     performance of gn
 
+Since September 2020, the filter is enabled only for the files that have not
+yet been converted. Eventually, this will be removed.
+
 ## Conversion pattern
 
 To convert a BUILD.gn file it is necessary to change the following:
@@ -70,19 +74,14 @@
 it is compatible whether the set_sources_assignment_filter feature is used or
 not.
 
-## Preventing regression
-
-As said above, while the converted file are compatible with the feature, there
-is a risk of regression. To prevent such regression, the following is added at
-the top of every BUILD.gn file after it has been converted:
+Once conversion is done, remove the following lines from the top of the file
+to avoid regressions:
 
 ```
-  # Reset sources_assignment_filter for the BUILD.gn file to prevent
-  # regression during the migration of Chromium away from the feature.
-  # See docs/no_sources_assignment_filter.md for more information.
-  # TODO(crbug.com/1018739): remove this when migration is done.
-  set_sources_assignment_filter([])
+import("//build/config/deprecated_default_sources_assignment_filter.gni")
+sources_assignment_filter = deprecated_default_sources_assignment_filter
 ```
 
+
 [0]: https://groups.google.com/a/chromium.org/d/topic/chromium-dev/hyLuCU6g2V4/discussion
 [1]: https://groups.google.com/a/chromium.org/d/topic/gn-dev/oQcYStl_WkI/discussion
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index c73061c8..6c6480d 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -231,7 +231,8 @@
         "chrome://hats/*",
         "chrome://mobilesetup/*",
         "chrome://oobe/*",
-        "chrome://password-change/*"
+        "chrome://password-change/*",
+        "chrome://lock-reauth/*"
       ]
     }
   ],
@@ -652,7 +653,8 @@
       "chrome://home/*",
       "chrome://mobilesetup/*",
       "chrome://oobe/*",
-      "chrome://password-change/*"
+      "chrome://password-change/*",
+      "chrome://lock-reauth/*"
     ]
   }],
   "webViewInternal": [{
@@ -673,7 +675,8 @@
       "chrome://home/*",
       "chrome://mobilesetup/*",
       "chrome://oobe/*",
-      "chrome://password-change/*"
+      "chrome://password-change/*",
+      "chrome://lock-reauth/*"
     ]
   }],
   "webViewRequest": [{
diff --git a/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc b/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
index 1fffef3..39cc85a 100644
--- a/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
+++ b/extensions/renderer/api/automation/automation_ax_tree_wrapper.cc
@@ -280,7 +280,7 @@
     bool root_changed,
     const std::vector<ui::AXTreeObserver::Change>& changes) {
   DCHECK_EQ(&tree_, tree);
-  for (const auto change : changes) {
+  for (const auto& change : changes) {
     ui::AXNode* node = change.node;
     switch (change.type) {
       case NODE_CREATED:
diff --git a/gpu/command_buffer/service/external_vk_image_backing.cc b/gpu/command_buffer/service/external_vk_image_backing.cc
index 6ac0998..48bb0d8 100644
--- a/gpu/command_buffer/service/external_vk_image_backing.cc
+++ b/gpu/command_buffer/service/external_vk_image_backing.cc
@@ -166,7 +166,7 @@
 
 // static
 std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::Create(
-    SharedContextState* context_state,
+    scoped_refptr<SharedContextState> context_state,
     VulkanCommandPool* command_pool,
     const Mailbox& mailbox,
     viz::ResourceFormat format,
@@ -206,7 +206,7 @@
     // Must request all available image usage flags if aliasing GL texture. This
     // is a spec requirement per EXT_memory_object. However, if
     // ANGLE_memory_object_flags is supported, usage flags can be arbitrary.
-    if (UseMinimalUsageFlags(context_state)) {
+    if (UseMinimalUsageFlags(context_state.get())) {
       // The following additional usage flags are provided for ANGLE:
       //
       // - TRANSFER_SRC: Used for copies from this image.
@@ -247,10 +247,11 @@
   if (!image)
     return nullptr;
 
-  bool use_separate_gl_texture = UseSeparateGLTexture(context_state, format);
+  bool use_separate_gl_texture =
+      UseSeparateGLTexture(context_state.get(), format);
   auto backing = std::make_unique<ExternalVkImageBacking>(
       util::PassKey<ExternalVkImageBacking>(), mailbox, format, size,
-      color_space, surface_origin, alpha_type, usage, context_state,
+      color_space, surface_origin, alpha_type, usage, std::move(context_state),
       std::move(image), command_pool, use_separate_gl_texture);
 
   if (!pixel_data.empty()) {
@@ -263,7 +264,7 @@
 
 // static
 std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::CreateFromGMB(
-    SharedContextState* context_state,
+    scoped_refptr<SharedContextState> context_state,
     VulkanCommandPool* command_pool,
     const Mailbox& mailbox,
     gfx::GpuMemoryBufferHandle handle,
@@ -293,11 +294,12 @@
     }
 
     bool use_separate_gl_texture =
-        UseSeparateGLTexture(context_state, resource_format);
+        UseSeparateGLTexture(context_state.get(), resource_format);
     auto backing = std::make_unique<ExternalVkImageBacking>(
         util::PassKey<ExternalVkImageBacking>(), mailbox, resource_format, size,
-        color_space, surface_origin, alpha_type, usage, context_state,
-        std::move(image), command_pool, use_separate_gl_texture);
+        color_space, surface_origin, alpha_type, usage,
+        std::move(context_state), std::move(image), command_pool,
+        use_separate_gl_texture);
     backing->SetCleared();
     return backing;
   }
@@ -313,10 +315,10 @@
   if (!shared_memory_wrapper.Initialize(handle, size, resource_format))
     return nullptr;
 
-  auto backing =
-      Create(context_state, command_pool, mailbox, resource_format, size,
-             color_space, surface_origin, alpha_type, usage, image_usage_cache,
-             base::span<const uint8_t>(), true /* using_gmb */);
+  auto backing = Create(std::move(context_state), command_pool, mailbox,
+                        resource_format, size, color_space, surface_origin,
+                        alpha_type, usage, image_usage_cache,
+                        base::span<const uint8_t>(), true /* using_gmb */);
   if (!backing)
     return nullptr;
 
@@ -333,7 +335,7 @@
     GrSurfaceOrigin surface_origin,
     SkAlphaType alpha_type,
     uint32_t usage,
-    SharedContextState* context_state,
+    scoped_refptr<SharedContextState> context_state,
     std::unique_ptr<VulkanImage> image,
     VulkanCommandPool* command_pool,
     bool use_separate_gl_texture)
@@ -346,7 +348,7 @@
                                       usage,
                                       image->device_size(),
                                       false /* is_thread_safe */),
-      context_state_(context_state),
+      context_state_(std::move(context_state)),
       image_(std::move(image)),
       backend_texture_(size.width(),
                        size.height(),
@@ -554,10 +556,8 @@
     // signalling but have not been signalled. In that case, we have to release
     // them via fence helper to make sure all submitted GPU works is finished
     // before releasing them.
-    // |context_state_| is out live fence_helper, so it is safe to use
-    // base::Unretained(context_state_).
     fence_helper()->EnqueueCleanupTaskForSubmittedWork(base::BindOnce(
-        [](SharedContextState* shared_context_state,
+        [](scoped_refptr<SharedContextState> shared_context_state,
            std::vector<ExternalSemaphore>, VulkanDeviceQueue* device_queue,
            bool device_lost) {
           if (!gl::GLContext::GetCurrent()) {
@@ -565,7 +565,7 @@
                                               /*needs_gl=*/true);
           }
         },
-        base::Unretained(context_state_), std::move(semaphores)));
+        context_state_, std::move(semaphores)));
   }
 }
 
@@ -662,7 +662,7 @@
     // If ANGLE_memory_object_flags is supported, use that to communicate the
     // exact create and usage flags the image was created with.
     DCHECK(image_->usage() != 0);
-    if (UseMinimalUsageFlags(context_state_)) {
+    if (UseMinimalUsageFlags(context_state())) {
       api->glTexStorageMemFlags2DANGLEFn(
           GL_TEXTURE_2D, 1, internal_format, size().width(), size().height(),
           memory_object->id(), 0, image_->flags(), image_->usage());
@@ -749,7 +749,7 @@
     scoped_refptr<SharedContextState> context_state) {
   // This backing type is only used when vulkan is enabled, so SkiaRenderer
   // should also be using Vulkan.
-  DCHECK_EQ(context_state_, context_state.get());
+  DCHECK_EQ(context_state_, context_state);
   DCHECK(context_state->GrContextIsVulkan());
   return std::make_unique<ExternalVkImageSkiaRepresentation>(manager, this,
                                                              tracker);
diff --git a/gpu/command_buffer/service/external_vk_image_backing.h b/gpu/command_buffer/service/external_vk_image_backing.h
index 4d4523a..27397700 100644
--- a/gpu/command_buffer/service/external_vk_image_backing.h
+++ b/gpu/command_buffer/service/external_vk_image_backing.h
@@ -34,7 +34,7 @@
 class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking {
  public:
   static std::unique_ptr<ExternalVkImageBacking> Create(
-      SharedContextState* context_state,
+      scoped_refptr<SharedContextState> context_state,
       VulkanCommandPool* command_pool,
       const Mailbox& mailbox,
       viz::ResourceFormat format,
@@ -48,7 +48,7 @@
       bool using_gmb = false);
 
   static std::unique_ptr<ExternalVkImageBacking> CreateFromGMB(
-      SharedContextState* context_state,
+      scoped_refptr<SharedContextState> context_state,
       VulkanCommandPool* command_pool,
       const Mailbox& mailbox,
       gfx::GpuMemoryBufferHandle handle,
@@ -68,14 +68,14 @@
                          GrSurfaceOrigin surface_origin,
                          SkAlphaType alpha_type,
                          uint32_t usage,
-                         SharedContextState* context_state,
+                         scoped_refptr<SharedContextState> context_state,
                          std::unique_ptr<VulkanImage> image,
                          VulkanCommandPool* command_pool,
                          bool use_separate_gl_texture);
 
   ~ExternalVkImageBacking() override;
 
-  SharedContextState* context_state() const { return context_state_; }
+  SharedContextState* context_state() const { return context_state_.get(); }
   const GrBackendTexture& backend_texture() const { return backend_texture_; }
   VulkanImage* image() const { return image_.get(); }
   const scoped_refptr<gles2::TexturePassthrough>& GetTexturePassthrough()
@@ -178,7 +178,7 @@
   void CopyPixelsFromGLTextureToVkImage();
   void CopyPixelsFromShmToGLTexture();
 
-  SharedContextState* const context_state_;
+  scoped_refptr<SharedContextState> context_state_;
   std::unique_ptr<VulkanImage> image_;
   GrBackendTexture backend_texture_;
   VulkanCommandPool* const command_pool_;
diff --git a/gpu/command_buffer/service/external_vk_image_factory.cc b/gpu/command_buffer/service/external_vk_image_factory.cc
index be1f1ad8..1ac61030 100644
--- a/gpu/command_buffer/service/external_vk_image_factory.cc
+++ b/gpu/command_buffer/service/external_vk_image_factory.cc
@@ -61,8 +61,8 @@
 }  // namespace
 
 ExternalVkImageFactory::ExternalVkImageFactory(
-    SharedContextState* context_state)
-    : context_state_(context_state),
+    scoped_refptr<SharedContextState> context_state)
+    : context_state_(std::move(context_state)),
       command_pool_(context_state_->vk_context_provider()
                         ->GetDeviceQueue()
                         ->CreateCommandPool()),
diff --git a/gpu/command_buffer/service/external_vk_image_factory.h b/gpu/command_buffer/service/external_vk_image_factory.h
index 63d36f2..f736400c 100644
--- a/gpu/command_buffer/service/external_vk_image_factory.h
+++ b/gpu/command_buffer/service/external_vk_image_factory.h
@@ -22,7 +22,8 @@
 // that allow it to be exported out and shared with GL.
 class ExternalVkImageFactory : public SharedImageBackingFactory {
  public:
-  explicit ExternalVkImageFactory(SharedContextState* context_state);
+  explicit ExternalVkImageFactory(
+      scoped_refptr<SharedContextState> context_state);
   ~ExternalVkImageFactory() override;
 
   // SharedImageBackingFactory implementation.
@@ -66,7 +67,7 @@
 
   void TransitionToColorAttachment(VkImage image);
 
-  SharedContextState* const context_state_;
+  scoped_refptr<SharedContextState> context_state_;
   std::unique_ptr<VulkanCommandPool> command_pool_;
 
   const VulkanImageUsageCache image_usage_cache_;
diff --git a/gpu/ipc/shared_image_interface_in_process.cc b/gpu/ipc/shared_image_interface_in_process.cc
index 958355a..c0629c8 100644
--- a/gpu/ipc/shared_image_interface_in_process.cc
+++ b/gpu/ipc/shared_image_interface_in_process.cc
@@ -84,8 +84,10 @@
 void SharedImageInterfaceInProcess::DestroyOnGpu(
     base::WaitableEvent* completion) {
   bool have_context = MakeContextCurrent();
-  if (shared_image_factory_)
+  if (shared_image_factory_) {
     shared_image_factory_->DestroyAllSharedImages(have_context);
+    shared_image_factory_ = nullptr;
+  }
 
   if (sync_point_client_state_) {
     sync_point_client_state_->Destroy();
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 24c6aff3..972d0f3 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
@@ -178,10 +178,6 @@
     [[bvc_ view] removeFromSuperview];
     [bvc_ shutdown];
 
-    // Cleanup to avoid debugger crash in non empty observer lists.
-    browser_->GetWebStateList()->CloseAllWebStates(
-        WebStateList::ClosingFlags::CLOSE_NO_FLAGS);
-
     BlockCleanupTest::TearDown();
   }
 
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm
index c4a279714..f6d4ba34 100644
--- a/ios/chrome/browser/ui/history/history_ui_egtest.mm
+++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -33,12 +33,10 @@
 #endif
 
 using chrome_test_util::ButtonWithAccessibilityLabelId;
-using chrome_test_util::CopyLinkButton;
 using chrome_test_util::HistoryEntry;
 using chrome_test_util::NavigationBarDoneButton;
-using chrome_test_util::OpenLinkInNewTabButton;
-using chrome_test_util::OpenLinkInIncognitoButton;
 using chrome_test_util::OpenLinkInNewWindowButton;
+using chrome_test_util::DeleteButton;
 
 namespace {
 char kURL1[] = "/firstURL";
@@ -392,12 +390,7 @@
 
   // Select "Open in New Tab" and confirm that new tab is opened with selected
   // URL.
-  [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(
-                                          _URL1.GetContent())]
-      assertWithMatcher:grey_notNil()];
-  [ChromeEarlGrey waitForMainTabCount:2];
+  [ChromeEarlGrey verifyOpenInNewTabActionWithURL:_URL1.GetContent()];
 }
 
 // Tests display and selection of 'Open in New Window' in a context menu on a
@@ -444,31 +437,15 @@
 
   // Select "Open in New Incognito Tab" and confirm that new tab is opened in
   // incognito with the selected URL.
-  [[EarlGrey selectElementWithMatcher:OpenLinkInIncognitoButton([ChromeEarlGrey
-                                          isNativeContextMenusEnabled])]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(
-                                          _URL1.GetContent())]
-      assertWithMatcher:grey_notNil()];
-  [ChromeEarlGrey waitForMainTabCount:1];
-  [ChromeEarlGrey waitForIncognitoTabCount:1];
+  [ChromeEarlGrey
+      verifyOpenInIncognitoActionWithURL:_URL1.GetContent()
+                            useNewString:[ChromeEarlGrey
+                                             isNativeContextMenusEnabled]];
 }
 
 // Tests display and selection of 'Copy URL' in a context menu on a history
 // entry.
-// TODO(crbug.com/1067812): Test won't pass on devices.
-#if TARGET_IPHONE_SIMULATOR
-#define MAYBE_testContextMenuCopy testContextMenuCopy
-#else
-#define MAYBE_testContextMenuCopy DISABLED_testContextMenuCopy
-#endif
-- (void)MAYBE_testContextMenuCopy {
-  ProceduralBlock clearPasteboard = ^{
-    [[UIPasteboard generalPasteboard] setURLs:nil];
-  };
-  [self setTearDownHandler:clearPasteboard];
-  clearPasteboard();
-
+- (void)testContextMenuCopy {
   [self loadTestURLs];
   [self openHistoryPanel];
 
@@ -478,16 +455,66 @@
       performAction:grey_longPress()];
 
   // Tap "Copy URL" and wait for the URL to be copied to the pasteboard.
-  [[EarlGrey selectElementWithMatcher:CopyLinkButton([ChromeEarlGrey
-                                          isNativeContextMenusEnabled])]
-      performAction:grey_tap()];
-  bool success = base::test::ios::WaitUntilConditionOrTimeout(
-      base::test::ios::kWaitForUIElementTimeout, ^{
-        return _URL1 ==
-               net::GURLWithNSURL([UIPasteboard generalPasteboard].URL);
-      });
-  GREYAssertTrue(success, @"Pasteboard URL was not set to %s",
-                 _URL1.spec().c_str());
+  [ChromeEarlGrey
+      verifyCopyLinkActionWithText:[NSString stringWithUTF8String:_URL1.spec()
+                                                                      .c_str()]
+                      useNewString:[ChromeEarlGrey
+                                       isNativeContextMenusEnabled]];
+}
+
+// Tests display and selection of "Share" in the context menu for a history
+// entry.
+- (void)testContextMenuShare {
+  if (![ChromeEarlGrey isNativeContextMenusEnabled]) {
+    EARL_GREY_TEST_SKIPPED(
+        @"Test disabled when Native Context Menus feature flag is off.");
+  }
+
+  [self loadTestURLs];
+  [self openHistoryPanel];
+
+  // Long press on the history element.
+  [[EarlGrey
+      selectElementWithMatcher:HistoryEntry(_URL1.GetOrigin().spec(), kTitle1)]
+      performAction:grey_longPress()];
+
+  [ChromeEarlGrey
+      verifyShareActionWithPageTitle:[NSString stringWithUTF8String:kTitle1]];
+}
+
+// Tests the Delete context menu action for a History entry.
+- (void)testContextMenuDelete {
+  if (![ChromeEarlGrey isNativeContextMenusEnabled]) {
+    EARL_GREY_TEST_SKIPPED(
+        @"Test disabled when Native Context Menus feature flag is off.");
+  }
+
+  [self loadTestURLs];
+  [self openHistoryPanel];
+
+  // Long press on the history element.
+  [[EarlGrey
+      selectElementWithMatcher:HistoryEntry(_URL1.GetOrigin().spec(), kTitle1)]
+      performAction:grey_longPress()];
+
+  [[EarlGrey selectElementWithMatcher:DeleteButton()] performAction:grey_tap()];
+
+  // Assert that the deleted entry is gone and the other two remain.
+  [[EarlGrey
+      selectElementWithMatcher:HistoryEntry(_URL1.GetOrigin().spec(), kTitle1)]
+      assertWithMatcher:grey_nil()];
+
+  // Wait for the animations to be done, then validate.
+  [ChromeEarlGrey
+      waitForSufficientlyVisibleElementWithMatcher:HistoryEntry(
+                                                       _URL2.GetOrigin().spec(),
+                                                       kTitle2)];
+  [[EarlGrey
+      selectElementWithMatcher:HistoryEntry(_URL2.GetOrigin().spec(), kTitle2)]
+      assertWithMatcher:grey_notNil()];
+  [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL3.GetOrigin().spec(),
+                                                   _URL3.GetContent())]
+      assertWithMatcher:grey_notNil()];
 }
 
 // Tests that the VC can be dismissed by swiping down.
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
index ba23a30b..c9d9ee82 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
@@ -321,7 +321,8 @@
 // Tests the Copy Link action on a recent tab's context menu.
 - (void)testContextMenuCopyLink {
   if (![ChromeEarlGrey isNativeContextMenusEnabled]) {
-    EARL_GREY_TEST_SKIPPED(@"Test disabled on when feature flag is off.");
+    EARL_GREY_TEST_SKIPPED(
+        @"Test disabled when Native Context Menus feature flag is off.");
   }
 
   [self loadTestURL];
@@ -338,7 +339,8 @@
 // Tests the Open in New Tab action on a recent tab's context menu.
 - (void)testContextMenuOpenInNewTab {
   if (![ChromeEarlGrey isNativeContextMenusEnabled]) {
-    EARL_GREY_TEST_SKIPPED(@"Test disabled on when feature flag is off.");
+    EARL_GREY_TEST_SKIPPED(
+        @"Test disabled when Native Context Menus feature flag is off.");
   }
 
   [self loadTestURL];
@@ -355,7 +357,8 @@
 // Tests the Share action on a recent tab's context menu.
 - (void)testContextMenuShare {
   if (![ChromeEarlGrey isNativeContextMenusEnabled]) {
-    EARL_GREY_TEST_SKIPPED(@"Test disabled on when feature flag is off.");
+    EARL_GREY_TEST_SKIPPED(
+        @"Test disabled when Native Context Menus feature flag is off.");
   }
 
   [self loadTestURL];
diff --git a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
index 9021bfce..01d469b3 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_mediator.mm
@@ -90,15 +90,15 @@
     _syncService = syncService;
     _savedPasswordsConsumer =
         std::make_unique<ios::SavePasswordsConsumer>(self);
+    _passwordStoreObserver =
+        std::make_unique<PasswordStoreObserverBridge>(self);
+    _passwordStore->AddObserver(_passwordStoreObserver.get());
 
     if (base::FeatureList::IsEnabled(
             password_manager::features::kPasswordCheck)) {
       _passwordCheckManager = passwordCheckManager;
       _passwordCheckObserver = std::make_unique<PasswordCheckObserverBridge>(
           self, _passwordCheckManager.get());
-      _passwordStoreObserver =
-          std::make_unique<PasswordStoreObserverBridge>(self);
-      _passwordStore->AddObserver(_passwordStoreObserver.get());
     }
   }
   return self;
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.h b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.h
index 97ec81f..396d110 100644
--- a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.h
+++ b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.h
@@ -32,7 +32,7 @@
 @property(nonatomic, weak) UIImage* snapshot;
 @property(nonatomic, copy) NSString* title;
 @property(nonatomic, assign) BOOL titleHidden;
-@property(nonatomic, readonly) UIBezierPath* visiblePath;
+@property(nonatomic, readonly) UIDragPreviewParameters* dragPreviewParameters;
 @end
 
 // A GridCell for use in animated transitions that only shows selection state
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm
index 2349999..83339c3 100644
--- a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm
+++ b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm
@@ -255,10 +255,13 @@
   _titleHidden = titleHidden;
 }
 
-- (UIBezierPath*)visiblePath {
-  return [UIBezierPath
+- (UIDragPreviewParameters*)dragPreviewParameters {
+  UIBezierPath* visiblePath = [UIBezierPath
       bezierPathWithRoundedRect:self.bounds
                    cornerRadius:self.contentView.layer.cornerRadius];
+  UIDragPreviewParameters* params = [[UIDragPreviewParameters alloc] init];
+  params.visiblePath = visiblePath;
+  return params;
 }
 
 #pragma mark - Private
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_drag_drop_handler.h b/ios/chrome/browser/ui/tab_grid/grid/grid_drag_drop_handler.h
index dd35a39..1391156 100644
--- a/ios/chrome/browser/ui/tab_grid/grid/grid_drag_drop_handler.h
+++ b/ios/chrome/browser/ui/tab_grid/grid/grid_drag_drop_handler.h
@@ -25,10 +25,21 @@
 
 // Tells the receiver to incorporate the |dragItem| into the model layer at the
 // |destinationIndex|. |fromSameCollection| is an indication that the operation
-// is a reorder within the same collection.
+// is a reorder within the same collection. |dragItem| must have a localObject,
+// which means the item is dragged from within the same app.
 - (void)dropItem:(UIDragItem*)dragItem
                toIndex:(NSUInteger)destinationIndex
     fromSameCollection:(BOOL)fromSameCollection;
+
+// Tells the receiver to asynchronously extract data from |itemProvider| into
+// the model layer at the |destinationIndex|. |placeholderContext| is used to
+// delete the placeholder once the item is ready to be inserted into the model
+// layer.
+- (void)dropItemFromProvider:(NSItemProvider*)itemProvider
+                     toIndex:(NSUInteger)destinationIndex
+          placeholderContext:
+              (id<UICollectionViewDropPlaceholderContext>)placeholderContext;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_GRID_GRID_GRID_DRAG_DROP_HANDLER_H_
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm
index d9eac9ed..27e781f 100644
--- a/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm
@@ -438,11 +438,9 @@
 
 - (UIDragPreviewParameters*)collectionView:(UICollectionView*)collectionView
     dragPreviewParametersForItemAtIndexPath:(NSIndexPath*)indexPath {
-  UIDragPreviewParameters* params = [[UIDragPreviewParameters alloc] init];
-  GridCell* cell = base::mac::ObjCCastStrict<GridCell>(
+  GridCell* gridCell = base::mac::ObjCCastStrict<GridCell>(
       [self.collectionView cellForItemAtIndexPath:indexPath]);
-  params.visiblePath = cell.visiblePath;
-  return params;
+  return gridCell.dragPreviewParameters;
 }
 
 #pragma mark - UICollectionViewDropDelegate
@@ -471,21 +469,52 @@
         (id<UICollectionViewDropCoordinator>)coordinator {
   id<UICollectionViewDropItem> item = coordinator.items.firstObject;
 
-  NSIndexPath* dropIndexPath = coordinator.destinationIndexPath;
-  if (!dropIndexPath) {
-    dropIndexPath = [NSIndexPath indexPathForItem:(self.items.count - 1)
-                                        inSection:0];
+  // Append to the end of the collection, unless drop index is specified.
+  NSUInteger destinationIndex = self.items.count;
+  if (item.sourceIndexPath) {
+    // The sourceIndexPath is non-nil if the drop item is from this same
+    // collection view. Move to last position rather than appending if this is a
+    // reorder operation.
+    destinationIndex = self.items.count - 1;
+  }
+  if (coordinator.destinationIndexPath) {
+    destinationIndex =
+        base::checked_cast<NSUInteger>(coordinator.destinationIndexPath.item);
+  }
+  NSIndexPath* dropIndexPath = [NSIndexPath indexPathForItem:destinationIndex
+                                                   inSection:0];
+
+  // Drop synchronously if local object is available.
+  if (item.dragItem.localObject) {
+    [coordinator dropItem:item.dragItem toItemAtIndexPath:dropIndexPath];
+    // The sourceIndexPath is non-nil if the drop item is from this same
+    // collection view.
+    [self.dragDropHandler dropItem:item.dragItem
+                           toIndex:destinationIndex
+                fromSameCollection:(item.sourceIndexPath != nil)];
+    return;
   }
 
-  NSUInteger destinationIndex =
-      base::checked_cast<NSUInteger>(dropIndexPath.item);
-  [coordinator dropItem:item.dragItem toItemAtIndexPath:dropIndexPath];
+  // Drop asynchronously if local object is not available.
+  UICollectionViewDropPlaceholder* placeholder =
+      [[UICollectionViewDropPlaceholder alloc]
+          initWithInsertionIndexPath:dropIndexPath
+                     reuseIdentifier:kCellIdentifier];
+  placeholder.cellUpdateHandler = ^(UICollectionViewCell* placeholderCell) {
+    GridCell* gridCell = base::mac::ObjCCastStrict<GridCell>(placeholderCell);
+    gridCell.theme = self.theme;
+  };
+  placeholder.previewParametersProvider =
+      ^UIDragPreviewParameters*(UICollectionViewCell* placeholderCell) {
+    GridCell* gridCell = base::mac::ObjCCastStrict<GridCell>(placeholderCell);
+    return gridCell.dragPreviewParameters;
+  };
 
-  // TODO(crbug.com/1095200): Handle the edge case that two windows are
-  // simultaneously dragging and dropping.
-  [self.dragDropHandler dropItem:item.dragItem
-                         toIndex:destinationIndex
-              fromSameCollection:collectionView.hasActiveDrag];
+  id<UICollectionViewDropPlaceholderContext> context =
+      [coordinator dropItem:item.dragItem toPlaceholder:placeholder];
+  [self.dragDropHandler dropItemFromProvider:item.dragItem.itemProvider
+                                     toIndex:destinationIndex
+                          placeholderContext:context];
 }
 
 #pragma mark - UIScrollViewDelegate
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm
index 6373e03d..d4c2bfc 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm
@@ -160,7 +160,8 @@
 // Tests the Copy Link action on a recent tab's context menu.
 - (void)testRecentTabsContextMenuCopyLink {
   if (![ChromeEarlGrey isNativeContextMenusEnabled]) {
-    EARL_GREY_TEST_SKIPPED(@"Test disabled on when feature flag is off.");
+    EARL_GREY_TEST_SKIPPED(
+        @"Test disabled when Native Context Menus feature flag is off.");
   }
 
   [self prepareRecentTabWithURL:_URL1 response:kResponse1];
@@ -175,7 +176,8 @@
 // Tests the Open in New Tab action on a recent tab's context menu.
 - (void)testRecentTabsContextMenuOpenInNewTab {
   if (![ChromeEarlGrey isNativeContextMenusEnabled]) {
-    EARL_GREY_TEST_SKIPPED(@"Test disabled on when feature flag is off.");
+    EARL_GREY_TEST_SKIPPED(
+        @"Test disabled when Native Context Menus feature flag is off.");
   }
 
   [self prepareRecentTabWithURL:_URL1 response:kResponse1];
@@ -191,7 +193,8 @@
 // Tests the Share action on a recent tab's context menu.
 - (void)testRecentTabsContextMenuShare {
   if (![ChromeEarlGrey isNativeContextMenusEnabled]) {
-    EARL_GREY_TEST_SKIPPED(@"Test disabled on when feature flag is off.");
+    EARL_GREY_TEST_SKIPPED(
+        @"Test disabled when Native Context Menus feature flag is off.");
   }
 
   [self prepareRecentTabWithURL:_URL1 response:kResponse1];
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
index 65902ff2..90eac23 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
@@ -465,31 +465,34 @@
                        withURL:net::GURLWithNSURL(droppedURL)];
     return;
   }
+}
 
-  // Handle URLs from other apps asynchronously, as synchronous is not possible
-  // with NSItemProvider.
-  NSItemProvider* itemProvider = dragItem.itemProvider;
-  if ([itemProvider canLoadObjectOfClass:[NSURL class]]) {
-    // The parameter type has changed with Xcode 12 SDK.
-    // TODO(crbug.com/1098318): Remove this once Xcode 11 support is dropped.
-#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
-    using providerType = __kindof id<NSItemProviderReading>;
-#else
-    using providerType = id<NSItemProviderReading>;
-#endif
-
-    auto loadHandler = ^(providerType providedItem, NSError* error) {
-      dispatch_async(dispatch_get_main_queue(), ^{
-        NSURL* droppedURL = static_cast<NSURL*>(providedItem);
-        [self insertNewItemAtIndex:destinationIndex
-                           withURL:net::GURLWithNSURL(droppedURL)];
-      });
-    };
-
-    [itemProvider loadObjectOfClass:[NSURL class]
-                  completionHandler:loadHandler];
+- (void)dropItemFromProvider:(NSItemProvider*)itemProvider
+                     toIndex:(NSUInteger)destinationIndex
+          placeholderContext:
+              (id<UICollectionViewDropPlaceholderContext>)placeholderContext {
+  if (![itemProvider canLoadObjectOfClass:[NSURL class]]) {
+    [placeholderContext deletePlaceholder];
     return;
   }
+
+  // The parameter type has changed with Xcode 12 SDK.
+  // TODO(crbug.com/1098318): Remove this once Xcode 11 support is dropped.
+#if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0
+  using providerType = __kindof id<NSItemProviderReading>;
+#else
+  using providerType = id<NSItemProviderReading>;
+#endif
+
+  auto loadHandler = ^(providerType providedItem, NSError* error) {
+    dispatch_async(dispatch_get_main_queue(), ^{
+      [placeholderContext deletePlaceholder];
+      NSURL* droppedURL = static_cast<NSURL*>(providedItem);
+      [self insertNewItemAtIndex:destinationIndex
+                         withURL:net::GURLWithNSURL(droppedURL)];
+    });
+  };
+  [itemProvider loadObjectOfClass:[NSURL class] completionHandler:loadHandler];
 }
 
 #pragma mark - GridImageDataSource
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.h b/ios/chrome/test/earl_grey/chrome_earl_grey.h
index ac287ae..5bbb599 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.h
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.h
@@ -582,6 +582,12 @@
 // present in the omnibox.
 - (void)verifyOpenInNewTabActionWithURL:(const std::string&)URL;
 
+// Taps on the Open in Incognito context menu action and waits for the |URL| to
+// be present in the omnibox. |useNewString| determines which action string
+// to use.
+- (void)verifyOpenInIncognitoActionWithURL:(const std::string&)URL
+                              useNewString:(BOOL)useNewString;
+
 // Taps on the Share context menu action and validates that the ActivityView
 // was brought up with |pageTitle| in its header.
 - (void)verifyShareActionWithPageTitle:(NSString*)pageTitle;
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
index bc5fe2d..24aff468 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -41,6 +41,7 @@
 using chrome_test_util::ActivityViewHeader;
 using chrome_test_util::CopyLinkButton;
 using chrome_test_util::OpenLinkInNewTabButton;
+using chrome_test_util::OpenLinkInIncognitoButton;
 using chrome_test_util::ShareButton;
 
 namespace {
@@ -1058,6 +1059,7 @@
 
 - (void)verifyCopyLinkActionWithText:(NSString*)text
                         useNewString:(BOOL)useNewString {
+  [ChromeEarlGreyAppInterface clearPasteboardURLs];
   [[EarlGrey selectElementWithMatcher:CopyLinkButton(useNewString)]
       performAction:grey_tap()];
   [self verifyStringCopied:text];
@@ -1065,12 +1067,31 @@
 
 - (void)verifyOpenInNewTabActionWithURL:(const std::string&)URL {
   // Check tab count prior to execution.
-  NSUInteger oldTabCount = [ChromeEarlGreyAppInterface mainTabCount];
+  NSUInteger oldRegularTabCount = [ChromeEarlGreyAppInterface mainTabCount];
+  NSUInteger oldIncognitoTabCount =
+      [ChromeEarlGreyAppInterface incognitoTabCount];
 
   [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()]
       performAction:grey_tap()];
 
-  [self waitForMainTabCount:oldTabCount + 1];
+  [self waitForMainTabCount:oldRegularTabCount + 1];
+  [self waitForIncognitoTabCount:oldIncognitoTabCount];
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(URL)]
+      assertWithMatcher:grey_notNil()];
+}
+
+- (void)verifyOpenInIncognitoActionWithURL:(const std::string&)URL
+                              useNewString:(BOOL)useNewString {
+  // Check tab count prior to execution.
+  NSUInteger oldRegularTabCount = [ChromeEarlGreyAppInterface mainTabCount];
+  NSUInteger oldIncognitoTabCount =
+      [ChromeEarlGreyAppInterface incognitoTabCount];
+
+  [[EarlGrey selectElementWithMatcher:OpenLinkInIncognitoButton(useNewString)]
+      performAction:grey_tap()];
+
+  [self waitForIncognitoTabCount:oldIncognitoTabCount + 1];
+  [self waitForMainTabCount:oldRegularTabCount];
   [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(URL)]
       assertWithMatcher:grey_notNil()];
 }
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
index a5b18cceb..a9c60b56 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h
@@ -482,6 +482,9 @@
 
 #pragma mark - Pasteboard utilities
 
+// Clears the URLs stored in the pasteboard, from the tested app's perspective.
++ (void)clearPasteboardURLs;
+
 // Retrieves the currently stored string on the pasteboard from the tested app's
 // perspective.
 + (NSString*)pasteboardString;
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
index bcaff7e6..fd4f648f 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.mm
@@ -840,6 +840,10 @@
 
 #pragma mark - Pasteboard utilities
 
++ (void)clearPasteboardURLs {
+  [[UIPasteboard generalPasteboard] setURLs:nil];
+}
+
 + (NSString*)pasteboardString {
   return [UIPasteboard generalPasteboard].string;
 }
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h
index fa940ae4d..6f36bab 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -330,7 +330,7 @@
 // Matcher for the Move option on the updated context menus.
 id<GREYMatcher> MoveButton();
 
-// Matcher for the Share option on the updated context menus.
+// Matcher for the Delete option on the updated context menus.
 id<GREYMatcher> DeleteButton();
 
 // Returns matcher for the Copy item on the old-style context menu.
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn
index 5a0dfd1..0a27e9d 100644
--- a/media/capture/BUILD.gn
+++ b/media/capture/BUILD.gn
@@ -169,6 +169,8 @@
 
   if (is_mac) {
     sources += [
+      "video/mac/pixel_buffer_pool_mac.cc",
+      "video/mac/pixel_buffer_pool_mac.h",
       "video/mac/video_capture_device_avfoundation_legacy_mac.h",
       "video/mac/video_capture_device_avfoundation_legacy_mac.mm",
       "video/mac/video_capture_device_avfoundation_mac.h",
@@ -195,6 +197,7 @@
       "CoreVideo.framework",
       "Foundation.framework",
       "IOSurface.framework",
+      "VideoToolbox.framework",
     ]
   }
 
@@ -407,6 +410,7 @@
     "video/linux/camera_config_chromeos_unittest.cc",
     "video/linux/v4l2_capture_delegate_unittest.cc",
     "video/linux/video_capture_device_factory_linux_unittest.cc",
+    "video/mac/pixel_buffer_pool_mac_unittest.mm",
     "video/mac/test/mock_video_capture_device_avfoundation_frame_receiver_mac.h",
     "video/mac/test/mock_video_capture_device_avfoundation_frame_receiver_mac.mm",
     "video/mac/test/video_capture_test_utils_mac.h",
@@ -459,6 +463,7 @@
     frameworks = [
       "AVFoundation.framework",
       "CoreMedia.framework",
+      "CoreVideo.framework",
     ]
   }
 
diff --git a/media/capture/video/mac/pixel_buffer_pool_mac.cc b/media/capture/video/mac/pixel_buffer_pool_mac.cc
new file mode 100644
index 0000000..b53db6a
--- /dev/null
+++ b/media/capture/video/mac/pixel_buffer_pool_mac.cc
@@ -0,0 +1,144 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/capture/video/mac/pixel_buffer_pool_mac.h"
+
+#include "base/check.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+
+namespace media {
+
+namespace {
+
+template <typename T>
+class CFNumber {
+ public:
+  CFNumber(CFNumberType type, T value)
+      : value_(value), number_(CFNumberCreate(nil, type, &value_)) {}
+
+  T* get() { return &value_; }
+  const T* get() const { return &value_; }
+  CFNumberRef cf_number_ref() { return number_.get(); }
+
+ private:
+  T value_;
+  base::ScopedCFTypeRef<CFNumberRef> number_;
+};
+
+base::ScopedCFTypeRef<CFDictionaryRef> CreateEmptyCFDictionary() {
+  return base::ScopedCFTypeRef<CFDictionaryRef>(
+      CFDictionaryCreate(nil, nil, nil, 0, &kCFTypeDictionaryKeyCallBacks,
+                         &kCFTypeDictionaryValueCallBacks));
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<PixelBufferPool> PixelBufferPool::Create(
+    OSType format,
+    int width,
+    int height,
+    base::Optional<size_t> max_buffers) {
+  // Pixel buffer attributes: The attributes of buffers created by the pool.
+  CFStringRef pixel_buffer_attribute_keys[] = {
+      kCVPixelBufferIOSurfacePropertiesKey,  // We want IOSurfaces.
+      kCVPixelBufferPixelFormatTypeKey, kCVPixelBufferWidthKey,
+      kCVPixelBufferHeightKey};
+  constexpr size_t pixel_buffer_attribute_count =
+      sizeof(pixel_buffer_attribute_keys) /
+      sizeof(pixel_buffer_attribute_keys[0]);
+  // Rely on default IOSurface properties.
+  base::ScopedCFTypeRef<CFDictionaryRef> io_surface_options =
+      CreateEmptyCFDictionary();
+  CFNumber<int> pixel_buffer_format(kCFNumberSInt32Type, format);
+  CFNumber<int> pixel_buffer_width(kCFNumberSInt32Type, width);
+  CFNumber<int> pixel_buffer_height(kCFNumberSInt32Type, height);
+  CFTypeRef pixel_buffer_attribute_values[] = {
+      io_surface_options.get(), pixel_buffer_format.cf_number_ref(),
+      pixel_buffer_width.cf_number_ref(), pixel_buffer_height.cf_number_ref()};
+  static_assert(pixel_buffer_attribute_count ==
+                    sizeof(pixel_buffer_attribute_values) /
+                        sizeof(pixel_buffer_attribute_values[0]),
+                "Key count and value count must match");
+  base::ScopedCFTypeRef<CFDictionaryRef> pixel_buffer_attributes(
+      CFDictionaryCreate(nil, (const void**)pixel_buffer_attribute_keys,
+                         (const void**)pixel_buffer_attribute_values,
+                         pixel_buffer_attribute_count,
+                         &kCFTypeDictionaryKeyCallBacks,
+                         &kCFTypeDictionaryValueCallBacks));
+
+  // Create the pool.
+  // We don't specify any pool attributes. It is unclear from the documentation
+  // what pool attributes are available; they might be
+  // kCVPixelBufferPoolMinimumBufferCountKey and
+  // kCVPixelBufferPoolMaximumBufferAgeKey unless these are more auxiliary
+  // attributes for CVPixelBufferPoolCreatePixelBufferWithAuxAttributes().
+  base::ScopedCFTypeRef<CVPixelBufferPoolRef> buffer_pool;
+  CVReturn pool_creation_error = CVPixelBufferPoolCreate(
+      nil, nil, pixel_buffer_attributes.get(), buffer_pool.InitializeInto());
+  if (pool_creation_error != noErr) {
+    DLOG(ERROR) << "Failed to create CVPixelBufferPool with CVReturn error: "
+                << pool_creation_error;
+    return nullptr;
+  }
+  return std::make_unique<PixelBufferPool>(std::move(buffer_pool),
+                                           std::move(max_buffers));
+}
+
+PixelBufferPool::PixelBufferPool(
+    base::ScopedCFTypeRef<CVPixelBufferPoolRef> buffer_pool,
+    base::Optional<size_t> max_buffers)
+    : buffer_pool_(std::move(buffer_pool)),
+      max_buffers_(std::move(max_buffers)) {
+  DCHECK(buffer_pool_);
+}
+
+PixelBufferPool::~PixelBufferPool() {
+  // Flushing before freeing probably isn't needed, but it can't hurt.
+  Flush();
+}
+
+base::ScopedCFTypeRef<CVPixelBufferRef> PixelBufferPool::CreateBuffer() {
+  DCHECK(buffer_pool_);
+  base::ScopedCFTypeRef<CVPixelBufferRef> buffer;
+  CVReturn buffer_creation_error;
+  if (!max_buffers_.has_value()) {
+    buffer_creation_error = CVPixelBufferPoolCreatePixelBuffer(
+        nil, buffer_pool_, buffer.InitializeInto());
+  } else {
+    // Specify the allocation threshold using auxiliary attributes.
+    CFStringRef attribute_keys[] = {kCVPixelBufferPoolAllocationThresholdKey};
+    constexpr size_t attribute_count =
+        sizeof(attribute_keys) / sizeof(attribute_keys[0]);
+    CFNumber<int> poolAllocationThreshold(
+        kCFNumberSInt32Type, base::checked_cast<int>(max_buffers_.value()));
+    CFTypeRef attribute_values[] = {poolAllocationThreshold.cf_number_ref()};
+    static_assert(attribute_count ==
+                      sizeof(attribute_values) / sizeof(attribute_values[0]),
+                  "Key count and value count must match");
+    base::ScopedCFTypeRef<CFDictionaryRef> attributes(CFDictionaryCreate(
+        nil, (const void**)attribute_keys, (const void**)attribute_values,
+        attribute_count, &kCFTypeDictionaryKeyCallBacks,
+        &kCFTypeDictionaryValueCallBacks));
+    buffer_creation_error = CVPixelBufferPoolCreatePixelBufferWithAuxAttributes(
+        nil, buffer_pool_, attributes.get(), buffer.InitializeInto());
+  }
+  if (buffer_creation_error == kCVReturnWouldExceedAllocationThreshold) {
+    // PixelBufferPool cannot create more buffers.
+    return base::ScopedCFTypeRef<CVPixelBufferRef>(nil);
+  }
+  // If |max_buffers_| wasn't reached, this operation must succeed.
+  CHECK(buffer_creation_error == noErr)
+      << "Failed to create destination CVPixelBuffer with CVReturn error: "
+      << buffer_creation_error;
+  return buffer;
+}
+
+void PixelBufferPool::Flush() {
+  DCHECK(buffer_pool_);
+  CVPixelBufferPoolFlush(buffer_pool_, kCVPixelBufferPoolFlushExcessBuffers);
+}
+
+}  // namespace media
diff --git a/media/capture/video/mac/pixel_buffer_pool_mac.h b/media/capture/video/mac/pixel_buffer_pool_mac.h
new file mode 100644
index 0000000..3e9c7cf
--- /dev/null
+++ b/media/capture/video/mac/pixel_buffer_pool_mac.h
@@ -0,0 +1,59 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_CAPTURE_VIDEO_MAC_PIXEL_BUFFER_POOL_MAC_H_
+#define MEDIA_CAPTURE_VIDEO_MAC_PIXEL_BUFFER_POOL_MAC_H_
+
+#import <VideoToolbox/VideoToolbox.h>
+#include <memory>
+
+#include "base/mac/scoped_cftyperef.h"
+#include "base/optional.h"
+#include "media/capture/capture_export.h"
+
+namespace media {
+
+class CAPTURE_EXPORT PixelBufferPool {
+ public:
+  // All buffers created by the pool will have the specified properties.
+  // If specified, the pool allows at most |max_buffers| to exist at a time by
+  // having CreateBuffer() returns null if this threshold would be exceeded.
+  //
+  // If an unsupportd |format| is specified, or the pool cannot be created for
+  // unknown reasons, null is returned.
+  static std::unique_ptr<PixelBufferPool> Create(
+      OSType format,
+      int width,
+      int height,
+      base::Optional<size_t> max_buffers);
+  ~PixelBufferPool();
+
+  // Creates a new buffer from the pool, or returns null if |max_buffers_| would
+  // be exceeded. The underlying buffers may be recycled.
+  //
+  // The caller owns the returned buffer and is responsible for calling
+  // CFRelease() after they are done using it. This returns the underlying
+  // buffer to the pool. In order to free memory, you must both release all
+  // buffers and call Flush() or delete the pool. It is safe for a buffer to
+  // outlive its pool.
+  base::ScopedCFTypeRef<CVPixelBufferRef> CreateBuffer();
+
+  // Frees the memory of any released buffers returned to the pool.
+  void Flush();
+
+ private:
+  friend std::unique_ptr<PixelBufferPool> std::make_unique<PixelBufferPool>(
+      base::ScopedCFTypeRef<CVPixelBufferPoolRef>&& buffer_pool,
+      base::Optional<size_t>&& max_buffers);
+
+  PixelBufferPool(base::ScopedCFTypeRef<CVPixelBufferPoolRef> buffer_pool,
+                  base::Optional<size_t> max_buffers);
+
+  base::ScopedCFTypeRef<CVPixelBufferPoolRef> buffer_pool_;
+  const base::Optional<size_t> max_buffers_;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_CAPTURE_VIDEO_MAC_PIXEL_BUFFER_POOL_MAC_H_
diff --git a/media/capture/video/mac/pixel_buffer_pool_mac_unittest.mm b/media/capture/video/mac/pixel_buffer_pool_mac_unittest.mm
new file mode 100644
index 0000000..b366cdb5e
--- /dev/null
+++ b/media/capture/video/mac/pixel_buffer_pool_mac_unittest.mm
@@ -0,0 +1,109 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/capture/video/mac/pixel_buffer_pool_mac.h"
+
+#include "base/bind.h"
+#include "base/mac/scoped_nsobject.h"
+#import "media/capture/video/mac/test/video_capture_test_utils_mac.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+namespace {
+
+// NV12, also known as 420v, also known as media::PIXEL_FORMAT_NV12.
+constexpr OSType kPixelFormatNv12 =
+    kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
+// A common 4:3 resolution.
+constexpr int kVgaWidth = 640;
+constexpr int kVgaHeight = 480;
+
+}  // namespace
+
+TEST(PixelBufferPoolTest, CannotCreatePoolWithNonsenseArguments) {
+  EXPECT_FALSE(PixelBufferPool::Create(0, -1, -1, 1));
+}
+
+TEST(PixelBufferPoolTest, CreatedBufferHasSpecifiedAttributes) {
+  std::unique_ptr<PixelBufferPool> pool =
+      PixelBufferPool::Create(kPixelFormatNv12, kVgaWidth, kVgaHeight, 1);
+  base::ScopedCFTypeRef<CVPixelBufferRef> buffer = pool->CreateBuffer();
+  EXPECT_TRUE(CVPixelBufferGetPixelFormatType(buffer) == kPixelFormatNv12);
+  EXPECT_EQ(CVPixelBufferGetWidth(buffer), static_cast<size_t>(kVgaWidth));
+  EXPECT_EQ(CVPixelBufferGetHeight(buffer), static_cast<size_t>(kVgaHeight));
+}
+
+TEST(PixelBufferPoolTest, CreatedBufferHasIOSurface) {
+  std::unique_ptr<PixelBufferPool> pool =
+      PixelBufferPool::Create(kPixelFormatNv12, kVgaWidth, kVgaHeight, 1);
+  base::ScopedCFTypeRef<CVPixelBufferRef> buffer = pool->CreateBuffer();
+  EXPECT_TRUE(CVPixelBufferGetIOSurface(buffer));
+}
+
+TEST(PixelBufferPoolTest, CannotExceedMaxBuffers) {
+  std::unique_ptr<PixelBufferPool> pool =
+      PixelBufferPool::Create(kPixelFormatNv12, kVgaWidth, kVgaHeight, 2);
+  base::ScopedCFTypeRef<CVPixelBufferRef> first_buffer = pool->CreateBuffer();
+  EXPECT_TRUE(first_buffer);
+  base::ScopedCFTypeRef<CVPixelBufferRef> second_buffer = pool->CreateBuffer();
+  EXPECT_TRUE(second_buffer);
+  base::ScopedCFTypeRef<CVPixelBufferRef> third_buffer = pool->CreateBuffer();
+  EXPECT_FALSE(third_buffer);
+}
+
+TEST(PixelBufferPoolTest, CanCreateBuffersIfMaxIsNull) {
+  std::unique_ptr<PixelBufferPool> pool = PixelBufferPool::Create(
+      kPixelFormatNv12, kVgaWidth, kVgaHeight, base::nullopt);
+  base::ScopedCFTypeRef<CVPixelBufferRef> first_buffer = pool->CreateBuffer();
+  EXPECT_TRUE(first_buffer);
+  base::ScopedCFTypeRef<CVPixelBufferRef> second_buffer = pool->CreateBuffer();
+  EXPECT_TRUE(second_buffer);
+  base::ScopedCFTypeRef<CVPixelBufferRef> third_buffer = pool->CreateBuffer();
+  EXPECT_TRUE(third_buffer);
+}
+
+TEST(PixelBufferPoolTest, CanCreateBufferAfterPreviousBufferIsReleased) {
+  std::unique_ptr<PixelBufferPool> pool =
+      PixelBufferPool::Create(kPixelFormatNv12, kVgaWidth, kVgaHeight, 1);
+  base::ScopedCFTypeRef<CVPixelBufferRef> buffer = pool->CreateBuffer();
+  buffer.reset();
+  buffer = pool->CreateBuffer();
+  EXPECT_TRUE(buffer);
+}
+
+TEST(PixelBufferPoolTest, BuffersCanOutliveThePool) {
+  std::unique_ptr<PixelBufferPool> pool =
+      PixelBufferPool::Create(kPixelFormatNv12, kVgaWidth, kVgaHeight, 1);
+  base::ScopedCFTypeRef<CVPixelBufferRef> buffer = pool->CreateBuffer();
+  pool.reset();
+  EXPECT_TRUE(CVPixelBufferGetPixelFormatType(buffer) == kPixelFormatNv12);
+  EXPECT_EQ(CVPixelBufferGetWidth(buffer), static_cast<size_t>(kVgaWidth));
+  EXPECT_EQ(CVPixelBufferGetHeight(buffer), static_cast<size_t>(kVgaHeight));
+  EXPECT_TRUE(CVPixelBufferGetIOSurface(buffer));
+}
+
+TEST(PixelBufferPoolTest, CanFlushWhileBufferIsInUse) {
+  std::unique_ptr<PixelBufferPool> pool = PixelBufferPool::Create(
+      kPixelFormatNv12, kVgaWidth, kVgaHeight, base::nullopt);
+  base::ScopedCFTypeRef<CVPixelBufferRef> retained_buffer =
+      pool->CreateBuffer();
+  base::ScopedCFTypeRef<CVPixelBufferRef> released_buffer =
+      pool->CreateBuffer();
+  released_buffer.reset();
+  // We expect the memory of |released_buffer| to be freed now, but there is no
+  // way to assert this in a unittest.
+  pool->Flush();
+  // We expect |retained_buffer| is still usable. Inspecting its properties.
+  EXPECT_TRUE(CVPixelBufferGetPixelFormatType(retained_buffer) ==
+              kPixelFormatNv12);
+  EXPECT_EQ(CVPixelBufferGetWidth(retained_buffer),
+            static_cast<size_t>(kVgaWidth));
+  EXPECT_EQ(CVPixelBufferGetHeight(retained_buffer),
+            static_cast<size_t>(kVgaHeight));
+  EXPECT_TRUE(CVPixelBufferGetIOSurface(retained_buffer));
+}
+
+}  // namespace media
diff --git a/net/android/java/src/org/chromium/net/ProxyChangeListener.java b/net/android/java/src/org/chromium/net/ProxyChangeListener.java
index 8b88d996..d48c60b 100644
--- a/net/android/java/src/org/chromium/net/ProxyChangeListener.java
+++ b/net/android/java/src/org/chromium/net/ProxyChangeListener.java
@@ -18,10 +18,10 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.text.TextUtils;
-import android.util.Log;
 
 import org.chromium.base.BuildConfig;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeClassQualifiedName;
@@ -233,6 +233,9 @@
             return ProxyConfig.DIRECT;
         }
 
+        // Temporary logging to debug crbug.com/1122903
+        Log.i(TAG, "ProxyInfo: " + proxyInfo.toString());
+
         if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q
                 && proxyInfo.getHost().equals("localhost") && proxyInfo.getPort() == -1) {
             // There's a bug in Android Q's PAC support. If ConnectivityManager
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index ff2ca894..e13745d 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -589,8 +589,24 @@
       CrossOriginReadBlockingExceptionForPlugin::ShouldAllowForPlugin(
           factory_params_->process_id);
   request_mode_ = request.mode;
+
   if (request.trusted_params) {
     has_user_activation_ = request.trusted_params->has_user_activation;
+
+    if (factory_params_->client_security_state) {
+      // Enforce that only one ClientSecurityState is ever given to us, as this
+      // is an invariant in the current codebase. In case of a compromised
+      // renderer process, we might be passed both, in which case we prefer to
+      // use the factory params' value: contrary to the request params, it is
+      // always sourced from the browser process.
+      DCHECK(!request.trusted_params->client_security_state)
+          << "Must not provide a ClientSecurityState in both "
+             "URLLoaderFactoryParams and ResourceRequest::TrustedParams.";
+    } else {
+      // This might be nullptr, but that does not matter. Clone it anyways.
+      request_client_security_state_ =
+          request.trusted_params->client_security_state.Clone();
+    }
   }
 
   throttling_token_ = network::ScopedThrottlingToken::MaybeCreate(
@@ -977,8 +993,24 @@
     return net::ERR_INSECURE_PRIVATE_NETWORK_REQUEST;
   }
 
-  const mojom::ClientSecurityStatePtr& security_state =
-      factory_params_->client_security_state;
+  // Depending on the type of URL request, we source the client security state
+  // from either the URLRequest's trusted params (for navigations, which share
+  // a factory) or the URLLoaderFactory's params. We prefer the factory params
+  // over the request params, as the former always come from the browser
+  // process.
+  //
+  // We use a raw pointer instead of a const-ref to a StructPtr in order to be
+  // able to assign a new value to the variable. A ternary operator would let us
+  // define a const-ref but would prevent logging which branch was taken.
+  const mojom::ClientSecurityState* security_state =
+      factory_params_->client_security_state.get();
+  if (security_state) {
+    DVLOG(1) << "CORS-RFC1918 check: using factory client security state.";
+  } else {
+    DVLOG(1) << "CORS-RFC1918 check: using request client security state.";
+    security_state = request_client_security_state_.get();
+  }
+
   if (!security_state) {
     DVLOG(1) << "CORS-RFC1918 check: skipped, missing client security state.";
     return net::OK;
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
index ed6dfca8..70518f4 100644
--- a/services/network/url_loader.h
+++ b/services/network/url_loader.h
@@ -509,6 +509,13 @@
   // Observer listening to all cookie reads and writes made by this request.
   mojo::Remote<mojom::CookieAccessObserver> cookie_observer_;
 
+  // Client security state copied from the input ResourceRequest.
+  //
+  // If |factory_params_->client_security_state| is non-null, this is null.
+  // We indeed prefer the factory params over the request params as we trust the
+  // former more, given that they always come from the browser process.
+  mojom::ClientSecurityStatePtr request_client_security_state_;
+
   // Indicates |url_request_| is fetch upload request and that has streaming
   // body.
   const bool has_fetch_streaming_upload_body_;
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 914cd69f3..bd8415c7 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -566,6 +566,9 @@
     if (request_body_)
       request.request_body = request_body_;
 
+    request.trusted_params->client_security_state.Swap(
+        &request_client_security_state_);
+
     base::RunLoop delete_run_loop;
     mojo::Remote<mojom::URLLoader> loader;
     std::unique_ptr<URLLoader> url_loader;
@@ -573,7 +576,7 @@
     mojom::URLLoaderFactoryParams params;
     params.process_id = mojom::kBrowserProcessId;
     params.is_corb_enabled = false;
-    params.client_security_state.Swap(&client_security_state_);
+    params.client_security_state.Swap(&factory_client_security_state_);
 
     url::Origin origin = url::Origin::Create(url);
     params.isolation_info =
@@ -749,8 +752,11 @@
     DCHECK(!ran_);
     expect_redirect_ = true;
   }
-  void set_client_security_state(mojom::ClientSecurityStatePtr state) {
-    client_security_state_ = std::move(state);
+  void set_factory_client_security_state(mojom::ClientSecurityStatePtr state) {
+    factory_client_security_state_ = std::move(state);
+  }
+  void set_request_client_security_state(mojom::ClientSecurityStatePtr state) {
+    request_client_security_state_ = std::move(state);
   }
   void set_request_body(scoped_refptr<ResourceRequestBody> request_body) {
     request_body_ = request_body;
@@ -875,7 +881,8 @@
   bool send_ssl_with_response_ = false;
   bool send_ssl_for_cert_error_ = false;
   bool expect_redirect_ = false;
-  mojom::ClientSecurityStatePtr client_security_state_;
+  mojom::ClientSecurityStatePtr factory_client_security_state_;
+  mojom::ClientSecurityStatePtr request_client_security_state_;
   scoped_refptr<ResourceRequestBody> request_body_;
 
   // Used to ensure that methods are called either before or after a request is
@@ -936,7 +943,7 @@
   auto client_security_state = NewSecurityState();
   client_security_state->is_web_secure_context = true;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kUnknown;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
@@ -945,7 +952,7 @@
   auto client_security_state = NewSecurityState();
   client_security_state->is_web_secure_context = true;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
@@ -954,7 +961,7 @@
   auto client_security_state = NewSecurityState();
   client_security_state->is_web_secure_context = true;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kPrivate;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
@@ -963,7 +970,7 @@
   auto client_security_state = NewSecurityState();
   client_security_state->is_web_secure_context = true;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kLocal;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
@@ -976,7 +983,7 @@
   client_security_state->private_network_request_policy =
       mojom::PrivateNetworkRequestPolicy::kAllow;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kUnknown;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
@@ -986,7 +993,7 @@
   client_security_state->private_network_request_policy =
       mojom::PrivateNetworkRequestPolicy::kAllow;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
@@ -996,7 +1003,7 @@
   client_security_state->private_network_request_policy =
       mojom::PrivateNetworkRequestPolicy::kAllow;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kPrivate;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
@@ -1006,7 +1013,7 @@
   client_security_state->private_network_request_policy =
       mojom::PrivateNetworkRequestPolicy::kAllow;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kLocal;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
@@ -1025,7 +1032,7 @@
   auto client_security_state = NewSecurityState();
   client_security_state->is_web_secure_context = false;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kUnknown;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_INSECURE_PRIVATE_NETWORK_REQUEST));
@@ -1035,7 +1042,7 @@
   auto client_security_state = NewSecurityState();
   client_security_state->is_web_secure_context = false;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_INSECURE_PRIVATE_NETWORK_REQUEST));
@@ -1045,7 +1052,7 @@
   auto client_security_state = NewSecurityState();
   client_security_state->is_web_secure_context = false;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kPrivate;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
               IsError(net::ERR_INSECURE_PRIVATE_NETWORK_REQUEST));
@@ -1055,11 +1062,25 @@
   auto client_security_state = NewSecurityState();
   client_security_state->is_web_secure_context = false;
   client_security_state->ip_address_space = mojom::IPAddressSpace::kLocal;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   EXPECT_THAT(Load(test_server()->GetURL("/empty.html")), IsOk());
 }
 
+// This test verifies that if the request's TrustedParams field carries a client
+// security state indicating that the request initiator is not a secure context
+// and came from the public IP address space, requests to local IP addresses
+// are blocked.
+TEST_F(URLLoaderTest, TrustedParamsInsecurePublicToLocalIsBlocked) {
+  auto client_security_state = NewSecurityState();
+  client_security_state->is_web_secure_context = false;
+  client_security_state->ip_address_space = mojom::IPAddressSpace::kPublic;
+  set_request_client_security_state(std::move(client_security_state));
+
+  EXPECT_THAT(Load(test_server()->GetURL("/empty.html")),
+              IsError(net::ERR_INSECURE_PRIVATE_NETWORK_REQUEST));
+}
+
 // Bundles together the inputs to a parameterized private network request test.
 struct URLLoaderFakeTransportInfoTestParams {
   // The address space of the client.
@@ -1119,7 +1140,7 @@
 
   auto client_security_state = NewSecurityState();
   client_security_state->ip_address_space = params.client_address_space;
-  set_client_security_state(std::move(client_security_state));
+  set_factory_client_security_state(std::move(client_security_state));
 
   const GURL url("http://fake-endpoint");
 
diff --git a/storage/browser/quota/quota_features.cc b/storage/browser/quota/quota_features.cc
index 42cc63ea..76be3c1 100644
--- a/storage/browser/quota/quota_features.cc
+++ b/storage/browser/quota/quota_features.cc
@@ -8,15 +8,6 @@
 
 namespace features {
 
-const base::Feature kQuotaExpandPoolSize{"QuotaExpandPoolSize",
-                                         base::FEATURE_ENABLED_BY_DEFAULT};
-
-constexpr base::FeatureParam<double> kExperimentalPoolSizeRatio{
-    &kQuotaExpandPoolSize, "PoolSizeRatio", 0.8};
-
-constexpr base::FeatureParam<double> kPerHostRatio{&kQuotaExpandPoolSize,
-                                                   "PerHostRatio", 0.75};
-
 // QuotaUnlimitedPoolSize removes limitations around disk space consumption with
 // respect to client-side storage web platform APIs. When enabled, quota will
 // set no limit on how much space a single origin can consume, as well as
diff --git a/storage/browser/quota/quota_features.h b/storage/browser/quota/quota_features.h
index 1ddc0305..d69cbc6 100644
--- a/storage/browser/quota/quota_features.h
+++ b/storage/browser/quota/quota_features.h
@@ -14,11 +14,6 @@
 namespace features {
 
 COMPONENT_EXPORT(STORAGE_BROWSER)
-extern const base::Feature kQuotaExpandPoolSize;
-extern const base::FeatureParam<double> kExperimentalPoolSizeRatio;
-extern const base::FeatureParam<double> kPerHostRatio;
-
-COMPONENT_EXPORT(STORAGE_BROWSER)
 extern const base::Feature kQuotaUnlimitedPoolSize;
 
 COMPONENT_EXPORT(STORAGE_BROWSER)
diff --git a/storage/browser/quota/quota_settings.cc b/storage/browser/quota/quota_settings.cc
index d5f6709..cdf8882 100644
--- a/storage/browser/quota/quota_settings.cc
+++ b/storage/browser/quota/quota_settings.cc
@@ -26,6 +26,8 @@
 
 const int64_t kMBytes = 1024 * 1024;
 const int kRandomizedPercentage = 10;
+const double kDefaultPerHostRatio = 0.75;
+const double kDefaultPoolSizeRatio = 0.8;
 
 // Skews |value| by +/- |percent|.
 int64_t RandomizeByPercent(int64_t value, int percent) {
@@ -77,7 +79,7 @@
   const double kTemporaryPoolSizeRatio =
       base::FeatureList::IsEnabled(features::kQuotaUnlimitedPoolSize)
           ? 1.0
-          : features::kExperimentalPoolSizeRatio.Get();
+          : kDefaultPoolSizeRatio;
 
   // The amount of the device's storage the browser attempts to
   // keep free. If there is less than this amount of storage free
@@ -114,7 +116,7 @@
   const double kPerHostTemporaryRatio =
       base::FeatureList::IsEnabled(features::kQuotaUnlimitedPoolSize)
           ? 1.0
-          : features::kPerHostRatio.Get();
+          : kDefaultPerHostRatio;
 
   // SessionOnly (or ephemeral) origins are allotted a fraction of what
   // normal origins are provided, and the amount is capped to a hard limit.
diff --git a/storage/browser/quota/quota_settings_unittest.cc b/storage/browser/quota/quota_settings_unittest.cc
index 34fb66e..8a8eba2c 100644
--- a/storage/browser/quota/quota_settings_unittest.cc
+++ b/storage/browser/quota/quota_settings_unittest.cc
@@ -140,29 +140,6 @@
   EXPECT_TRUE(callback_executed);
 }
 
-TEST_F(QuotaSettingsTest, ExpandedTempPool) {
-  MockQuotaDeviceInfoHelper device_info_helper;
-  ON_CALL(device_info_helper, AmountOfTotalDiskSpace(_))
-      .WillByDefault(::testing::Return(2000));
-  scoped_feature_list_.InitAndEnableFeatureWithParameters(
-      features::kQuotaExpandPoolSize,
-      {{"PoolSizeRatio", "0.75"}, {"PerHostRatio", "0.5"}});
-
-  bool callback_executed = false;
-  GetNominalDynamicSettings(
-      profile_path(), false, &device_info_helper,
-      base::BindLambdaForTesting([&](base::Optional<QuotaSettings> settings) {
-        callback_executed = true;
-        ASSERT_NE(settings, base::nullopt);
-        // 1500 = 2000 * PoolSizeRatio
-        EXPECT_EQ(settings->pool_size, 1500);
-        // 750 = 1500 * PerHostRatio
-        EXPECT_EQ(settings->per_host_quota, 750);
-      }));
-  task_environment_.RunUntilIdle();
-  EXPECT_TRUE(callback_executed);
-}
-
 TEST_F(QuotaSettingsTest, UnlimitedTempPool) {
   MockQuotaDeviceInfoHelper device_info_helper;
   ON_CALL(device_info_helper, AmountOfTotalDiskSpace(_))
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b1e15ab..d3dd3271 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2959,30 +2959,6 @@
             ]
         }
     ],
-    "GamepadPollingInterval": [
-        {
-            "platforms": [
-                "windows",
-                "mac",
-                "chromeos",
-                "linux",
-                "android",
-                "android_weblayer",
-                "android_webview"
-            ],
-            "experiments": [
-                {
-                    "name": "EnabledGamepadPolling250Hz",
-                    "params": {
-                        "interval-ms": "4"
-                    },
-                    "enable_features": [
-                        "GamepadPollingInterval"
-                    ]
-                }
-            ]
-        }
-    ],
     "GestureNavigation": [
         {
             "platforms": [
@@ -4563,6 +4539,7 @@
                     "name": "Enabled",
                     "enable_features": [
                         "DisableSearchSuggestChips",
+                        "IframeOneGoogleBar",
                         "NtpWebUI"
                     ]
                 }
@@ -5777,30 +5754,6 @@
             ]
         }
     ],
-    "QuotaExpandPoolSize": [
-        {
-            "platforms": [
-                "android",
-                "android_weblayer",
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_Pool_Four_Fifths_Origin_ThreeQuarters_20190710",
-                    "params": {
-                        "PerHostRatio": "0.75",
-                        "PoolSizeRatio": "0.8"
-                    },
-                    "enable_features": [
-                        "QuotaExpandPoolSize"
-                    ]
-                }
-            ]
-        }
-    ],
     "ReleaseNotesNotification": [
         {
             "platforms": [
@@ -6611,26 +6564,6 @@
             ]
         }
     ],
-    "SyncReuploadBookmarkFullTitles": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "ios",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "SyncReuploadBookmarkFullTitles"
-                    ]
-                }
-            ]
-        }
-    ],
     "SyncTriggerFullKeystoreMigration": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/renderer_preferences.mojom b/third_party/blink/public/mojom/renderer_preferences.mojom
index c7d1b39..bdfe1ae 100644
--- a/third_party/blink/public/mojom/renderer_preferences.mojom
+++ b/third_party/blink/public/mojom/renderer_preferences.mojom
@@ -90,6 +90,10 @@
 
   array<string> webrtc_local_ips_allowed_urls;
 
+  // Whether WebRTC peer connections are allowed to use legacy versions of the
+  // TLS/DTLS protocols.
+  bool webrtc_allow_legacy_tls_protocols = false;
+
   // The user agent given to WebKit when it requests one and the user agent is
   // being overridden for the current navigation.
   UserAgentOverride user_agent_override;
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 08804af..069ebc8 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -553,6 +553,9 @@
     return nullptr;
   }
 
+  // WebRTC
+  virtual bool AllowRTCLegacyTLSProtocols() { return false; }
+
   // Encrypted Media -------------------------------------------------
 
   virtual WebEncryptedMediaClient* EncryptedMediaClient() { return nullptr; }
diff --git a/third_party/blink/renderer/bindings/bindings.gni b/third_party/blink/renderer/bindings/bindings.gni
index 563db10..deb188d 100644
--- a/third_party/blink/renderer/bindings/bindings.gni
+++ b/third_party/blink/renderer/bindings/bindings.gni
@@ -19,7 +19,6 @@
                     "core/v8/callback_invoke_helper.cc",
                     "core/v8/callback_invoke_helper.h",
                     "core/v8/callback_promise_adapter.h",
-                    "core/v8/classic_evaluation_result.h",
                     "core/v8/custom/v8_custom_xpath_ns_resolver.cc",
                     "core/v8/custom/v8_custom_xpath_ns_resolver.h",
                     "core/v8/custom/v8_dev_tools_host_custom.cc",
@@ -78,6 +77,8 @@
                     "core/v8/script_custom_element_definition_builder.cc",
                     "core/v8/script_custom_element_definition_builder.h",
                     "core/v8/script_custom_element_definition_data.h",
+                    "core/v8/script_evaluation_result.cc",
+                    "core/v8/script_evaluation_result.h",
                     "core/v8/script_event_listener.cc",
                     "core/v8/script_event_listener.h",
                     "core/v8/script_function.cc",
diff --git a/third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h b/third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h
deleted file mode 100644
index 61edac3..0000000
--- a/third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CLASSIC_EVALUATION_RESULT_H_
-#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CLASSIC_EVALUATION_RESULT_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
-#include "third_party/blink/renderer/platform/loader/fetch/cached_metadata_handler.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/text/text_position.h"
-#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-#include "v8/include/v8.h"
-
-namespace blink {
-
-// ClassicEvaluationResult encapsulates the result of a classic script
-// evaluation.
-// - If IsEmpty() is false:
-//     A script is evaluated successfully.
-//     No exceptions are thrown.
-//     GetValue() returns a non-Empty value.
-// - If IsEmpty() is true:
-//     Script evaluation failed (compile error, evaluation error, or so).
-//     An exception might or might not be thrown in V8.
-//     Unlike v8::MaybeLocal<>, there are cases where no exceptions are thrown
-//     to V8 while returning an Empty ClassicEvaluationResult, like when:
-//     - An exception is thrown during script evaluation but caught and passed
-//       to https://html.spec.whatwg.org/C/#report-the-error, instead of
-//       being rethrown, or
-//     - Script evaluation is skipped due to checks within Blink.
-//
-// TODO(crbug/1111134): Consider merging with ModuleEvaluationResult later.
-// Right now classic and module evaluation paths are not yet merged, and
-// top-level await (crbug/1022182) will modify ModuleEvaluationResult.
-class CORE_EXPORT ClassicEvaluationResult final {
-  STACK_ALLOCATED();
-
- public:
-  ClassicEvaluationResult() = default;
-  explicit ClassicEvaluationResult(v8::Local<v8::Value> value) : value_(value) {
-    DCHECK(!IsEmpty());
-  }
-
-  bool IsEmpty() const { return value_.IsEmpty(); }
-  v8::Local<v8::Value> GetValue() const {
-    DCHECK(!IsEmpty());
-    return value_;
-  }
-
- private:
-  v8::Local<v8::Value> value_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_CLASSIC_EVALUATION_RESULT_H_
diff --git a/third_party/blink/renderer/bindings/core/v8/module_record.cc b/third_party/blink/renderer/bindings/core/v8/module_record.cc
index f6eaa51..b85a1fc 100644
--- a/third_party/blink/renderer/bindings/core/v8/module_record.cc
+++ b/third_party/blink/renderer/bindings/core/v8/module_record.cc
@@ -20,51 +20,6 @@
 
 namespace blink {
 
-// static
-ModuleEvaluationResult ModuleEvaluationResult::Empty() {
-  return ModuleEvaluationResult(true, {});
-}
-
-// static
-ModuleEvaluationResult ModuleEvaluationResult::FromResult(
-    v8::Local<v8::Value> promise) {
-  DCHECK(base::FeatureList::IsEnabled(features::kTopLevelAwait) ||
-         promise.IsEmpty());
-  DCHECK(!base::FeatureList::IsEnabled(features::kTopLevelAwait) ||
-         promise->IsPromise());
-  return ModuleEvaluationResult(true, promise);
-}
-
-// static
-ModuleEvaluationResult ModuleEvaluationResult::FromException(
-    v8::Local<v8::Value> exception) {
-  DCHECK(!exception.IsEmpty());
-  return ModuleEvaluationResult(false, exception);
-}
-
-ModuleEvaluationResult& ModuleEvaluationResult::Escape(
-    ScriptState::EscapableScope* scope) {
-  value_ = scope->Escape(value_);
-  return *this;
-}
-
-v8::Local<v8::Value> ModuleEvaluationResult::GetException() const {
-  DCHECK(IsException());
-  DCHECK(!value_.IsEmpty());
-  return value_;
-}
-
-ScriptPromise ModuleEvaluationResult::GetPromise(
-    ScriptState* script_state) const {
-  DCHECK(base::FeatureList::IsEnabled(features::kTopLevelAwait));
-  DCHECK(!value_.IsEmpty());
-  if (IsSuccess()) {
-    return ScriptPromise(script_state, value_);
-  } else {
-    return ScriptPromise::Reject(script_state, value_);
-  }
-}
-
 ModuleRecordProduceCacheData::ModuleRecordProduceCacheData(
     v8::Isolate* isolate,
     SingleCachedMetadataHandler* cache_handler,
@@ -168,7 +123,7 @@
   return ScriptValue();
 }
 
-ModuleEvaluationResult ModuleRecord::Evaluate(ScriptState* script_state,
+ScriptEvaluationResult ModuleRecord::Evaluate(ScriptState* script_state,
                                               v8::Local<v8::Module> record,
                                               const KURL& source_url) {
   v8::Isolate* isolate = script_state->GetIsolate();
@@ -192,13 +147,9 @@
   if (!V8ScriptRunner::EvaluateModule(isolate, execution_context, record,
                                       script_state->GetContext())
            .ToLocal(&result)) {
-    return ModuleEvaluationResult::FromException(try_catch.Exception());
+    return ScriptEvaluationResult::FromModuleException(try_catch.Exception());
   }
-  if (base::FeatureList::IsEnabled(features::kTopLevelAwait)) {
-    return ModuleEvaluationResult::FromResult(result);
-  } else {
-    return ModuleEvaluationResult::Empty();
-  }
+  return ScriptEvaluationResult::FromModuleSuccess(result);
 }
 
 void ModuleRecord::ReportException(ScriptState* script_state,
diff --git a/third_party/blink/renderer/bindings/core/v8/module_record.h b/third_party/blink/renderer/bindings/core/v8/module_record.h
index 6a9d5de..36b21f1 100644
--- a/third_party/blink/renderer/bindings/core/v8/module_record.h
+++ b/third_party/blink/renderer/bindings/core/v8/module_record.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_MODULE_RECORD_H_
 
 #include "third_party/blink/renderer/bindings/core/v8/module_request.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_source_location_type.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -24,48 +25,6 @@
 class ScriptFetchOptions;
 class ScriptState;
 class ScriptValue;
-class ScriptPromise;
-
-// ModuleEvaluationResult encapsulates the result of a module evaluation.
-// - Without top-level-await
-//   - succeed and not return a value, or
-//     (IsSuccess() == true), no return value is available.
-//   - throw any object.
-//     (IsException() == true && GetException()) returns the thrown exception
-// - With top-level-await a module can either
-//   - return a promise, or
-//     (IsSuccess() == true && GetPromise()) returns a valid ScriptPromise())
-//   - throw any object.
-//     (IsException() == true && GetException()) returns the thrown exception
-class CORE_EXPORT ModuleEvaluationResult final {
-  STACK_ALLOCATED();
-
- public:
-  ModuleEvaluationResult() = delete;
-  static ModuleEvaluationResult Empty();
-  static ModuleEvaluationResult FromResult(v8::Local<v8::Value> promise);
-  static ModuleEvaluationResult FromException(v8::Local<v8::Value> exception);
-
-  ModuleEvaluationResult(const ModuleEvaluationResult& value) = default;
-  ModuleEvaluationResult& operator=(const ModuleEvaluationResult& value) =
-      default;
-  ~ModuleEvaluationResult() = default;
-
-  ModuleEvaluationResult& Escape(ScriptState::EscapableScope* scope);
-
-  bool IsSuccess() const { return is_success_; }
-  bool IsException() const { return !is_success_; }
-
-  v8::Local<v8::Value> GetException() const;
-  ScriptPromise GetPromise(ScriptState* script_state) const;
-
- private:
-  ModuleEvaluationResult(bool is_success, v8::Local<v8::Value> value)
-      : is_success_(is_success), value_(value) {}
-
-  bool is_success_;
-  v8::Local<v8::Value> value_;
-};
 
 // ModuleRecordProduceCacheData is a parameter object for
 // ModuleRecord::ProduceCache().
@@ -121,7 +80,7 @@
                                  v8::Local<v8::Module> record,
                                  const KURL& source_url);
 
-  static ModuleEvaluationResult Evaluate(ScriptState*,
+  static ScriptEvaluationResult Evaluate(ScriptState*,
                                          v8::Local<v8::Module> record,
                                          const KURL& source_url);
 
diff --git a/third_party/blink/renderer/bindings/core/v8/module_record_test.cc b/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
index efcb338..37a219a 100644
--- a/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/module_record_test.cc
@@ -238,7 +238,7 @@
   ASSERT_TRUE(ModuleRecord::Instantiate(scope.GetScriptState(), module_failure,
                                         js_url_f)
                   .IsEmpty());
-  ModuleEvaluationResult evaluation_result1 =
+  ScriptEvaluationResult evaluation_result1 =
       ModuleRecord::Evaluate(scope.GetScriptState(), module_failure, js_url_f);
 
   resolver->PrepareMockResolveResult(module_failure);
@@ -252,12 +252,14 @@
   ASSERT_TRUE(
       ModuleRecord::Instantiate(scope.GetScriptState(), module, js_url_c)
           .IsEmpty());
-  ModuleEvaluationResult evaluation_result2 =
+  ScriptEvaluationResult evaluation_result2 =
       ModuleRecord::Evaluate(scope.GetScriptState(), module, js_url_f);
 
   if (base::FeatureList::IsEnabled(features::kTopLevelAwait)) {
-    EXPECT_TRUE(evaluation_result1.IsSuccess());
-    EXPECT_TRUE(evaluation_result2.IsSuccess());
+    EXPECT_EQ(evaluation_result1.GetResultType(),
+              ScriptEvaluationResult::ResultType::kSuccess);
+    EXPECT_EQ(evaluation_result2.GetResultType(),
+              ScriptEvaluationResult::ResultType::kSuccess);
 
     ScriptValue value1;
     ScriptValue value2;
@@ -273,10 +275,12 @@
     EXPECT_FALSE(value2.IsEmpty());
     EXPECT_EQ(value1, value2);
   } else {
-    EXPECT_TRUE(evaluation_result1.IsException());
-    EXPECT_TRUE(evaluation_result2.IsException());
-    EXPECT_EQ(evaluation_result1.GetException(),
-              evaluation_result2.GetException());
+    EXPECT_EQ(evaluation_result1.GetResultType(),
+              ScriptEvaluationResult::ResultType::kException);
+    EXPECT_EQ(evaluation_result2.GetResultType(),
+              ScriptEvaluationResult::ResultType::kException);
+    EXPECT_EQ(evaluation_result1.GetExceptionForModule(),
+              evaluation_result2.GetExceptionForModule());
   }
 
   ASSERT_EQ(1u, resolver->ResolveCount());
@@ -300,8 +304,9 @@
       ModuleRecord::Instantiate(scope.GetScriptState(), module, js_url);
   ASSERT_TRUE(exception.IsEmpty());
 
-  EXPECT_TRUE(ModuleRecord::Evaluate(scope.GetScriptState(), module, js_url)
-                  .IsSuccess());
+  EXPECT_EQ(ModuleRecord::Evaluate(scope.GetScriptState(), module, js_url)
+                .GetResultType(),
+            ScriptEvaluationResult::ResultType::kSuccess);
   v8::Local<v8::Value> value =
       ClassicScript::CreateUnspecifiedScript(ScriptSourceCode("window.foo"))
           ->RunScriptAndReturnValue(&scope.GetFrame());
@@ -334,12 +339,13 @@
       ModuleRecord::Instantiate(scope.GetScriptState(), module, js_url);
   ASSERT_TRUE(exception.IsEmpty());
 
-  ModuleEvaluationResult result =
+  ScriptEvaluationResult result =
       ModuleRecord::Evaluate(scope.GetScriptState(), module, js_url);
 
   v8::Local<v8::Value> value;
   if (base::FeatureList::IsEnabled(features::kTopLevelAwait)) {
-    ASSERT_TRUE(result.IsSuccess());
+    ASSERT_EQ(result.GetResultType(),
+              ScriptEvaluationResult::ResultType::kSuccess);
     ScriptValue script_value;
     result.GetPromise(scope.GetScriptState())
         .Then(v8::Local<v8::Function>(),
@@ -350,8 +356,9 @@
     EXPECT_FALSE(script_value.IsEmpty());
     value = script_value.V8Value();
   } else {
-    ASSERT_TRUE(result.IsException());
-    value = result.GetException();
+    ASSERT_EQ(result.GetResultType(),
+              ScriptEvaluationResult::ResultType::kException);
+    value = result.GetExceptionForModule();
   }
   ASSERT_TRUE(value->IsString());
   EXPECT_EQ("bar", ToCoreString(v8::Local<v8::String>::Cast(value)));
diff --git a/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc b/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc
new file mode 100644
index 0000000..b9241cb
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.cc
@@ -0,0 +1,127 @@
+// 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 "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
+
+#include "base/feature_list.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
+namespace blink {
+
+ScriptEvaluationResult::ScriptEvaluationResult(
+    mojom::blink::ScriptType script_type,
+    ResultType result_type,
+    v8::Local<v8::Value> value)
+    :
+#if DCHECK_IS_ON()
+      script_type_(script_type),
+#endif
+      result_type_(result_type),
+      value_(value) {
+}
+
+// static
+ScriptEvaluationResult ScriptEvaluationResult::FromClassicNotRun() {
+  return ScriptEvaluationResult(mojom::blink::ScriptType::kClassic,
+                                ResultType::kNotRun, {});
+}
+
+// static
+ScriptEvaluationResult ScriptEvaluationResult::FromModuleNotRun() {
+  return ScriptEvaluationResult(mojom::blink::ScriptType::kModule,
+                                ResultType::kNotRun, {});
+}
+
+// static
+ScriptEvaluationResult ScriptEvaluationResult::FromClassicSuccess(
+    v8::Local<v8::Value> value) {
+  DCHECK(!value.IsEmpty());
+  return ScriptEvaluationResult(mojom::blink::ScriptType::kClassic,
+                                ResultType::kSuccess, value);
+}
+
+// static
+ScriptEvaluationResult ScriptEvaluationResult::FromModuleSuccess(
+    v8::Local<v8::Value> value) {
+  DCHECK(!value.IsEmpty());
+  DCHECK(!base::FeatureList::IsEnabled(features::kTopLevelAwait) ||
+         value->IsPromise());
+
+  return ScriptEvaluationResult(mojom::blink::ScriptType::kModule,
+                                ResultType::kSuccess, value);
+}
+
+// static
+ScriptEvaluationResult ScriptEvaluationResult::FromClassicException() {
+  return ScriptEvaluationResult(mojom::blink::ScriptType::kClassic,
+                                ResultType::kException, {});
+}
+
+// static
+ScriptEvaluationResult ScriptEvaluationResult::FromModuleException(
+    v8::Local<v8::Value> exception) {
+  DCHECK(!exception.IsEmpty());
+  return ScriptEvaluationResult(mojom::blink::ScriptType::kModule,
+                                ResultType::kException, exception);
+}
+
+// static
+ScriptEvaluationResult ScriptEvaluationResult::FromClassicAborted() {
+  return ScriptEvaluationResult(mojom::blink::ScriptType::kClassic,
+                                ResultType::kAborted, {});
+}
+
+// static
+ScriptEvaluationResult ScriptEvaluationResult::FromModuleAborted() {
+  return ScriptEvaluationResult(mojom::blink::ScriptType::kModule,
+                                ResultType::kAborted, {});
+}
+
+ScriptEvaluationResult& ScriptEvaluationResult::Escape(
+    ScriptState::EscapableScope* scope) {
+  value_ = scope->Escape(value_);
+  return *this;
+}
+
+v8::Local<v8::Value> ScriptEvaluationResult::GetSuccessValue() const {
+  DCHECK_EQ(result_type_, ResultType::kSuccess);
+  DCHECK(!value_.IsEmpty());
+  return value_;
+}
+
+v8::Local<v8::Value> ScriptEvaluationResult::GetExceptionForModule() const {
+#if DCHECK_IS_ON()
+  DCHECK_EQ(script_type_, mojom::blink::ScriptType::kModule);
+#endif
+  DCHECK_EQ(result_type_, ResultType::kException);
+  DCHECK(!value_.IsEmpty());
+
+  return value_;
+}
+
+ScriptPromise ScriptEvaluationResult::GetPromise(
+    ScriptState* script_state) const {
+  DCHECK(base::FeatureList::IsEnabled(features::kTopLevelAwait));
+#if DCHECK_IS_ON()
+  DCHECK_EQ(script_type_, mojom::blink::ScriptType::kModule);
+#endif
+
+  switch (result_type_) {
+    case ResultType::kSuccess:
+      return ScriptPromise(script_state, GetSuccessValue());
+
+    case ResultType::kException:
+      return ScriptPromise::Reject(script_state, GetExceptionForModule());
+
+    case ResultType::kNotRun:
+    case ResultType::kAborted:
+      NOTREACHED();
+      return ScriptPromise::Reject(script_state, v8::Local<v8::Value>());
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h b/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h
new file mode 100644
index 0000000..f31b03e
--- /dev/null
+++ b/third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h
@@ -0,0 +1,135 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_EVALUATION_RESULT_H_
+#define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_EVALUATION_RESULT_H_
+
+#include "third_party/blink/public/mojom/script/script_type.mojom-blink-forward.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+class ScriptPromise;
+
+// ScriptEvaluationResult encapsulates the result of a classic or module script
+// evaluation:
+// - https://html.spec.whatwg.org/C/#run-a-classic-script
+// - https://html.spec.whatwg.org/C/#run-a-module-script
+//
+// Note: Top-level await (TLA, https://github.com/whatwg/html/pull/4352) will
+// affect the semantics where mentioned below.
+class CORE_EXPORT ScriptEvaluationResult final {
+  STACK_ALLOCATED();
+
+ public:
+  ScriptEvaluationResult() = delete;
+  ScriptEvaluationResult(const ScriptEvaluationResult& value) = default;
+  ScriptEvaluationResult& operator=(const ScriptEvaluationResult& value) =
+      default;
+  ~ScriptEvaluationResult() = default;
+
+  enum class ResultType {
+    // The script is not evaluated.
+    // Spec: NormalCompletion with empty [[Value]]
+    // |value_| is empty.
+    kNotRun,
+
+    // The script is successfully evaluated.
+    // Spec: #run-a-classic-script/#run-a-module-script return
+    //       NormalCompletion with non-empty [[Value]].
+    // |value_| is its non-empty [[Value]].
+    //
+    // Modules after TLA:
+    // |value_| is the promise returned by #run-a-module-script.
+    // Note: The promise can be rejected.
+    // The script is either:
+    // - Successfully evaluated synchronously
+    //   (|value_|'s [[PromiseState]] is fulfilled), or
+    // - Throwing synchronously during evaluation
+    //   (|value_|'s [[PromiseState]] is rejected), or
+    // - Successfully evaluated until a top-level await and is waiting for the
+    //   promise awaited
+    //   (|value_|'s [[PromiseState]] is pending).
+    kSuccess,
+
+    // The script is evaluated and an exception is thrown.
+    // Spec: #run-a-classic-script/#run-a-module-script return an abrupt
+    //       completion.
+    // |value_| is the non-empty exception thrown for module scripts, or
+    // empty for classic scripts.
+    //
+    // Note: The exception can be already caught and passed to
+    // https://html.spec.whatwg.org/C/#report-the-error, instead of being
+    // rethrown.
+    //
+    // Modules after TLA: #run-a-module-script returns a promise where
+    // [[PromiseState]] is rejected and [[PromiseResult]] is |value_|,
+    // only if #concept-script-error-to-rethrow is not null, i.e.
+    // only for parse/instantiation errors.
+    // Module scripts throwing synchronously during evaluation return kSuccess.
+    // TODO(cbruni, hiroshige): Consider cleaning up this semantics.
+    kException,
+
+    // The script is evaluated and aborted prematurely by
+    // #abort-a-running-script.
+    // |value_| is empty.
+    // This corresponds to that TryCatch::CanContinue() is false, and currently
+    // only checked in classic scripts in WorkerOrWorkletGlobalScope, for
+    // handling e.g.
+    // worker.terminate().
+    // TODO(crbug.com/1129793): Check TryCatch::CanContinue() also in module
+    // scripts.
+    kAborted
+  };
+
+  static ScriptEvaluationResult FromClassicNotRun();
+  static ScriptEvaluationResult FromClassicSuccess(v8::Local<v8::Value> value);
+  static ScriptEvaluationResult FromClassicException();
+  static ScriptEvaluationResult FromClassicAborted();
+
+  static ScriptEvaluationResult FromModuleNotRun();
+  static ScriptEvaluationResult FromModuleSuccess(v8::Local<v8::Value> value);
+  static ScriptEvaluationResult FromModuleException(
+      v8::Local<v8::Value> exception);
+  static ScriptEvaluationResult FromModuleAborted();
+
+  ScriptEvaluationResult& Escape(ScriptState::EscapableScope* scope);
+
+  ResultType GetResultType() const { return result_type_; }
+
+  // Can be called only when GetResultType() == kSuccess.
+  // TODO(crbug.com/1132793): Fix some of the callers (in unit tests) that
+  // expect bool, string, etc., because after TLA is enabled this will return a
+  // promise for modules.
+  v8::Local<v8::Value> GetSuccessValue() const;
+
+  // Returns the exception thrown.
+  // Can be called only when GetResultType() == kException.
+  v8::Local<v8::Value> GetExceptionForModule() const;
+
+  // Returns the promise returned by #run-a-module-script.
+  // Can be called only
+  // - For module script with TLA is enabled, and
+  // - If GetResultType() == kSuccess or kException.
+  //   (For kNotRun/kAborted, we should do nothing)
+  ScriptPromise GetPromise(ScriptState* script_state) const;
+
+ private:
+  ScriptEvaluationResult(mojom::blink::ScriptType,
+                         ResultType,
+                         v8::Local<v8::Value>);
+
+#if DCHECK_IS_ON()
+  mojom::blink::ScriptType script_type_;
+#endif
+
+  ResultType result_type_;
+  v8::Local<v8::Value> value_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SCRIPT_EVALUATION_RESULT_H_
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
index 211ea70..3c7a7a56 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -355,11 +355,6 @@
     v8::Local<v8::Context> context,
     v8::Local<v8::String> source) {
   if (ExecutionContext* execution_context = ToExecutionContext(context)) {
-    DCHECK(execution_context->IsWindow() ||
-           execution_context->IsMainThreadWorkletGlobalScope());
-
-    v8::Context::Scope scope(context);
-
     // Note this callback is only triggered for contexts which have eval
     // disabled. Hence we don't need to handle the case of isolated world
     // contexts with no CSP specified. (They should be exempt from the page CSP.
@@ -367,6 +362,7 @@
 
     if (ContentSecurityPolicy* policy =
             execution_context->GetContentSecurityPolicyForCurrentWorld()) {
+      v8::Context::Scope scope(context);
       v8::String::Value source_str(context->GetIsolate(), source);
       UChar snippet[ContentSecurityPolicy::kMaxSampleLength + 1];
       size_t len = std::min((sizeof(snippet) / sizeof(UChar)) - 1,
@@ -786,6 +782,8 @@
 
   isolate->SetStackLimit(WTF::GetCurrentStackPosition() - kWorkerMaxStackSize);
   isolate->SetPromiseRejectCallback(PromiseRejectHandlerInWorker);
+  isolate->SetModifyCodeGenerationFromStringsCallback(
+      CodeGenerationCheckCallbackInMainThread);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
index 4443d82..dc9b7f4f 100644
--- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
@@ -312,13 +312,14 @@
 }
 
 // https://html.spec.whatwg.org/C/#run-a-classic-script
-ClassicEvaluationResult WorkerOrWorkletScriptController::EvaluateAndReturnValue(
+ScriptEvaluationResult WorkerOrWorkletScriptController::EvaluateAndReturnValue(
     const ScriptSourceCode& source_code,
     SanitizeScriptErrors sanitize_script_errors,
     mojom::blink::V8CacheOptions v8_cache_options,
     RethrowErrorsOption rethrow_errors) {
-  if (IsExecutionForbidden())
-    return ClassicEvaluationResult();
+  if (IsExecutionForbidden()) {
+    return ScriptEvaluationResult::FromClassicNotRun();
+  }
 
   // Scope for |TRACE_EVENT1| and |v8::TryCatch| below.
   {
@@ -368,7 +369,7 @@
     // script evaluation code paths.
     if (!block.CanContinue()) {
       ForbidExecution();
-      return ClassicEvaluationResult();
+      return ScriptEvaluationResult::FromClassicAborted();
     }
 
     CHECK(!IsExecutionForbidden());
@@ -377,10 +378,9 @@
       // Step 10. If evaluationStatus is a normal completion, then return
       // evaluationStatus. [spec text]
       v8::Local<v8::Value> result;
-      if (!maybe_result.ToLocal(&result))
-        return ClassicEvaluationResult();
-
-      return ClassicEvaluationResult(result);
+      bool success = maybe_result.ToLocal(&result);
+      DCHECK(success);
+      return ScriptEvaluationResult::FromClassicSuccess(result);
     }
 
     DCHECK(maybe_result.IsEmpty());
@@ -398,7 +398,7 @@
       // reported to WorkerGlobalScope.onerror via `TryCatch::SetVerbose(true)`
       // called at top-level worker script evaluation.
       block.ReThrow();
-      return ClassicEvaluationResult();
+      return ScriptEvaluationResult::FromClassicException();
     }
   }
   // |v8::TryCatch| is (and should be) exited, before ThrowException() below.
@@ -418,12 +418,12 @@
         isolate_, V8ThrowDOMException::CreateOrEmpty(
                       isolate_, DOMExceptionCode::kNetworkError,
                       rethrow_errors.Message()));
-    return ClassicEvaluationResult();
+    return ScriptEvaluationResult::FromClassicException();
   }
 
   // #report-the-error for rethrow errors == true is already handled via
   // |TryCatch::SetVerbose(true)| above.
-  return ClassicEvaluationResult();
+  return ScriptEvaluationResult::FromClassicException();
 }
 
 void WorkerOrWorkletScriptController::ForbidExecution() {
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
index 14ce99f..5ab5e584 100644
--- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
+++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
@@ -33,9 +33,9 @@
 
 #include "base/macros.h"
 #include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
-#include "third_party/blink/renderer/bindings/core/v8/classic_evaluation_result.h"
 #include "third_party/blink/renderer/bindings/core/v8/rejected_promises.h"
 #include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -96,7 +96,7 @@
 
   // https://html.spec.whatwg.org/C/#run-a-classic-script
   // Callers should enter ScriptState::Scope before calling this.
-  ClassicEvaluationResult EvaluateAndReturnValue(
+  ScriptEvaluationResult EvaluateAndReturnValue(
       const ScriptSourceCode&,
       SanitizeScriptErrors sanitize_script_errors,
       mojom::blink::V8CacheOptions = mojom::blink::V8CacheOptions::kDefault,
diff --git a/third_party/blink/renderer/core/css/view-source.css b/third_party/blink/renderer/core/css/view-source.css
index 699f4b0..3ed9294 100644
--- a/third_party/blink/renderer/core/css/view-source.css
+++ b/third_party/blink/renderer/core/css/view-source.css
@@ -27,7 +27,7 @@
 }
 
 table {
-    width: 100%;
+    width: max-content;
     border-spacing: 0;
     white-space: pre;
     margin: 0;
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
index 3edb10e..968b50a9 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -395,14 +395,17 @@
   DCHECK(IsLocked());
   DCHECK(ShouldCommitForActivation(DisplayLockActivationReason::kAny));
 
-  // Find in page scrolls content into view. However, if the position of the
-  // target is outside of the bounds that would cause the auto-context to
-  // unlock, then we can scroll into wrong content while the context remains
-  // lock. To avoid this, unlock it until the next lifecycle. If the scroll is
-  // successful, then we will gain visibility anyway so the context will be
-  // unlocked for other reasons.
-  // TODO(vmpstr): See if scrollIntoView() needs this as well.
-  if (reason == DisplayLockActivationReason::kFindInPage) {
+  // The following actions (can) scroll content into view. However, if the
+  // position of the target is outside of the bounds that would cause the
+  // auto-context to unlock, then we can scroll into wrong content while the
+  // context remains lock. To avoid this, unlock it until the next lifecycle.
+  // If the scroll is successful, then we will gain visibility anyway so the
+  // context will be unlocked for other reasons.
+  if (reason == DisplayLockActivationReason::kAccessibility ||
+      reason == DisplayLockActivationReason::kFindInPage ||
+      reason == DisplayLockActivationReason::kFragmentNavigation ||
+      reason == DisplayLockActivationReason::kScrollIntoView ||
+      reason == DisplayLockActivationReason::kSimulatedClick) {
     // Note that because the visibility is only determined at the _end_ of the
     // next frame, we need to ensure that we stay unlocked for two frames.
     SetKeepUnlockedUntilLifecycleCount(2);
diff --git a/third_party/blink/renderer/core/html/forms/html_input_element.cc b/third_party/blink/renderer/core/html/forms/html_input_element.cc
index 240a846..e73c739 100644
--- a/third_party/blink/renderer/core/html/forms/html_input_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_input_element.cc
@@ -1966,6 +1966,14 @@
   return input_type_->SupportsInputModeAttribute();
 }
 
+void HTMLInputElement::CapsLockStateMayHaveChanged() {
+  input_type_view_->CapsLockStateMayHaveChanged();
+}
+
+bool HTMLInputElement::ShouldDrawCapsLockIndicator() const {
+  return input_type_view_->ShouldDrawCapsLockIndicator();
+}
+
 void HTMLInputElement::SetShouldRevealPassword(bool value) {
   if (!!should_reveal_password_ == value)
     return;
diff --git a/third_party/blink/renderer/core/html/forms/html_input_element.h b/third_party/blink/renderer/core/html/forms/html_input_element.h
index 04857422..b8eaae0 100644
--- a/third_party/blink/renderer/core/html/forms/html_input_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_input_element.h
@@ -316,6 +316,8 @@
 
   bool SupportsInputModeAttribute() const;
 
+  void CapsLockStateMayHaveChanged();
+  bool ShouldDrawCapsLockIndicator() const;
   void SetShouldRevealPassword(bool value);
   bool ShouldRevealPassword() const { return should_reveal_password_; }
   AXObject* PopupRootAXObject();
diff --git a/third_party/blink/renderer/core/html/forms/input_type_view.cc b/third_party/blink/renderer/core/html/forms/input_type_view.cc
index e5251f5..8819c83 100644
--- a/third_party/blink/renderer/core/html/forms/input_type_view.cc
+++ b/third_party/blink/renderer/core/html/forms/input_type_view.cc
@@ -180,6 +180,12 @@
 
 void InputTypeView::ListAttributeTargetChanged() {}
 
+void InputTypeView::CapsLockStateMayHaveChanged() {}
+
+bool InputTypeView::ShouldDrawCapsLockIndicator() const {
+  return false;
+}
+
 void InputTypeView::UpdateClearButtonVisibility() {}
 
 void InputTypeView::UpdatePlaceholderText() {}
diff --git a/third_party/blink/renderer/core/html/forms/input_type_view.h b/third_party/blink/renderer/core/html/forms/input_type_view.h
index ad0d260..f2a5ed4 100644
--- a/third_party/blink/renderer/core/html/forms/input_type_view.h
+++ b/third_party/blink/renderer/core/html/forms/input_type_view.h
@@ -132,6 +132,8 @@
   virtual void ValueAttributeChanged();
   virtual void DidSetValue(const String&, bool value_changed);
   virtual void ListAttributeTargetChanged();
+  virtual void CapsLockStateMayHaveChanged();
+  virtual bool ShouldDrawCapsLockIndicator() const;
   virtual void UpdateClearButtonVisibility();
   virtual void UpdatePlaceholderText();
   virtual AXObject* PopupRootAXObject();
diff --git a/third_party/blink/renderer/core/html/forms/password_input_type.cc b/third_party/blink/renderer/core/html/forms/password_input_type.cc
index 92f00a1f..bdc7976 100644
--- a/third_party/blink/renderer/core/html/forms/password_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/password_input_type.cc
@@ -43,6 +43,7 @@
 #include "third_party/blink/renderer/core/html/forms/form_controller.h"
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
+#include "third_party/blink/renderer/core/input/keyboard_event_manager.h"
 #include "third_party/blink/renderer/core/input_type_names.h"
 #include "third_party/blink/renderer/core/layout/layout_text_control_single_line.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -126,6 +127,30 @@
     UpdatePasswordRevealButton();
 }
 
+void PasswordInputType::CapsLockStateMayHaveChanged() {
+  auto& document = GetElement().GetDocument();
+  LocalFrame* frame = document.GetFrame();
+  // Only draw the caps lock indicator if these things are true:
+  // 1) The field is a password field
+  // 2) The frame is active
+  // 3) The element is focused
+  // 4) The caps lock is on
+  const bool should_draw_caps_lock_indicator =
+      frame && frame->Selection().FrameIsFocusedAndActive() &&
+      document.FocusedElement() == GetElement() &&
+      KeyboardEventManager::CurrentCapsLockState();
+
+  if (should_draw_caps_lock_indicator != should_draw_caps_lock_indicator_) {
+    should_draw_caps_lock_indicator_ = should_draw_caps_lock_indicator;
+    if (auto* layout_object = GetElement().GetLayoutObject())
+      layout_object->SetShouldDoFullPaintInvalidation();
+  }
+}
+
+bool PasswordInputType::ShouldDrawCapsLockIndicator() const {
+  return should_draw_caps_lock_indicator_;
+}
+
 void PasswordInputType::UpdatePasswordRevealButton() {
   Element* button = GetElement().UserAgentShadowRoot()->getElementById(
       shadow_element_names::kIdPasswordRevealButton);
@@ -163,6 +188,16 @@
   }
 }
 
+void PasswordInputType::ForwardEvent(Event& event) {
+  BaseTextInputType::ForwardEvent(event);
+
+  if (GetElement().GetLayoutObject() &&
+      !GetElement().GetForceReattachLayoutTree() &&
+      (event.type() == event_type_names::kBlur ||
+       event.type() == event_type_names::kFocus))
+    CapsLockStateMayHaveChanged();
+}
+
 void PasswordInputType::HandleBlurEvent() {
   if (RuntimeEnabledFeatures::PasswordRevealEnabled()) {
     should_show_reveal_button_ = false;
diff --git a/third_party/blink/renderer/core/html/forms/password_input_type.h b/third_party/blink/renderer/core/html/forms/password_input_type.h
index 8dff1f7..5ac3317 100644
--- a/third_party/blink/renderer/core/html/forms/password_input_type.h
+++ b/third_party/blink/renderer/core/html/forms/password_input_type.h
@@ -54,16 +54,20 @@
   void CreateShadowSubtree() override;
 
   void UpdateView() override;
+  void CapsLockStateMayHaveChanged() override;
+  bool ShouldDrawCapsLockIndicator() const override;
   void UpdatePasswordRevealButton();
   void DidSetValueByUserEdit() override;
   void DidSetValue(const String&, bool value_changed) override;
 
+  void ForwardEvent(Event& event) override;
   void HandleKeydownEvent(KeyboardEvent&) override;
   void HandleBeforeTextInsertedEvent(BeforeTextInsertedEvent&) override;
 
   void HandleBlurEvent() override;
   bool SupportsInputModeAttribute() const override;
 
+  bool should_draw_caps_lock_indicator_ = false;
   bool should_show_reveal_button_ = false;
 };
 
diff --git a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
index b0e6c4b..b7938ca 100644
--- a/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/text_field_input_type.cc
@@ -239,8 +239,6 @@
        event.HasInterface(event_interface_names::kWheelEvent) ||
        event.type() == event_type_names::kBlur ||
        event.type() == event_type_names::kFocus)) {
-    auto* layout_text_control =
-        To<LayoutTextControlSingleLine>(GetElement().GetLayoutObject());
     if (event.type() == event_type_names::kBlur) {
       if (LayoutBox* inner_editor_layout_object =
               GetElement().InnerEditorElement()->GetLayoutBox()) {
@@ -253,10 +251,6 @@
           }
         }
       }
-
-      layout_text_control->CapsLockStateMayHaveChanged();
-    } else if (event.type() == event_type_names::kFocus) {
-      layout_text_control->CapsLockStateMayHaveChanged();
     }
 
     GetElement().ForwardEvent(event);
diff --git a/third_party/blink/renderer/core/html/forms/text_field_input_type.h b/third_party/blink/renderer/core/html/forms/text_field_input_type.h
index 645df53..4f24cb60 100644
--- a/third_party/blink/renderer/core/html/forms/text_field_input_type.h
+++ b/third_party/blink/renderer/core/html/forms/text_field_input_type.h
@@ -58,6 +58,7 @@
   void DisabledAttributeChanged() override;
   void ReadonlyAttributeChanged() override;
   bool SupportsReadOnly() const override;
+  void ForwardEvent(Event&) override;
   void HandleBlurEvent() override;
   void HandleBeforeTextInsertedEvent(BeforeTextInsertedEvent&) override;
   String SanitizeValue(const String&) const override;
@@ -84,7 +85,6 @@
   bool MayTriggerVirtualKeyboard() const final;
   bool IsTextField() const final;
   bool ValueMissing(const String&) const override;
-  void ForwardEvent(Event&) final;
   bool ShouldSubmitImplicitly(const Event&) final;
   bool ShouldRespectListAttribute() override;
   void ListAttributeTargetChanged() override;
diff --git a/third_party/blink/renderer/core/html/html_view_source_document.cc b/third_party/blink/renderer/core/html/html_view_source_document.cc
index 3176975..797ff5d1 100644
--- a/third_party/blink/renderer/core/html/html_view_source_document.cc
+++ b/third_party/blink/renderer/core/html/html_view_source_document.cc
@@ -70,7 +70,6 @@
   body->ParserAppendChild(div);
 
   auto* table = MakeGarbageCollected<HTMLTableElement>(*this);
-  table->SetInlineStyleProperty(CSSPropertyID::kWhiteSpace, CSSValueID::kPre);
   body->ParserAppendChild(table);
   tbody_ = MakeGarbageCollected<HTMLTableSectionElement>(html_names::kTbodyTag,
                                                          *this);
diff --git a/third_party/blink/renderer/core/html/html_view_source_document_test.cc b/third_party/blink/renderer/core/html/html_view_source_document_test.cc
index 391645e..8110668 100644
--- a/third_party/blink/renderer/core/html/html_view_source_document_test.cc
+++ b/third_party/blink/renderer/core/html/html_view_source_document_test.cc
@@ -38,8 +38,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td "
       "class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
       "value=\"2\"></td><td class=\"line-content\">      <span "
@@ -92,8 +91,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td "
       "class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
       "value=\"2\"></td><td class=\"line-content\">      <span "
@@ -145,8 +143,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td "
       "class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
       "value=\"2\"></td><td class=\"line-content\">      <span "
@@ -211,8 +208,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td "
       "class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
       "value=\"2\"></td><td class=\"line-content\">      <span "
@@ -280,8 +276,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td "
       "class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
       "value=\"2\"></td><td class=\"line-content\"><br></td></tr><tr><td "
@@ -313,8 +308,7 @@
   LoadMainResource((many_spaces + std::string("       <b>A</b>  ")).c_str());
   std::string expected_beginning(
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td class=\"line-content\">     "
       " ");
   std::string expected_ending(
@@ -330,8 +324,7 @@
   LoadMainResource("1234567");
   EXPECT_EQ(GetDocument().documentElement()->outerHTML(),
             "<html><head></head><body><div "
-            "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-            "pre;\"><tbody><tr><td "
+            "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
             "class=\"line-number\" value=\"1\"></td><td "
             "class=\"line-content\">1234567<span "
             "class=\"html-end-of-file\"></span></td></tr></tbody></table></"
@@ -353,8 +346,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td "
       "class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
       "value=\"2\"></td><td class=\"line-content\">      <span "
@@ -421,8 +413,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td "
       "class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
       "value=\"2\"></td><td class=\"line-content\">      <span "
@@ -453,8 +444,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td "
       "class=\"line-content\"><br></td></tr><tr><td class=\"line-number\" "
       "value=\"2\"></td><td class=\"line-content\">      Incomplete token "
@@ -476,8 +466,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td class=\"line-content\"><span "
       "class=\"html-tag\">&lt;textarea&gt;</span>foobar in "
       "textarea</td></tr><tr><td class=\"line-number\" value=\"2\"></td><td "
@@ -492,8 +481,7 @@
   EXPECT_EQ(
       GetDocument().documentElement()->outerHTML(),
       "<html><head></head><body><div "
-      "class=\"line-gutter-backdrop\"></div><table style=\"white-space: "
-      "pre;\"><tbody><tr><td "
+      "class=\"line-gutter-backdrop\"></div><table><tbody><tr><td "
       "class=\"line-number\" value=\"1\"></td><td class=\"line-content\"><span "
       "class=\"html-tag\">&lt;script&gt;</span>foobar in "
       "script</td></tr><tr><td class=\"line-number\" value=\"2\"></td><td "
diff --git a/third_party/blink/renderer/core/input/keyboard_event_manager.cc b/third_party/blink/renderer/core/input/keyboard_event_manager.cc
index 875aae45..9776ad8aa 100644
--- a/third_party/blink/renderer/core/input/keyboard_event_manager.cc
+++ b/third_party/blink/renderer/core/input/keyboard_event_manager.cc
@@ -18,13 +18,12 @@
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/html/html_dialog_element.h"
 #include "third_party/blink/renderer/core/input/event_handler.h"
 #include "third_party/blink/renderer/core/input/event_handling_util.h"
 #include "third_party/blink/renderer/core/input/input_device_capabilities.h"
 #include "third_party/blink/renderer/core/input/scroll_manager.h"
-#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/layout/layout_text_control_single_line.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/page/page.h"
@@ -348,10 +347,8 @@
 
 void KeyboardEventManager::CapsLockStateMayHaveChanged() {
   if (Element* element = frame_->GetDocument()->FocusedElement()) {
-    if (LayoutObject* r = element->GetLayoutObject()) {
-      if (auto* text_control = DynamicTo<LayoutTextControlSingleLine>(r))
-        text_control->CapsLockStateMayHaveChanged();
-    }
+    if (auto* text_control = DynamicTo<HTMLInputElement>(element))
+      text_control->CapsLockStateMayHaveChanged();
   }
 }
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index 20e71fd..9e41b60 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -641,9 +641,11 @@
       break;
   }
 
-  // Use mime type from cached resource in case the one in response is empty.
+  // Use mime type from cached resource in case the one in response is empty
+  // or the response is a 304 Not Modified.
   String mime_type = response.MimeType();
-  if (mime_type.IsEmpty() && cached_resource)
+  if (cached_resource &&
+      (mime_type.IsEmpty() || response.HttpStatusCode() == 304))
     mime_type = cached_resource->GetResponse().MimeType();
 
   if (is_empty)
diff --git a/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc b/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
index a484ab4..461ae6d 100644
--- a/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
@@ -1900,6 +1900,24 @@
 
   CSSRuleVector& parsed_rules = parsed_flat_rules_;
 
+  if (page_style_sheet_->IsConstructed()) {
+    // If we are dealing with constructed stylesheets, the order
+    // of the parsed_rules matches the order of cssom_rules
+    // because the source CSS is generated based on CSSOM rules
+    // in the same order.
+    // Therefore, we can skip the expensive diff algorithm below
+    // that causes performance issues if there are subtle differences
+    // in rules due to specific issues with the CSS parser.
+    // See crbug.com/1131113, crbug.com/604023, crbug.com/1132778.
+    DCHECK(parsed_rules.size() == cssom_rules.size());
+    auto min_size = std::min(parsed_rules.size(), cssom_rules.size());
+    for (wtf_size_t i = 0; i < min_size; ++i) {
+      rule_to_source_data_.Set(i, i);
+      source_data_to_rule_.Set(i, i);
+    }
+    return;
+  }
+
   Vector<String> cssom_rules_text = Vector<String>();
   Vector<String> parsed_rules_text = Vector<String>();
   for (wtf_size_t i = 0; i < cssom_rules.size(); ++i)
diff --git a/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc b/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
index b9e56a2..7be1af4 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
@@ -26,15 +26,10 @@
 
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/editing/frame_selection.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
-#include "third_party/blink/renderer/core/input/keyboard_event_manager.h"
-#include "third_party/blink/renderer/core/input_type_names.h"
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
 #include "third_party/blink/renderer/core/layout/layout_analyzer.h"
-#include "third_party/blink/renderer/core/layout/layout_theme.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/paint/text_control_single_line_painter.h"
 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
 
@@ -42,7 +37,7 @@
 
 LayoutTextControlSingleLine::LayoutTextControlSingleLine(
     HTMLInputElement* element)
-    : LayoutTextControl(element), should_draw_caps_lock_indicator_(false) {}
+    : LayoutTextControl(element) {}
 
 LayoutTextControlSingleLine::~LayoutTextControlSingleLine() = default;
 
@@ -179,31 +174,6 @@
   return true;
 }
 
-void LayoutTextControlSingleLine::CapsLockStateMayHaveChanged() {
-  NOT_DESTROYED();
-  if (!GetNode())
-    return;
-
-  // Only draw the caps lock indicator if these things are true:
-  // 1) The field is a password field
-  // 2) The frame is active
-  // 3) The element is focused
-  // 4) The caps lock is on
-  bool should_draw_caps_lock_indicator = false;
-
-  if (LocalFrame* frame = GetDocument().GetFrame())
-    should_draw_caps_lock_indicator =
-        InputElement()->type() == input_type_names::kPassword &&
-        frame->Selection().FrameIsFocusedAndActive() &&
-        GetDocument().FocusedElement() == GetNode() &&
-        KeyboardEventManager::CurrentCapsLockState();
-
-  if (should_draw_caps_lock_indicator != should_draw_caps_lock_indicator_) {
-    should_draw_caps_lock_indicator_ = should_draw_caps_lock_indicator;
-    SetShouldDoFullPaintInvalidation();
-  }
-}
-
 LayoutUnit LayoutTextControlSingleLine::PreferredContentLogicalWidth(
     float char_width) const {
   NOT_DESTROYED();
diff --git a/third_party/blink/renderer/core/layout/layout_text_control_single_line.h b/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
index 006b889..d727acc 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
+++ b/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
@@ -42,12 +42,6 @@
   LayoutTextControlSingleLine(HTMLInputElement*);
   ~LayoutTextControlSingleLine() override;
 
-  void CapsLockStateMayHaveChanged();
-  bool ShouldDrawCapsLockIndicator() const {
-    NOT_DESTROYED();
-    return should_draw_caps_lock_indicator_;
-  }
-
  protected:
   Element* ContainerElement() const;
   Element* EditingViewPortElement() const;
@@ -90,8 +84,6 @@
   }
 
   HTMLElement* InnerSpinButtonElement() const;
-
-  bool should_draw_caps_lock_indicator_;
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_test.cc b/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_test.cc
index 3bf55bf..34bffe0 100644
--- a/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_test.cc
@@ -44,7 +44,7 @@
     return GetGlobalScope()->ScriptController()->GetScriptState();
   }
 
-  ModuleEvaluationResult EvaluateScriptModule(const String& source_code) {
+  ScriptEvaluationResult EvaluateScriptModule(const String& source_code) {
     ScriptState* script_state = GetScriptState();
     EXPECT_TRUE(script_state);
 
@@ -69,7 +69,7 @@
 
 TEST_F(LayoutWorkletTest, ParseProperties) {
   ScriptState::Scope scope(GetScriptState());
-  EXPECT_TRUE(EvaluateScriptModule(R"JS(
+  EXPECT_EQ(EvaluateScriptModule(R"JS(
     registerLayout('foo', class {
       static get inputProperties() { return ['--prop', 'flex-basis', 'thing'] }
       static get childInputProperties() { return ['--child-prop', 'margin-top', 'other-thing'] }
@@ -77,7 +77,8 @@
       async layout() { }
     });
   )JS")
-                  .IsSuccess());
+                .GetResultType(),
+            ScriptEvaluationResult::ResultType::kSuccess);
 
   LayoutWorkletGlobalScope* global_scope = GetGlobalScope();
   CSSLayoutDefinition* definition = global_scope->FindDefinition("foo");
@@ -105,14 +106,15 @@
 
 TEST_F(LayoutWorkletTest, RegisterLayout) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     registerLayout('foo', class {
       async intrinsicSizes() { }
       async layout() { }
     });
   )JS");
 
-  EXPECT_TRUE(result.IsSuccess());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kSuccess);
 
   result = EvaluateScriptModule(R"JS(
     registerLayout('bar', class {
@@ -123,23 +125,25 @@
     });
   )JS");
 
-  EXPECT_TRUE(result.IsSuccess());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kSuccess);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_EmptyName) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     registerLayout('', class {
     });
   )JS");
 
   // "The empty string is not a valid name."
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_Duplicate) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     registerLayout('foo', class {
       async intrinsicSizes() { }
       async layout() { }
@@ -151,95 +155,103 @@
   )JS");
 
   // "A class with name:'foo' is already registered."
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_NoIntrinsicSizes) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     registerLayout('foo', class {
     });
   )JS");
 
   // "The 'intrinsicSizes' property on the prototype does not exist."
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_ThrowingPropertyGetter) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     registerLayout('foo', class {
       static get inputProperties() { throw Error(); }
     });
   )JS");
 
   // "Uncaught Error"
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_BadPropertyGetter) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     registerLayout('foo', class {
       static get inputProperties() { return 42; }
     });
   )JS");
 
   // "The provided value cannot be converted to a sequence."
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_NoPrototype) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     const foo = function() { };
     foo.prototype = undefined;
     registerLayout('foo', foo);
   )JS");
 
   // "The 'prototype' object on the class does not exist."
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_BadPrototype) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     const foo = function() { };
     foo.prototype = 42;
     registerLayout('foo', foo);
   )JS");
 
   // "The 'prototype' property on the class is not an object."
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_BadIntrinsicSizes) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     registerLayout('foo', class {
       get intrinsicSizes() { return 42; }
     });
   )JS");
 
   // "The 'intrinsicSizes' property on the prototype is not a function."
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_NoLayout) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     registerLayout('foo', class {
       async intrinsicSizes() { }
     });
   )JS");
 
   // "The 'layout' property on the prototype does not exist."
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 TEST_F(LayoutWorkletTest, RegisterLayout_BadLayout) {
   ScriptState::Scope scope(GetScriptState());
-  ModuleEvaluationResult result = EvaluateScriptModule(R"JS(
+  ScriptEvaluationResult result = EvaluateScriptModule(R"JS(
     registerLayout('foo', class {
       async intrinsicSizes() { }
       get layout() { return 42; }
@@ -247,7 +259,8 @@
   )JS");
 
   // "The 'layout' property on the prototype is not a function."
-  EXPECT_TRUE(result.IsException());
+  EXPECT_EQ(result.GetResultType(),
+            ScriptEvaluationResult::ResultType::kException);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_box_utils.cc b/third_party/blink/renderer/core/layout/ng/layout_box_utils.cc
index b6327df..4b258bf 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_box_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_box_utils.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 
 namespace blink {
@@ -170,4 +171,33 @@
   return LayoutBox::SkipContainingBlockForPercentHeightCalculation(cb);
 }
 
+LayoutUnit LayoutBoxUtils::TotalBlockSize(const LayoutBox& box) {
+  wtf_size_t num_fragments = box.PhysicalFragmentCount();
+  DCHECK_GT(num_fragments, 0u);
+
+  // Calculate the total block size by looking at the last two block fragments
+  // with a non-zero block-size.
+  LayoutUnit total_block_size;
+  while (num_fragments > 0) {
+    LayoutUnit block_size =
+        box.GetPhysicalFragment(num_fragments - 1)
+            ->Size()
+            .ConvertToLogical(box.StyleRef().GetWritingMode())
+            .block_size;
+    if (block_size > LayoutUnit()) {
+      total_block_size += block_size;
+      break;
+    }
+    num_fragments--;
+  }
+
+  if (num_fragments > 1) {
+    total_block_size +=
+        To<NGBlockBreakToken>(
+            box.GetPhysicalFragment(num_fragments - 2)->BreakToken())
+            ->ConsumedBlockSize();
+  }
+  return total_block_size;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_box_utils.h b/third_party/blink/renderer/core/layout/ng/layout_box_utils.h
index c8ef21f..497beee 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_box_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_box_utils.h
@@ -38,6 +38,9 @@
 
   static bool SkipContainingBlockForPercentHeightCalculation(
       const LayoutBlock* cb);
+
+  // The total block size of all fragments.
+  static LayoutUnit TotalBlockSize(const LayoutBox& box);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
index 5a5955eb..862e7db 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
@@ -425,19 +425,28 @@
     const ComputedStyle& style,
     const NGBoxStrut& border_padding,
     const NGLogicalStaticPosition& static_position,
-    const base::Optional<MinMaxSizes>& min_max_sizes,
+    const base::Optional<MinMaxSizes>& minmax_content_sizes,
+    const base::Optional<MinMaxSizes>& minmax_intrinsic_sizes_for_ar,
     const base::Optional<LogicalSize>& replaced_size,
     const WritingMode container_writing_mode,
     const TextDirection container_direction,
     NGLogicalOutOfFlowDimensions* dimensions) {
   DCHECK(dimensions);
 
-  LayoutUnit min_inline_size = ResolveMinInlineLength(
-      space, style, border_padding, min_max_sizes, style.LogicalMinWidth(),
-      LengthResolvePhase::kLayout);
+  Length min_inline_length = style.LogicalMinWidth();
+  base::Optional<MinMaxSizes> min_size_minmax = minmax_content_sizes;
+  // We don't need to check for IsInlineSizeComputableFromBlockSize; this is
+  // done by the caller.
+  if (minmax_intrinsic_sizes_for_ar) {
+    min_inline_length = Length::MinIntrinsic();
+    min_size_minmax = minmax_intrinsic_sizes_for_ar;
+  }
+  LayoutUnit min_inline_size =
+      ResolveMinInlineLength(space, style, border_padding, min_size_minmax,
+                             min_inline_length, LengthResolvePhase::kLayout);
   LayoutUnit max_inline_size = ResolveMaxInlineLength(
-      space, style, border_padding, min_max_sizes, style.LogicalMaxWidth(),
-      LengthResolvePhase::kLayout);
+      space, style, border_padding, minmax_content_sizes,
+      style.LogicalMaxWidth(), LengthResolvePhase::kLayout);
 
   // This implements the transferred min/max sizes per
   // https://drafts.csswg.org/css-sizing-4/#aspect-ratio
@@ -451,8 +460,9 @@
   bool is_table = style.IsDisplayTableBox();
   base::Optional<LayoutUnit> inline_size;
   if (!style.LogicalWidth().IsAuto()) {
-    LayoutUnit resolved_inline_size = ResolveMainInlineLength(
-        space, style, border_padding, min_max_sizes, style.LogicalWidth());
+    LayoutUnit resolved_inline_size =
+        ResolveMainInlineLength(space, style, border_padding,
+                                minmax_content_sizes, style.LogicalWidth());
 
     // Tables use the inline-size as a minimum.
     if (is_table)
@@ -462,8 +472,8 @@
   } else if (replaced_size.has_value()) {
     inline_size = replaced_size->inline_size;
   } else if (IsInlineSizeComputableFromBlockSize(style)) {
-    DCHECK(min_max_sizes.has_value());
-    inline_size = min_max_sizes->min_size;
+    DCHECK(minmax_content_sizes.has_value());
+    inline_size = minmax_content_sizes->min_size;
   }
 
   bool is_start_dominant;
@@ -478,7 +488,7 @@
   }
 
   ComputeAbsoluteSize(
-      border_padding.InlineSum(), min_max_sizes,
+      border_padding.InlineSum(), minmax_content_sizes,
       space.PercentageResolutionInlineSizeForParentWritingMode(),
       space.AvailableSize().inline_size, style.MarginStart(), style.MarginEnd(),
       style.LogicalInlineStart(), style.LogicalInlineEnd(), min_inline_size,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h
index ec4a18d..4bd7b44a 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h
@@ -61,6 +61,8 @@
 
 // Computes part of the absolute position which depends on the child's
 // inline-size.
+// |minmax_intrinsic_size_for_ar| is only used for min-inline-size: auto in
+// combination with aspect-ratio.
 // |replaced_size| should be set if and only if element is replaced element.
 // Returns the partially filled position.
 CORE_EXPORT void ComputeOutOfFlowInlineDimensions(
@@ -68,7 +70,8 @@
     const ComputedStyle&,
     const NGBoxStrut& border_padding,
     const NGLogicalStaticPosition&,
-    const base::Optional<MinMaxSizes>& child_minmax,
+    const base::Optional<MinMaxSizes>& minmax_content_sizes,
+    const base::Optional<MinMaxSizes>& minmax_intrinsic_sizes_for_ar,
     const base::Optional<LogicalSize>& replaced_size,
     const WritingMode container_writing_mode,
     const TextDirection container_direction,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc
index 07dad74..2a8ff06 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc
@@ -161,10 +161,10 @@
   SetHorizontalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
   estimated_inline = min_max_60;
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(min_max_60.min_size, dimensions.size.inline_size);
   EXPECT_EQ(LayoutUnit(0), dimensions.inset.inline_start);
 
@@ -172,18 +172,18 @@
   SetHorizontalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
   estimated_inline = min_max_60;
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position_inline_end, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position_inline_end,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(min_max_60.min_size, dimensions.size.inline_size);
   EXPECT_EQ(container_size_.inline_size, dimensions.inset.inline_end);
 
   // All auto + RTL.
-  ComputeOutOfFlowInlineDimensions(rtl_space_, *style_, rtl_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      rtl_space_, *style_, rtl_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(min_max_60.min_size, dimensions.size.inline_size);
   EXPECT_EQ(container_size_.inline_size - min_max_60.min_size,
             dimensions.inset.inline_end);
@@ -192,10 +192,10 @@
   SetHorizontalStyle(left, NGAuto, width, NGAuto, right);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
   estimated_inline.reset();
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   LayoutUnit margin_space = (container_size_.inline_size - left - right -
                              dimensions.size.inline_size) /
                             2;
@@ -229,10 +229,10 @@
   // left, right, and width are known, not enough space for margins LTR.
   SetHorizontalStyle(left, NGAuto, LayoutUnit(200), NGAuto, right);
   estimated_inline.reset();
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(left, dimensions.inset.inline_start);
   EXPECT_EQ(-left, dimensions.inset.inline_end);
 
@@ -240,10 +240,10 @@
   SetHorizontalStyle(left, NGAuto, LayoutUnit(200), NGAuto, right,
                      WritingMode::kHorizontalTb);
   estimated_inline.reset();
-  ComputeOutOfFlowInlineDimensions(rtl_space_, *style_, rtl_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kRtl, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      rtl_space_, *style_, rtl_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kRtl, &dimensions);
   EXPECT_EQ(-right, dimensions.inset.inline_start);
   EXPECT_EQ(right, dimensions.inset.inline_end);
 
@@ -251,20 +251,20 @@
   SetHorizontalStyle(NGAuto, margin_left, NGAuto, margin_right, right);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
   estimated_inline = min_max_60;
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(min_max_60.min_size, dimensions.size.inline_size);
 
   // Rule 2 left and right are auto LTR.
   SetHorizontalStyle(NGAuto, margin_left, width, margin_right, NGAuto);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
   estimated_inline.reset();
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(margin_left, dimensions.inset.inline_start);
   EXPECT_EQ(container_size_.inline_size - margin_left - width,
             dimensions.inset.inline_end);
@@ -273,10 +273,10 @@
   SetHorizontalStyle(NGAuto, margin_left, width, margin_right, NGAuto);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
   estimated_inline.reset();
-  ComputeOutOfFlowInlineDimensions(rtl_space_, *style_, rtl_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      rtl_space_, *style_, rtl_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(margin_left, dimensions.inset.inline_start);
   EXPECT_EQ(container_size_.inline_size - margin_left - width,
             dimensions.inset.inline_end);
@@ -285,10 +285,10 @@
   SetHorizontalStyle(left, margin_left, NGAuto, margin_right, NGAuto);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
   estimated_inline = min_max_60;
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(
       container_size_.inline_size - min_max_60.min_size - left - margin_left,
       dimensions.inset.inline_end);
@@ -298,10 +298,10 @@
   SetHorizontalStyle(NGAuto, margin_left, width, margin_right, right);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
   estimated_inline.reset();
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(left + margin_left, dimensions.inset.inline_start);
 
   // Rule 4: left is auto, EBoxSizing::kContentBox
@@ -311,10 +311,10 @@
                      margin_right, right);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
   estimated_inline.reset();
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(left + margin_left, dimensions.inset.inline_start);
   style_->SetBoxSizing(EBoxSizing::kBorderBox);
 
@@ -322,20 +322,20 @@
   SetHorizontalStyle(left, margin_left, width, margin_right, NGAuto);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
   estimated_inline.reset();
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(right + margin_right, dimensions.inset.inline_end);
 
   // Rule 6: width is auto.
   SetHorizontalStyle(left, margin_left, NGAuto, margin_right, right);
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
   estimated_inline.reset();
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(width, dimensions.size.inline_size);
 }
 
@@ -430,7 +430,7 @@
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
   ComputeOutOfFlowInlineDimensions(vlr_space_, *style_, vlr_border_padding,
                                    static_position, min_max_60, base::nullopt,
-                                   WritingMode::kHorizontalTb,
+                                   base::nullopt, WritingMode::kHorizontalTb,
                                    TextDirection::kLtr, &dimensions);
   EXPECT_EQ(top + margin_space, dimensions.inset.inline_start);
   EXPECT_EQ(bottom + margin_space, dimensions.inset.inline_end);
@@ -441,7 +441,7 @@
   EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
   ComputeOutOfFlowInlineDimensions(vrl_space_, *style_, vrl_border_padding,
                                    static_position, min_max_60, base::nullopt,
-                                   WritingMode::kHorizontalTb,
+                                   base::nullopt, WritingMode::kHorizontalTb,
                                    TextDirection::kLtr, &dimensions);
   EXPECT_EQ(top + margin_space, dimensions.inset.inline_start);
   EXPECT_EQ(bottom + margin_space, dimensions.inset.inline_end);
@@ -549,7 +549,7 @@
 
   ComputeOutOfFlowInlineDimensions(
       ltr_space_, *style_, border_padding, static_position,
-      MinMaxSizes{LayoutUnit(), LayoutUnit(1000)}, base::nullopt,
+      MinMaxSizes{LayoutUnit(), LayoutUnit(1000)}, base::nullopt, base::nullopt,
       WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(LayoutUnit(100), dimensions.size.inline_size);
   EXPECT_EQ(LayoutUnit(100), dimensions.inset.inline_start);
@@ -557,7 +557,7 @@
 
   ComputeOutOfFlowInlineDimensions(
       ltr_space_, *style_, border_padding, static_position,
-      MinMaxSizes{LayoutUnit(), LayoutUnit(1000)}, base::nullopt,
+      MinMaxSizes{LayoutUnit(), LayoutUnit(1000)}, base::nullopt, base::nullopt,
       WritingMode::kHorizontalTb, TextDirection::kRtl, &dimensions);
   EXPECT_EQ(LayoutUnit(100), dimensions.size.inline_size);
   EXPECT_EQ(LayoutUnit(100), dimensions.inset.inline_start);
@@ -595,26 +595,26 @@
 
   // width < min gets set to min.
   SetHorizontalStyle(NGAuto, NGAuto, LayoutUnit(5), NGAuto, NGAuto);
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(min, dimensions.size.inline_size);
 
   // width > max gets set to max.
   SetHorizontalStyle(NGAuto, NGAuto, LayoutUnit(200), NGAuto, NGAuto);
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(max, dimensions.size.inline_size);
 
   // Unspecified width becomes min_max, gets clamped to min.
   SetHorizontalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
-  ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
-                                   static_position, estimated_inline,
-                                   base::nullopt, WritingMode::kHorizontalTb,
-                                   TextDirection::kLtr, &dimensions);
+  ComputeOutOfFlowInlineDimensions(
+      ltr_space_, *style_, ltr_border_padding, static_position,
+      estimated_inline, base::nullopt, base::nullopt,
+      WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
   EXPECT_EQ(min, dimensions.size.inline_size);
 
   // HEIGHT TESTS
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 4a3cdf6..28a5293 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -87,8 +87,8 @@
             descendant.static_position.ConvertToLogical(empty_outer_size);
         oof_positioned_fragmentainer_descendants_.emplace_back(
             descendant.node, static_position, descendant.inline_container,
-            /* needs_block_offset_adjustment */ false,
-            containing_block_offset, containing_block_fragment);
+            /* needs_block_offset_adjustment */ false, containing_block_offset,
+            containing_block_fragment);
       }
     }
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
index 3daed90..c19d6e3 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
@@ -157,6 +157,9 @@
     }
   }
 
+  LogicalSize adjusted_padding_box_size =
+      ShrinkLogicalSize(border_box_size_, borders_);
+
   NGBlockNode legend = Node().GetRenderedLegend();
   if (legend) {
     if (!IsResumingLayout(BreakToken()))
@@ -168,40 +171,35 @@
       minimum_border_box_block_size_ =
           intrinsic_block_size_ + padding_.BlockSum() + borders_.block_end;
     }
-  }
 
-  LogicalSize adjusted_padding_box_size =
-      ShrinkLogicalSize(border_box_size_, borders_);
+    if (adjusted_padding_box_size.block_size != kIndefiniteSize) {
+      DCHECK_NE(border_box_size_.block_size, kIndefiniteSize);
+      LayoutUnit legend_size_contribution;
+      if (IsResumingLayout(BreakToken())) {
+        // The legend has been laid out in previous fragments, and
+        // adjusted_padding_box_size will need to be adjusted further to account
+        // for block size taken up by the legend.
+        //
+        // To calculate its size contribution to the border block-start area,
+        // take the difference between the previously consumed block-size of the
+        // fieldset excluding its specified block-start border, and the consumed
+        // block-size of the contents wrapper.
+        LayoutUnit content_consumed_block_size =
+            content_break_token ? content_break_token->ConsumedBlockSize()
+                                : LayoutUnit();
+        legend_size_contribution = consumed_block_size_ - borders_.block_start -
+                                   content_consumed_block_size;
+      } else {
+        // We're at the first fragment. The current layout position
+        // (intrinsic_block_size_) is at the outer block-end edge of the legend
+        // or just after the block-start border, whichever is larger.
+        legend_size_contribution = intrinsic_block_size_ - borders_.block_start;
+      }
 
-  // If the legend has been laid out in previous fragments,
-  // adjusted_padding_box_size will need to be adjusted further to account for
-  // block size taken up by the legend.
-  if (adjusted_padding_box_size.block_size != kIndefiniteSize && legend) {
-    LayoutUnit content_consumed_block_size =
-        content_break_token ? content_break_token->ConsumedBlockSize()
-                            : LayoutUnit();
-
-    // Calculate the amount of the border block-start that was consumed in
-    // previous fragments.
-    LayoutUnit consumed_border_block_start =
-        borders_.block_start - intrinsic_block_size_;
-
-    // Calculate the amount of the border block-end that was consumed in
-    // previous fragments.
-    DCHECK_NE(border_box_size_.block_size, kIndefiniteSize);
-    LayoutUnit consumed_border_block_end =
-        std::max(consumed_block_size_ -
-                     (border_box_size_.block_size - borders_.block_end),
-                 LayoutUnit());
-
-    LayoutUnit legend_block_size =
-        consumed_block_size_ - content_consumed_block_size -
-        consumed_border_block_start - consumed_border_block_end;
-    DCHECK_GE(legend_block_size, LayoutUnit());
-
-    adjusted_padding_box_size.block_size =
-        std::max(padding_.BlockSum(),
-                 adjusted_padding_box_size.block_size - legend_block_size);
+      adjusted_padding_box_size.block_size = std::max(
+          adjusted_padding_box_size.block_size - legend_size_contribution,
+          padding_.BlockSum());
+    }
   }
 
   // Proceed with normal fieldset children (excluding the rendered legend). They
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
index b59601e..f6f8f550 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -244,7 +244,13 @@
   LayoutUnit fragments_total_block_size = builder->FragmentsTotalBlockSize();
   LayoutUnit desired_block_size =
       fragments_total_block_size - previously_consumed_block_size;
-  DCHECK_GE(desired_block_size, LayoutUnit());
+
+  // Consumed block-size stored in the break tokens is always stretched to the
+  // fragmentainers. If this wasn't also the case for all previous fragments
+  // (because we reached the end of the node and were overflowing), we may end
+  // up with negative values here.
+  desired_block_size = desired_block_size.ClampNegativeToZero();
+
   LayoutUnit intrinsic_block_size = builder->IntrinsicBlockSize();
 
   LayoutUnit final_block_size = desired_block_size;
@@ -318,8 +324,18 @@
     sides.block_end = false;
   builder->SetSidesToInclude(sides);
 
-  builder->SetConsumedBlockSize(previously_consumed_block_size +
-                                final_block_size);
+  LayoutUnit consumed_here = final_block_size;
+  if (builder->DidBreakSelf() || builder->HasChildBreakInside()) {
+    // If this node is to be resumed in the next fragmentainer, consumed
+    // block-size always includes the entire remainder of the fragmentainer. The
+    // frament itself will only do that unless we've reached the end of the node
+    // (and we are breaking because of overflow). We include the entire
+    // fragmentainer in consumed block-size in order to write offsets correctly
+    // back to legacy layout, which would otherwise become incorrect for
+    // overflowing content.
+    consumed_here = std::max(consumed_here, space_left);
+  }
+  builder->SetConsumedBlockSize(previously_consumed_block_size + consumed_here);
   builder->SetFragmentBlockSize(final_block_size);
 
   if (builder->FoundColumnSpanner())
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 518d2cc2..d48b156 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -310,6 +310,9 @@
     const ComputedStyle& style = containing_block->StyleRef();
     LogicalSize size = containing_block_fragment->Size().ConvertToLogical(
         style.GetWritingMode());
+    size.block_size =
+        LayoutBoxUtils::TotalBlockSize(*ToLayoutBox(containing_block));
+
     const NGPhysicalBoxFragment* fragment =
         To<NGPhysicalBoxFragment>(containing_block_fragment);
 
@@ -743,13 +746,16 @@
   bool should_be_considered_as_replaced = node.ShouldBeConsideredAsReplaced();
   bool absolute_needs_child_block_size =
       AbsoluteNeedsChildBlockSize(candidate_style);
+  base::Optional<MinMaxSizes> minmax_intrinsic_sizes_for_ar;
 
   // We also include items with aspect ratio here, because if the inline size
   // is auto and we have a definite block size, we want to use that for the
   // inline size calculation.
+  bool compute_inline_from_ar =
+      IsInlineSizeComputableFromBlockSize(candidate_style);
   if (AbsoluteNeedsChildInlineSize(candidate_style) ||
       NeedMinMaxSize(candidate_style) || should_be_considered_as_replaced ||
-      IsInlineSizeComputableFromBlockSize(candidate_style)) {
+      compute_inline_from_ar) {
     MinMaxSizesInput input(kIndefiniteSize, MinMaxSizesType::kContent);
     if (is_replaced) {
       input.percentage_resolution_block_size =
@@ -764,6 +770,15 @@
       has_computed_block_dimensions = true;
       input.percentage_resolution_block_size = node_dimensions.size.block_size;
     }
+    if (compute_inline_from_ar &&
+        candidate_style.OverflowInlineDirection() == EOverflow::kVisible) {
+      MinMaxSizesInput intrinsic_input(input);
+      intrinsic_input.type = MinMaxSizesType::kIntrinsic;
+      minmax_intrinsic_sizes_for_ar =
+          node.ComputeMinMaxSizes(candidate_writing_mode, intrinsic_input,
+                                  &candidate_constraint_space)
+              .sizes;
+    }
 
     min_max_sizes = node.ComputeMinMaxSizes(candidate_writing_mode, input,
                                             &candidate_constraint_space)
@@ -795,10 +810,11 @@
                     kIndefiniteSize};
   }
 
-  ComputeOutOfFlowInlineDimensions(
-      candidate_constraint_space, candidate_style, border_padding,
-      candidate_static_position, min_max_sizes, replaced_size,
-      default_writing_mode, container_direction, &node_dimensions);
+  ComputeOutOfFlowInlineDimensions(candidate_constraint_space, candidate_style,
+                                   border_padding, candidate_static_position,
+                                   min_max_sizes, minmax_intrinsic_sizes_for_ar,
+                                   replaced_size, default_writing_mode,
+                                   container_direction, &node_dimensions);
 
   // |should_be_considered_as_replaced| sets the inline-size.
   // It does not set the block-size. This is a compatibility quirk.
@@ -1185,8 +1201,9 @@
     column_size.block_size = column_size.block_size.ClampNegativeToZero();
   }
 
-  // TODO(layout-dev): Calculate correct percentage resolution size.
-  LogicalSize percentage_resolution_size = column_size;
+  LogicalSize percentage_resolution_size =
+      LogicalSize(column_size.inline_size,
+                  container_builder_->ChildAvailableSize().block_size);
 
   // TODO(bebeaudr): Need to handle different fragmentation types. It won't
   // always be multi-column.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
index c7213a840..5e70bb5d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
@@ -1138,5 +1138,114 @@
   EXPECT_EQ(expectation, dump);
 }
 
+// Fragmented OOF element with block-size percentage resolution.
+TEST_F(NGOutOfFlowLayoutPartTest, AbsposFragmentationPctResolution) {
+  SetBodyInnerHTML(
+      R"HTML(
+      <style>
+        #multicol {
+          column-count:2; column-fill:auto; column-gap:16px; height:40px;
+        }
+        .rel {
+          position: relative; width:30px;
+        }
+        .abs {
+          position:absolute; top:30px; width:5px; height:100%;
+        }
+        .spanner {
+          column-span:all; height:25%;
+        }
+      </style>
+      <div id="container">
+        <div id="multicol">
+          <div class="rel">
+            <div class="abs"></div>
+            <div style="width: 10px; height:30px;"></div>
+          </div>
+          <div class="spanner"></div>
+        </div>
+      </div>
+      )HTML");
+  String dump = DumpFragmentTree(GetElementById("container"));
+
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x40
+    offset:0,0 size:1000x40
+      offset:0,0 size:492x15
+        offset:0,0 size:30x15
+          offset:0,0 size:10x15
+      offset:508,0 size:492x15
+        offset:0,0 size:30x15
+          offset:0,0 size:10x15
+      offset:0,15 size:1000x10
+      offset:0,25 size:492x15
+        offset:0,0 size:5x15
+      offset:508,25 size:492x15
+        offset:0,0 size:5x15
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+// Fragmented OOF element with block-size percentage resolution and overflow.
+TEST_F(NGOutOfFlowLayoutPartTest,
+       AbsposFragmentationPctResolutionWithOverflow) {
+  SetBodyInnerHTML(
+      R"HTML(
+      <style>
+        #multicol {
+          columns:5; column-fill:auto; column-gap:0px; height:100px;
+        }
+        .rel {
+          position: relative; width:55px;
+        }
+        .abs {
+          position:absolute; top:0px; width:5px; height:100%;
+        }
+      </style>
+      <div id="container">
+        <div id="multicol">
+          <div style="height:30px;"></div>
+          <div class="rel">
+            <div class="abs"></div>
+            <div style="width:44px; height:200px;">
+              <div style="width:33px; height:400px;"></div>
+            </div>
+          </div>
+        </div>
+      </div>
+      )HTML");
+  String dump = DumpFragmentTree(GetElementById("container"));
+
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:1000x100
+      offset:0,0 size:200x100
+        offset:0,0 size:200x30
+        offset:0,30 size:55x70
+          offset:0,0 size:44x70
+            offset:0,0 size:33x70
+        offset:0,30 size:5x70
+      offset:200,0 size:200x100
+        offset:0,0 size:55x100
+          offset:0,0 size:44x100
+            offset:0,0 size:33x100
+        offset:0,0 size:5x100
+      offset:400,0 size:200x100
+        offset:0,0 size:55x30
+          offset:0,0 size:44x30
+            offset:0,0 size:33x100
+        offset:0,0 size:5x30
+      offset:600,0 size:200x100
+        offset:0,0 size:55x0
+          offset:0,0 size:44x0
+            offset:0,0 size:33x100
+      offset:800,0 size:200x100
+        offset:0,0 size:55x0
+          offset:0,0 size:44x0
+            offset:0,0 size:33x30
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
 }  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_image.h b/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
index 23b1b601..ed0bca5 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
@@ -69,6 +69,11 @@
            LayoutSVGModelObject::IsOfType(type);
   }
 
+  AffineTransform LocalSVGTransform() const override {
+    NOT_DESTROYED();
+    return local_transform_;
+  }
+
   const char* GetName() const override {
     NOT_DESTROYED();
     return "LayoutSVGImage";
@@ -96,11 +101,6 @@
                    const PhysicalOffset& accumulated_offset,
                    HitTestAction) override;
 
-  AffineTransform LocalSVGTransform() const override {
-    NOT_DESTROYED();
-    return local_transform_;
-  }
-
   FloatSize CalculateObjectSize() const;
   bool HasOverriddenIntrinsicSize() const;
 
diff --git a/third_party/blink/renderer/core/paint/svg_container_painter.cc b/third_party/blink/renderer/core/paint/svg_container_painter.cc
index 0c0d457..0ec0ecda 100644
--- a/third_party/blink/renderer/core/paint/svg_container_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_container_painter.cc
@@ -28,6 +28,15 @@
 
 }  // namespace
 
+bool SVGContainerPainter::CanUseCullRect() const {
+  // LayoutSVGHiddenContainer's visual rect is always empty but we need to
+  // paint its descendants so we cannot skip painting.
+  if (layout_svg_container_.IsSVGHiddenContainer())
+    return false;
+  return SVGModelObjectPainter::CanUseCullRect(
+      layout_svg_container_.StyleRef());
+}
+
 void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
   // Spec: An empty viewBox on the <svg> element disables rendering.
   DCHECK(layout_svg_container_.GetElement());
@@ -36,20 +45,20 @@
   if (svg_svg_element && svg_svg_element->HasEmptyViewBox())
     return;
 
-  if (SVGModelObjectPainter(layout_svg_container_)
-          .CullRectSkipsPainting(paint_info)) {
-    return;
-  }
-
   const auto* properties =
       layout_svg_container_.FirstFragment().PaintProperties();
   PaintInfo paint_info_before_filtering(paint_info);
-  if (SVGModelObjectPainter::ShouldUseInfiniteCullRect(
-          layout_svg_container_.StyleRef())) {
+  if (CanUseCullRect()) {
+    if (!paint_info.GetCullRect().IntersectsTransformed(
+            layout_svg_container_.LocalToSVGParentTransform(),
+            layout_svg_container_.VisualRectInLocalSVGCoordinates()))
+      return;
+    if (properties) {
+      if (const auto* transform = properties->Transform())
+        paint_info_before_filtering.TransformCullRect(*transform);
+    }
+  } else {
     paint_info_before_filtering.ApplyInfiniteCullRect();
-  } else if (properties) {
-    if (const auto* transform = properties->Transform())
-      paint_info_before_filtering.TransformCullRect(*transform);
   }
 
   ScopedSVGTransformState transform_state(
diff --git a/third_party/blink/renderer/core/paint/svg_container_painter.h b/third_party/blink/renderer/core/paint/svg_container_painter.h
index 9c13032a..4c26d62a 100644
--- a/third_party/blink/renderer/core/paint/svg_container_painter.h
+++ b/third_party/blink/renderer/core/paint/svg_container_painter.h
@@ -22,6 +22,8 @@
   void Paint(const PaintInfo&);
 
  private:
+  bool CanUseCullRect() const;
+
   const LayoutSVGContainer& layout_svg_container_;
 };
 
diff --git a/third_party/blink/renderer/core/paint/svg_image_painter.cc b/third_party/blink/renderer/core/paint/svg_image_painter.cc
index 1f6d0d2f..8c6726a 100644
--- a/third_party/blink/renderer/core/paint/svg_image_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_image_painter.cc
@@ -31,15 +31,16 @@
       !layout_svg_image_.ImageResource()->HasImage())
     return;
 
-  if (SVGModelObjectPainter(layout_svg_image_)
-          .CullRectSkipsPainting(paint_info)) {
-    return;
+  if (SVGModelObjectPainter::CanUseCullRect(layout_svg_image_.StyleRef())) {
+    if (!paint_info.GetCullRect().IntersectsTransformed(
+            layout_svg_image_.LocalSVGTransform(),
+            layout_svg_image_.VisualRectInLocalSVGCoordinates()))
+      return;
   }
   // Images cannot have children so do not call TransformCullRect.
 
   ScopedSVGTransformState transform_state(
-      paint_info, layout_svg_image_,
-      layout_svg_image_.LocalToSVGParentTransform());
+      paint_info, layout_svg_image_, layout_svg_image_.LocalSVGTransform());
   {
     ScopedSVGPaintState paint_state(layout_svg_image_, paint_info);
     if (paint_state.ApplyEffects() &&
diff --git a/third_party/blink/renderer/core/paint/svg_model_object_painter.cc b/third_party/blink/renderer/core/paint/svg_model_object_painter.cc
index dbe2a07..681754a 100644
--- a/third_party/blink/renderer/core/paint/svg_model_object_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_model_object_painter.cc
@@ -11,33 +11,18 @@
 
 namespace blink {
 
-bool SVGModelObjectPainter::ShouldUseInfiniteCullRect(
-    const ComputedStyle& style) {
+bool SVGModelObjectPainter::CanUseCullRect(const ComputedStyle& style) {
   // We do not apply cull rect optimizations across transforms for two reasons:
   //   1) Performance: We can optimize transform changes by not repainting.
   //   2) Complexity: Difficulty updating clips when ancestor transforms change.
   // For these reasons, we do not cull painting if there is a transform.
   if (style.HasTransform())
-    return true;
+    return false;
   // If the filter "moves pixels" we may require input from outside the cull
   // rect.
   if (style.HasFilter() && style.Filter().HasFilterThatMovesPixels())
-    return true;
-  return false;
-}
-
-bool SVGModelObjectPainter::CullRectSkipsPainting(const PaintInfo& paint_info) {
-  if (ShouldUseInfiniteCullRect(layout_svg_model_object_.StyleRef()))
     return false;
-
-  // LayoutSVGHiddenContainer's visual rect is always empty but we need to
-  // paint its descendants so we cannot skip painting.
-  if (layout_svg_model_object_.IsSVGHiddenContainer())
-    return false;
-
-  return !paint_info.GetCullRect().IntersectsTransformed(
-      layout_svg_model_object_.LocalToSVGParentTransform(),
-      layout_svg_model_object_.VisualRectInLocalSVGCoordinates());
+  return true;
 }
 
 void SVGModelObjectPainter::RecordHitTestData(const LayoutObject& svg_object,
diff --git a/third_party/blink/renderer/core/paint/svg_model_object_painter.h b/third_party/blink/renderer/core/paint/svg_model_object_painter.h
index 3157b1a..7b3fd23c 100644
--- a/third_party/blink/renderer/core/paint/svg_model_object_painter.h
+++ b/third_party/blink/renderer/core/paint/svg_model_object_painter.h
@@ -29,12 +29,7 @@
 
   // Should we use an infinite cull rect when painting an object with the
   // specified style.
-  static bool ShouldUseInfiniteCullRect(const ComputedStyle&);
-
-  // If the object is outside the cull rect, painting can be skipped in most
-  // cases. An important exception is when there is a transform style: see the
-  // comment in the implementation.
-  bool CullRectSkipsPainting(const PaintInfo&);
+  static bool CanUseCullRect(const ComputedStyle&);
 
   void PaintOutline(const PaintInfo&);
 
diff --git a/third_party/blink/renderer/core/paint/svg_shape_painter.cc b/third_party/blink/renderer/core/paint/svg_shape_painter.cc
index cd517c0..533ecd27 100644
--- a/third_party/blink/renderer/core/paint/svg_shape_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_shape_painter.cc
@@ -47,9 +47,11 @@
       layout_svg_shape_.IsShapeEmpty())
     return;
 
-  if (SVGModelObjectPainter(layout_svg_shape_)
-          .CullRectSkipsPainting(paint_info)) {
-    return;
+  if (SVGModelObjectPainter::CanUseCullRect(layout_svg_shape_.StyleRef())) {
+    if (!paint_info.GetCullRect().IntersectsTransformed(
+            layout_svg_shape_.LocalSVGTransform(),
+            layout_svg_shape_.VisualRectInLocalSVGCoordinates()))
+      return;
   }
   // Shapes cannot have children so do not call TransformCullRect.
 
diff --git a/third_party/blink/renderer/core/paint/text_control_single_line_painter.cc b/third_party/blink/renderer/core/paint/text_control_single_line_painter.cc
index a49d62e..350d7733 100644
--- a/third_party/blink/renderer/core/paint/text_control_single_line_painter.cc
+++ b/third_party/blink/renderer/core/paint/text_control_single_line_painter.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/paint/text_control_single_line_painter.h"
 
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/layout/layout_text_control_single_line.h"
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
 #include "third_party/blink/renderer/core/paint/block_painter.h"
@@ -18,7 +19,8 @@
   BlockPainter(text_control_).Paint(paint_info);
 
   if (!ShouldPaintSelfBlockBackground(paint_info.phase) ||
-      !text_control_.ShouldDrawCapsLockIndicator())
+      !To<HTMLInputElement>(text_control_.GetNode())
+           ->ShouldDrawCapsLockIndicator())
     return;
 
   if (DrawingRecorder::UseCachedDrawingIfPossible(
diff --git a/third_party/blink/renderer/core/script/classic_script.cc b/third_party/blink/renderer/core/script/classic_script.cc
index fd4014b..eaefbcb2 100644
--- a/third_party/blink/renderer/core/script/classic_script.cc
+++ b/third_party/blink/renderer/core/script/classic_script.cc
@@ -57,11 +57,11 @@
   DCHECK(global_scope.IsContextThread());
 
   ScriptState::Scope scope(global_scope.ScriptController()->GetScriptState());
-  ClassicEvaluationResult result =
+  ScriptEvaluationResult result =
       global_scope.ScriptController()->EvaluateAndReturnValue(
           GetScriptSourceCode(), sanitize_script_errors_,
           global_scope.GetV8CacheOptions());
-  return !result.IsEmpty();
+  return result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess;
 }
 
 std::pair<size_t, size_t> ClassicScript::GetClassicScriptSizes() const {
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
index 8e45173..8340bf7 100644
--- a/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
+++ b/third_party/blink/renderer/core/script/dynamic_module_resolver.cc
@@ -153,85 +153,94 @@
 
   // <spec step="7">Run the module script result, with the rethrow errors
   // boolean set to true.</spec>
-  ModuleEvaluationResult result = modulator_->ExecuteModule(
+  ScriptEvaluationResult result = modulator_->ExecuteModule(
       module_script, Modulator::CaptureEvalErrorFlag::kCapture);
 
-  // <spec step="8">If running the module script throws an exception, ...</spec>
-  if (result.IsException()) {
-    // <spec step="8">... then perform
-    // FinishDynamicImport(referencingScriptOrModule, specifier,
-    // promiseCapability, the thrown exception completion).</spec>
-    //
-    // Note: "the thrown exception completion" is |error|.
-    //
-    // <spec
-    // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
-    // step="1">If completion is an abrupt completion, then perform !
-    // Call(promiseCapability.[[Reject]], undefined, « completion.[[Value]]
-    // »).</spec>
-    promise_resolver_->Reject(result.GetException());
-    return;
+  switch (result.GetResultType()) {
+    case ScriptEvaluationResult::ResultType::kException:
+      // <spec step="8">If running the module script throws an exception,
+      // ...</spec> <spec step="8">... then perform
+      // FinishDynamicImport(referencingScriptOrModule, specifier,
+      // promiseCapability, the thrown exception completion).</spec>
+      //
+      // Note: "the thrown exception completion" is |error|.
+      //
+      // <spec
+      // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
+      // step="1">If completion is an abrupt completion, then perform !
+      // Call(promiseCapability.[[Reject]], undefined, « completion.[[Value]]
+      // »).</spec>
+      promise_resolver_->Reject(result.GetExceptionForModule());
+      break;
+
+    case ScriptEvaluationResult::ResultType::kNotRun:
+    case ScriptEvaluationResult::ResultType::kAborted:
+      // Do nothing when script is disabled or after a script is aborted.
+      break;
+
+    case ScriptEvaluationResult::ResultType::kSuccess: {
+      // <spec step="9">Otherwise, perform
+      // FinishDynamicImport(referencingScriptOrModule, specifier,
+      // promiseCapability, NormalCompletion(undefined)).</spec>
+      //
+      // <spec
+      // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
+      // step="2.1">Assert: completion is a normal completion and
+      // completion.[[Value]] is undefined.</spec>
+
+      if (base::FeatureList::IsEnabled(features::kTopLevelAwait)) {
+        ScriptPromise promise = result.GetPromise(script_state);
+        v8::Local<v8::Function> callback_success =
+            ModuleResolutionSuccessCallback::CreateFunction(
+                script_state, promise_resolver_, module_script);
+        v8::Local<v8::Function> callback_failure =
+            ModuleResolutionFailureCallback::CreateFunction(script_state,
+                                                            promise_resolver_);
+        promise.Then(callback_success, callback_failure);
+        return;
+      }
+
+      // <spec
+      // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
+      // step="2.2">Let moduleRecord be !
+      // HostResolveImportedModule(referencingScriptOrModule, specifier).</spec>
+      //
+      // Note: We skip invocation of ModuleRecordResolver here. The
+      // result of HostResolveImportedModule is guaranteed to be
+      // |module_script|.
+      v8::Local<v8::Module> record = module_script->V8Module();
+      DCHECK(!record.IsEmpty());
+
+      // <spec
+      // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
+      // step="2.3">Assert: Evaluate has already been invoked on moduleRecord
+      // and successfully completed.</spec>
+      //
+      // Because |error| is empty, we are sure that ExecuteModule() above was
+      // successfully completed.
+
+      // <spec
+      // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
+      // step="2.4">Let namespace be GetModuleNamespace(moduleRecord).</spec>
+      v8::Local<v8::Value> module_namespace = ModuleRecord::V8Namespace(record);
+
+      // <spec
+      // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
+      // step="2.5">If namespace is an abrupt completion, perform !
+      // Call(promiseCapability.[[Reject]], undefined, « namespace.[[Value]]
+      // »).</spec>
+      //
+      // Note: Blink's implementation never allows |module_namespace| to be
+      // an abrupt completion.
+
+      // <spec
+      // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
+      // step="2.6">Otherwise, perform ! Call(promiseCapability.[[Resolve]],
+      // undefined, « namespace.[[Value]] »).</spec>
+      promise_resolver_->Resolve(module_namespace);
+      break;
+    }
   }
-
-  // <spec step="9">Otherwise, perform
-  // FinishDynamicImport(referencingScriptOrModule, specifier,
-  // promiseCapability, NormalCompletion(undefined)).</spec>
-  //
-  // <spec
-  // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
-  // step="2.1">Assert: completion is a normal completion and
-  // completion.[[Value]] is undefined.</spec>
-  DCHECK(result.IsSuccess());
-
-  if (base::FeatureList::IsEnabled(features::kTopLevelAwait)) {
-    ScriptPromise promise = result.GetPromise(script_state);
-    v8::Local<v8::Function> callback_success =
-        ModuleResolutionSuccessCallback::CreateFunction(
-            script_state, promise_resolver_, module_script);
-    v8::Local<v8::Function> callback_failure =
-        ModuleResolutionFailureCallback::CreateFunction(script_state,
-                                                        promise_resolver_);
-    promise.Then(callback_success, callback_failure);
-    return;
-  }
-
-  // <spec
-  // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
-  // step="2.2">Let moduleRecord be !
-  // HostResolveImportedModule(referencingScriptOrModule, specifier).</spec>
-  //
-  // Note: We skip invocation of ModuleRecordResolver here. The
-  // result of HostResolveImportedModule is guaranteed to be |module_script|.
-  v8::Local<v8::Module> record = module_script->V8Module();
-  DCHECK(!record.IsEmpty());
-
-  // <spec
-  // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
-  // step="2.3">Assert: Evaluate has already been invoked on moduleRecord and
-  // successfully completed.</spec>
-  //
-  // Because |error| is empty, we are sure that ExecuteModule() above was
-  // successfully completed.
-
-  // <spec
-  // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
-  // step="2.4">Let namespace be GetModuleNamespace(moduleRecord).</spec>
-  v8::Local<v8::Value> module_namespace = ModuleRecord::V8Namespace(record);
-
-  // <spec
-  // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
-  // step="2.5">If namespace is an abrupt completion, perform !
-  // Call(promiseCapability.[[Reject]], undefined, « namespace.[[Value]]
-  // »).</spec>
-  //
-  // Note: Blink's implementation never allows |module_namespace| to be
-  // an abrupt completion.
-
-  // <spec
-  // href="https://tc39.github.io/proposal-dynamic-import/#sec-finishdynamicimport"
-  // step="2.6">Otherwise, perform ! Call(promiseCapability.[[Resolve]],
-  // undefined, « namespace.[[Value]] »).</spec>
-  promise_resolver_->Resolve(module_namespace);
 }
 
 void DynamicImportTreeClient::Trace(Visitor* visitor) const {
diff --git a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
index 727bbf4c..dc1e4ba 100644
--- a/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
+++ b/third_party/blink/renderer/core/script/dynamic_module_resolver_test.cc
@@ -91,13 +91,13 @@
     fetch_tree_was_called_ = true;
   }
 
-  ModuleEvaluationResult ExecuteModule(
+  ScriptEvaluationResult ExecuteModule(
       ModuleScript* module_script,
       CaptureEvalErrorFlag capture_error) final {
     EXPECT_EQ(CaptureEvalErrorFlag::kCapture, capture_error);
 
     ScriptState::EscapableScope scope(script_state_);
-    ModuleEvaluationResult result = ModuleRecord::Evaluate(
+    ScriptEvaluationResult result = ModuleRecord::Evaluate(
         script_state_, module_script->V8Module(), module_script->SourceURL());
     return result.Escape(&scope);
   }
diff --git a/third_party/blink/renderer/core/script/modulator.h b/third_party/blink/renderer/core/script/modulator.h
index af13a118..b6387d8 100644
--- a/third_party/blink/renderer/core/script/modulator.h
+++ b/third_party/blink/renderer/core/script/modulator.h
@@ -201,14 +201,14 @@
   // CaptureEvalErrorFlag is used to implement "rethrow errors" parameter in
   // run-a-module-script.
   // - When "rethrow errors" is to be set, use kCapture for EvaluateModule().
-  // Then EvaluateModule() wraps exceptions in a ModuleEvaluationResult instead
+  // Then EvaluateModule() wraps exceptions in a ScriptEvaluationResult instead
   // of throwing it and the caller should rethrow the exception.
   // - When "rethrow errors" is not to be set, use kReport. If there is an error
   // to throw, EvaluateModule() "report the error" inside it, and returns
-  // ModuleEvaluationResult wrapping the error. Otherwise, it returns either a
-  // ModuleEvaluationResult that is empty or contains the successful evaluation
+  // ScriptEvaluationResult wrapping the error. Otherwise, it returns either a
+  // ScriptEvaluationResult that is empty or contains the successful evaluation
   // result.
-  virtual ModuleEvaluationResult ExecuteModule(ModuleScript*,
+  virtual ScriptEvaluationResult ExecuteModule(ModuleScript*,
                                                CaptureEvalErrorFlag) = 0;
 
   virtual ModuleScriptFetcher* CreateModuleScriptFetcher(
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.cc b/third_party/blink/renderer/core/script/modulator_impl_base.cc
index 15bc5d0..4cc48c7 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.cc
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.cc
@@ -337,7 +337,7 @@
 
 // <specdef href="https://html.spec.whatwg.org/C/#run-a-module-script">
 // Spec with TLA: https://github.com/whatwg/html/pull/4352
-ModuleEvaluationResult ModulatorImplBase::ExecuteModule(
+ScriptEvaluationResult ModulatorImplBase::ExecuteModule(
     ModuleScript* module_script,
     CaptureEvalErrorFlag capture_error) {
   // <spec step="1">If rethrow errors is not given, let it be false.</spec>
@@ -348,8 +348,9 @@
 
   // <spec step="3">Check if we can run script with settings. If this returns
   // "do not run" then return NormalCompletion(empty).</spec>
-  if (IsScriptingDisabled())
-    return ModuleEvaluationResult::Empty();
+  if (IsScriptingDisabled()) {
+    return ScriptEvaluationResult::FromModuleNotRun();
+  }
 
   // <spec step="4">Prepare to run script given settings.</spec>
   //
@@ -361,7 +362,7 @@
   ScriptState::EscapableScope scope(script_state_);
 
   // Without TLA: <spec step="5">Let evaluationStatus be null.</spec>
-  ModuleEvaluationResult result = ModuleEvaluationResult::Empty();
+  ScriptEvaluationResult result = ScriptEvaluationResult::FromModuleNotRun();
 
   // <spec step="6">If script's error to rethrow is not null, ...</spec>
   if (module_script->HasErrorToRethrow()) {
@@ -371,7 +372,7 @@
     // With TLA:    <spec step="5">If script's error to rethrow is not null,
     //     then let valuationPromise be a promise rejected with script's error
     //     to rethrow.</spec>
-    result = ModuleEvaluationResult::FromException(
+    result = ScriptEvaluationResult::FromModuleException(
         module_script->CreateErrorToRethrow().V8Value());
   } else {
     // <spec step="7">Otherwise:</spec>
@@ -390,7 +391,8 @@
     // DOMException, [[Target]]: empty }.</spec>
 
     // [not specced] Store V8 code cache on successful evaluation.
-    if (result.IsSuccess()) {
+    if (result.GetResultType() ==
+        ScriptEvaluationResult::ResultType::kSuccess) {
       TaskRunner()->PostTask(
           FROM_HERE,
           WTF::Bind(&ModulatorImplBase::ProduceCacheModuleTreeTopLevel,
@@ -398,27 +400,26 @@
     }
   }
 
-  if (base::FeatureList::IsEnabled(features::kTopLevelAwait)) {
-    if (capture_error == CaptureEvalErrorFlag::kReport) {
+  if (capture_error == CaptureEvalErrorFlag::kReport) {
+    if (base::FeatureList::IsEnabled(features::kTopLevelAwait)) {
       // <spec step="7"> If report errors is true, then upon rejection of
       // evaluationPromise with reason, report the exception given by reason
       // for script.</spec>
       v8::Local<v8::Function> callback_failure =
           ModuleEvaluationRejectionCallback::CreateFunction(script_state_);
-      // Add a rejection handler to report back errors once the result promise
-      // is rejected.
+      // Add a rejection handler to report back errors once the result
+      // promise is rejected.
       result.GetPromise(script_state_)
           .Then(v8::Local<v8::Function>(), callback_failure);
-    }
-  } else {
-    // <spec step="8">If evaluationStatus is an abrupt completion, then:</spec>
-    if (result.IsException()) {
-      // <spec step="8.1">If rethrow errors is true, rethrow the exception given
-      // by evaluationStatus.[[Value]].</spec>
-      if (capture_error == CaptureEvalErrorFlag::kReport) {
+    } else {
+      // <spec step="8">If evaluationStatus is an abrupt completion,
+      // then:</spec>
+      if (result.GetResultType() ==
+          ScriptEvaluationResult::ResultType::kException) {
         // <spec step="8.2">Otherwise, report the exception given by
         // evaluationStatus.[[Value]] for script.</spec>
-        ModuleRecord::ReportException(script_state_, result.GetException());
+        ModuleRecord::ReportException(script_state_,
+                                      result.GetExceptionForModule());
       }
     }
   }
diff --git a/third_party/blink/renderer/core/script/modulator_impl_base.h b/third_party/blink/renderer/core/script/modulator_impl_base.h
index 03f875ba..6b03d3f5 100644
--- a/third_party/blink/renderer/core/script/modulator_impl_base.h
+++ b/third_party/blink/renderer/core/script/modulator_impl_base.h
@@ -89,7 +89,7 @@
   ScriptValue InstantiateModule(v8::Local<v8::Module>, const KURL&) override;
   Vector<ModuleRequest> ModuleRequestsFromModuleRecord(
       v8::Local<v8::Module>) override;
-  ModuleEvaluationResult ExecuteModule(ModuleScript*,
+  ScriptEvaluationResult ExecuteModule(ModuleScript*,
                                        CaptureEvalErrorFlag) override;
 
   // Populates |reason| and returns true if the dynamic import is disallowed on
diff --git a/third_party/blink/renderer/core/script/module_script.cc b/third_party/blink/renderer/core/script/module_script.cc
index bb775ea..7970c77 100644
--- a/third_party/blink/renderer/core/script/module_script.cc
+++ b/third_party/blink/renderer/core/script/module_script.cc
@@ -101,7 +101,7 @@
 }
 
 void ModuleScript::RunScript(LocalFrame* frame) {
-  // We need a HandleScope for the ModuleEvaluationResult that is created
+  // We need a HandleScope for the ScriptEvaluationResult that is created
   // in ::ExecuteModule(...).
   ScriptState::Scope scope(SettingsObject()->GetScriptState());
   DVLOG(1) << *this << "::RunScript()";
@@ -112,7 +112,7 @@
 
 bool ModuleScript::RunScriptOnWorkerOrWorklet(
     WorkerOrWorkletGlobalScope& global_scope) {
-  // We need a HandleScope for the ModuleEvaluationResult that is created
+  // We need a HandleScope for the ScriptEvaluationResult that is created
   // in ::ExecuteModule(...).
   ScriptState::Scope scope(SettingsObject()->GetScriptState());
   DCHECK(global_scope.IsContextThread());
@@ -120,9 +120,10 @@
   // This |error| is always null because the second argument is |kReport|.
   // TODO(nhiroki): Catch an error when an evaluation error happens.
   // (https://crbug.com/680046)
-  ModuleEvaluationResult result = SettingsObject()->ExecuteModule(
+  ScriptEvaluationResult result = SettingsObject()->ExecuteModule(
       this, Modulator::CaptureEvalErrorFlag::kReport);
-  return result.IsSuccess();
+
+  return result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess;
 }
 
 std::pair<size_t, size_t> ModuleScript::GetClassicScriptSizes() const {
diff --git a/third_party/blink/renderer/core/script/module_script_test.cc b/third_party/blink/renderer/core/script/module_script_test.cc
index eb25d05..c1773ac6 100644
--- a/third_party/blink/renderer/core/script/module_script_test.cc
+++ b/third_party/blink/renderer/core/script/module_script_test.cc
@@ -167,10 +167,11 @@
                                           module_script->V8Module(),
                                           module_script->SourceURL())
                     .IsEmpty());
-    ASSERT_TRUE(ModuleRecord::Evaluate(scope.GetScriptState(),
-                                       module_script->V8Module(),
-                                       module_script->SourceURL())
-                    .IsSuccess());
+    ASSERT_EQ(ModuleRecord::Evaluate(scope.GetScriptState(),
+                                     module_script->V8Module(),
+                                     module_script->SourceURL())
+                  .GetResultType(),
+              ScriptEvaluationResult::ResultType::kSuccess);
     TestFoo(scope);
 
     Checkpoint checkpoint;
@@ -293,10 +294,11 @@
                                           module_script->V8Module(),
                                           module_script->SourceURL())
                     .IsEmpty());
-    ASSERT_TRUE(ModuleRecord::Evaluate(scope.GetScriptState(),
-                                       module_script->V8Module(),
-                                       module_script->SourceURL())
-                    .IsSuccess());
+    ASSERT_EQ(ModuleRecord::Evaluate(scope.GetScriptState(),
+                                     module_script->V8Module(),
+                                     module_script->SourceURL())
+                  .GetResultType(),
+              ScriptEvaluationResult::ResultType::kSuccess);
     TestFoo(scope);
 
     Checkpoint checkpoint;
diff --git a/third_party/blink/renderer/core/testing/dummy_modulator.cc b/third_party/blink/renderer/core/testing/dummy_modulator.cc
index a32dd5da..cf3218f 100644
--- a/third_party/blink/renderer/core/testing/dummy_modulator.cc
+++ b/third_party/blink/renderer/core/testing/dummy_modulator.cc
@@ -169,10 +169,10 @@
   return Vector<ModuleRequest>();
 }
 
-ModuleEvaluationResult DummyModulator::ExecuteModule(ModuleScript*,
+ScriptEvaluationResult DummyModulator::ExecuteModule(ModuleScript*,
                                                      CaptureEvalErrorFlag) {
   NOTREACHED();
-  return ModuleEvaluationResult::Empty();
+  return ScriptEvaluationResult::FromModuleNotRun();
 }
 
 ModuleScriptFetcher* DummyModulator::CreateModuleScriptFetcher(
diff --git a/third_party/blink/renderer/core/testing/dummy_modulator.h b/third_party/blink/renderer/core/testing/dummy_modulator.h
index b461b49..26f54cd 100644
--- a/third_party/blink/renderer/core/testing/dummy_modulator.h
+++ b/third_party/blink/renderer/core/testing/dummy_modulator.h
@@ -75,7 +75,7 @@
   ScriptValue InstantiateModule(v8::Local<v8::Module>, const KURL&) override;
   Vector<ModuleRequest> ModuleRequestsFromModuleRecord(
       v8::Local<v8::Module>) override;
-  ModuleEvaluationResult ExecuteModule(ModuleScript*,
+  ScriptEvaluationResult ExecuteModule(ModuleScript*,
                                        CaptureEvalErrorFlag) override;
   ModuleScriptFetcher* CreateModuleScriptFetcher(
       ModuleScriptCustomFetchType,
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc
index c1e4291..ba9586b 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -330,7 +330,7 @@
     ReportingProxy().WillEvaluateImportedClassicScript(
         source_code.length(), handler ? handler->GetCodeCacheSize() : 0);
     ScriptState::Scope scope(ScriptController()->GetScriptState());
-    ClassicEvaluationResult result = ScriptController()->EvaluateAndReturnValue(
+    ScriptEvaluationResult result = ScriptController()->EvaluateAndReturnValue(
         ScriptSourceCode(source_code, ScriptSourceLocationType::kUnknown,
                          handler,
                          ScriptSourceCode::UsePostRedirectURL() ? response_url
@@ -342,7 +342,7 @@
     // Step 5.2: "If an exception was thrown or if the script was prematurely
     // aborted, then abort all these steps, letting the exception or aborting
     // continue to be processed by the calling script."
-    if (result.IsEmpty())
+    if (result.GetResultType() != ScriptEvaluationResult::ResultType::kSuccess)
       return;
   }
 }
diff --git a/third_party/blink/renderer/core/workers/worklet_module_tree_client.cc b/third_party/blink/renderer/core/workers/worklet_module_tree_client.cc
index f0a1614..f8f4090 100644
--- a/third_party/blink/renderer/core/workers/worklet_module_tree_client.cc
+++ b/third_party/blink/renderer/core/workers/worklet_module_tree_client.cc
@@ -70,7 +70,7 @@
   }
 
   // Step 5: "Run a module script given script."
-  ModuleEvaluationResult result =
+  ScriptEvaluationResult result =
       Modulator::From(script_state_)
           ->ExecuteModule(module_script,
                           Modulator::CaptureEvalErrorFlag::kReport);
@@ -78,7 +78,8 @@
   auto* global_scope =
       To<WorkletGlobalScope>(ExecutionContext::From(script_state_));
 
-  global_scope->ReportingProxy().DidEvaluateTopLevelScript(result.IsSuccess());
+  global_scope->ReportingProxy().DidEvaluateTopLevelScript(
+      result.GetResultType() == ScriptEvaluationResult::ResultType::kSuccess);
 
   // Step 6: "Queue a task on outsideSettings's responsible event loop to run
   // these steps:"
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
index b1be9f9..3ef1a12 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
@@ -157,11 +157,12 @@
     DCHECK(isolate);
     ScriptState::Scope scope(script_state);
 
-    ClassicEvaluationResult result =
+    ScriptEvaluationResult result =
         global_scope->ScriptController()->EvaluateAndReturnValue(
             ScriptSourceCode(script), SanitizeScriptErrors::kSanitize);
-    DCHECK(!result.IsEmpty());
-    return ToBoolean(isolate, result.GetValue(), ASSERT_NO_EXCEPTION);
+    DCHECK_EQ(result.GetResultType(),
+              ScriptEvaluationResult::ResultType::kSuccess);
+    return ToBoolean(isolate, result.GetSuccessValue(), ASSERT_NO_EXCEPTION);
   }
 
   void RunConstructAndAnimateTestOnWorklet(
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
index ea3c51fe..602abb7 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_local_frame_client.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h"
 #include "third_party/blink/renderer/modules/webrtc/webrtc_audio_device_impl.h"
 #include "third_party/blink/renderer/platform/mediastream/media_constraints.h"
@@ -56,6 +57,7 @@
 #include "third_party/webrtc/media/engine/webrtc_media_engine.h"
 #include "third_party/webrtc/modules/audio_processing/include/audio_processing.h"
 #include "third_party/webrtc/modules/video_coding/codecs/h264/include/h264.h"
+#include "third_party/webrtc/rtc_base/openssl_stream_adapter.h"
 #include "third_party/webrtc/rtc_base/ref_counted_object.h"
 #include "third_party/webrtc/rtc_base/ssl_adapter.h"
 #include "third_party/webrtc_overrides/task_queue_factory.h"
@@ -349,6 +351,8 @@
   if (!GetPcFactory().get())
     return nullptr;
 
+  rtc::SetAllowLegacyTLSProtocols(
+      web_frame->Client()->AllowRTCLegacyTLSProtocols());
   webrtc::PeerConnectionDependencies dependencies(observer);
   dependencies.allocator = CreatePortAllocator(web_frame);
   dependencies.async_resolver_factory = CreateAsyncResolverFactory();
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
index 463db2d..d37ab20c 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
@@ -148,9 +148,10 @@
         ModuleRecord::Instantiate(script_state, module, js_url);
     EXPECT_TRUE(exception.IsEmpty());
 
-    ModuleEvaluationResult result =
+    ScriptEvaluationResult result =
         ModuleRecord::Evaluate(script_state, module, js_url);
-    return result.IsSuccess();
+    return result.GetResultType() ==
+           ScriptEvaluationResult::ResultType::kSuccess;
   }
 
   // Test if AudioWorkletGlobalScope and V8 components (ScriptState, Isolate)
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
index fe18563..0a1daa3 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
@@ -120,9 +120,10 @@
     ScriptValue exception =
         ModuleRecord::Instantiate(script_state, module, js_url);
     EXPECT_TRUE(exception.IsEmpty());
-    ModuleEvaluationResult result =
+    ScriptEvaluationResult result =
         ModuleRecord::Evaluate(script_state, module, js_url);
-    EXPECT_TRUE(result.IsSuccess());
+    EXPECT_EQ(result.GetResultType(),
+              ScriptEvaluationResult::ResultType::kSuccess);
     wait_event->Signal();
   }
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
index 36f0827c..3d590aa00 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
@@ -291,6 +291,16 @@
       resolver->Reject(MakeGarbageCollected<DOMException>(
           DOMExceptionCode::kOperationError, "Device is lost"));
       break;
+    case WGPUBufferMapAsyncStatus_DestroyedBeforeCallback:
+      resolver->Reject(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kOperationError,
+          "Buffer is destroyed before the mapping is resolved"));
+      break;
+    case WGPUBufferMapAsyncStatus_UnmappedBeforeCallback:
+      resolver->Reject(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kOperationError,
+          "Buffer is unmapped before the mapping is resolved"));
+      break;
     default:
       NOTREACHED();
   }
diff --git a/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc b/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc
index 658dd80c..e4bfb7de 100644
--- a/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc
+++ b/third_party/blink/renderer/modules/worklet/animation_and_paint_worklet_thread_test.cc
@@ -81,8 +81,9 @@
     ScriptValue exception =
         ModuleRecord::Instantiate(script_state, module, js_url);
     EXPECT_TRUE(exception.IsEmpty());
-    EXPECT_TRUE(
-        ModuleRecord::Evaluate(script_state, module, js_url).IsSuccess());
+    EXPECT_EQ(
+        ModuleRecord::Evaluate(script_state, module, js_url).GetResultType(),
+        ScriptEvaluationResult::ResultType::kSuccess);
     wait_event->Signal();
   }
 };
diff --git a/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator_test.cc b/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator_test.cc
index a967dd9..fe01532 100644
--- a/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator_test.cc
+++ b/third_party/blink/renderer/platform/fonts/utf16_ragel_iterator_test.cc
@@ -105,9 +105,11 @@
 TEST(UTF16RagelIteratorTest, InvalidOperationOnEmpty) {
   UTF16RagelIterator ragel_iterator;
   CHECK_EQ(ragel_iterator.Cursor(), 0u);
+#if DCHECK_IS_ON()
   EXPECT_DEATH_IF_SUPPORTED(ragel_iterator++, "");
   EXPECT_DEATH_IF_SUPPORTED(ragel_iterator--, "");
   EXPECT_DEATH_IF_SUPPORTED(*ragel_iterator, "");
+#endif
 }
 
 TEST(UTF16RagelIteratorTest, CursorPositioning) {
@@ -128,9 +130,11 @@
   CHECK_EQ(*(ragel_iterator.SetCursor(6)),
            UTF16RagelIterator::EMOJI_TEXT_PRESENTATION);
 
+#if DCHECK_IS_ON()
   EXPECT_DEATH_IF_SUPPORTED(ragel_iterator.SetCursor(-1), "");
   EXPECT_DEATH_IF_SUPPORTED(
       ragel_iterator.SetCursor(ragel_iterator.end().Cursor()), "");
+#endif
 }
 
 }  // namespace blink
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 51c7de4..a7c6ee3 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -273,7 +273,6 @@
 crbug.com/1007229 external/wpt/intersection-observer/same-origin-grand-child-iframe.sub.html [ Pass Failure ]
 
 # Not supported yet
-crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/abspos-013.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-013.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/flex-aspect-ratio-014.tentative.html [ Failure ]
 crbug.com/1045668 external/wpt/css/css-sizing/aspect-ratio/replaced-element-016.tentative.html [ Failure ]
@@ -1084,11 +1083,6 @@
 crbug.com/1061423 virtual/layout_ng_block_frag/fast/multicol/flipped-blocks-hit-test.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-margin-at-row-boundary.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-margin-at-row-boundary-fixed-multicol-height.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-moved-by-child-line-and-unbreakable.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-by-child-block-and-unbreakable.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-by-child-block.html [ Failure Timeout ]
-crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-by-child-line-and-unbreakable.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-by-child-line.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/forced-break-in-nested-columns.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/forced-break-too-short-column.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/hit-test-above-or-below.html [ Failure ]
@@ -1166,7 +1160,6 @@
 crbug.com/829028 virtual/layout_ng_block_frag/fragmentation/auto-scrollbar-shrink-to-fit.html [ Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/fragmentation/content-preceding-first-fragmentainer.html [ Crash Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fragmentation/float-after-forced-break.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/fragmentation/overflow-crossing-boundary.html [ Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/fragmentation/relayout-abspos.html [ Failure ]
 
 ### With LayoutNGFragmentTraversal (and LayoutNGFragmentItem) enabled:
@@ -1822,9 +1815,6 @@
 
 crbug.com/524160 [ Debug ] http/tests/media/media-source/stream_memory_tests/mediasource-appendbuffer-quota-exceeded-default-buffers.html [ Timeout ]
 
-# Awaiting DevTools roll.
-crbug.com/1109224 inspector-protocol/overlay/overlay-persistent-overlays.js [ Pass Failure ]
-
 # On these platforms (all but Android) media tests don't currently use gpu-accelerated (proprietary) codecs, so no
 # benefit to running them again with gpu acceleration enabled.
 crbug.com/555703 [ Linux ] virtual/media-gpu-accelerated/* [ Skip ]
@@ -3069,9 +3059,6 @@
 crbug.com/626703 external/wpt/css/css-lists/content-property/marker-text-matches-square.html [ Failure ]
 crbug.com/626703 external/wpt/svg/linking/reftests/use-descendant-combinator-003.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-lists/content-property/marker-text-matches-circle.html [ Failure ]
-crbug.com/626703 external/wpt/content-security-policy/securitypolicyviolation/inside-service-worker.https.html [ Timeout ]
-crbug.com/626703 external/wpt/content-security-policy/securitypolicyviolation/inside-shared-worker.html [ Timeout ]
-crbug.com/626703 external/wpt/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html [ Timeout ]
 crbug.com/626703 external/wpt/content-security-policy/securitypolicyviolation/targeting.html [ Timeout ]
 crbug.com/863355 [ Mac ] external/wpt/svg/shapes/reftests/pathlength-002.svg [ Failure ]
 crbug.com/366559 external/wpt/svg/shapes/reftests/pathlength-003.svg [ Failure ]
diff --git a/third_party/blink/web_tests/WPTOverrideExpectations b/third_party/blink/web_tests/WPTOverrideExpectations
index b373135..40bcef8 100644
--- a/third_party/blink/web_tests/WPTOverrideExpectations
+++ b/third_party/blink/web_tests/WPTOverrideExpectations
@@ -176,9 +176,6 @@
 external/wpt/content-security-policy/reporting-api/reporting-api-works-on-frame-src.https.sub.html [ Pass ] # wpt_subtest_failure
 external/wpt/content-security-policy/script-src/script-src-strict_dynamic_hashes.html [ Failure ]
 external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html [ Timeout ] # wpt_subtest_failure
-external/wpt/content-security-policy/securitypolicyviolation/inside-dedicated-worker.html [ Timeout ] # wpt_subtest_failure
-external/wpt/content-security-policy/securitypolicyviolation/inside-service-worker.https.html [ Timeout ] # wpt_subtest_failure
-external/wpt/content-security-policy/securitypolicyviolation/inside-shared-worker.html [ Timeout ] # wpt_subtest_failure
 external/wpt/content-security-policy/securitypolicyviolation/securitypolicyviolation-block-cross-origin-image.sub.html [ Pass ] # wpt_subtest_failure
 external/wpt/content-security-policy/securitypolicyviolation/targeting.html [ Timeout ] # wpt_subtest_failure
 external/wpt/content-security-policy/worker-src/service-none.https.sub.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-026.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-026.html
index 1306493..6b3de88 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-026.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-026.html
@@ -69,7 +69,7 @@
       t.step(() => assert_equals(getComputedStyle(offscreen_container).contain, "size layout style paint", "frame 2 offscreen"));
 
       requestAnimationFrame(() => {
-        offscreen_container.scrollIntoView();
+        window.scrollBy(0, 10000);
 
         // Frame 3 checks:
         t.step(() => assert_equals(getComputedStyle(offscreen_container).contain, "size layout style paint", "frame 3"));
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-058-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-058-ref.html
index 067d064..ee55290 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-058-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-058-ref.html
@@ -35,7 +35,7 @@
 </style>
 
 <div class=spacer></div>
-<div id=container class="container size_contained">
+<div id=container class="container">
   <div class=child></div>
   <div id=target></div>
 </div>
@@ -45,7 +45,6 @@
 
 function runReference() {
   document.getElementById("target").scrollIntoView(true /* alignToTop */);
-  document.getElementById("container").classList.remove("size_contained");
   requestAnimationFrame(takeScreenshot);
 }
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-075-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-075-ref.html
new file mode 100644
index 0000000..05799e0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-075-ref.html
@@ -0,0 +1,37 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + scrollIntoView/fragment nav when size estimate is off (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.small_child {
+  height: 500px;
+}
+.large_child {
+  height: 5000px;
+  position: relative;
+}
+#target {
+  position: absolute;
+  bottom: 0;
+}
+</style>
+
+<div class=auto><div class=small_child></div></div>
+<div class=auto><div class=small_child></div></div>
+<div class=auto><div class=large_child><div id=target>target</div></div></div>
+<div class=auto><div class=large_child></div></div>
+<div class=auto><div class=small_child></div></div>
+
+<script>
+function runReference() {
+  target.scrollIntoView();
+  takeScreenshot();
+}
+
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runReference));
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-075.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-075.html
new file mode 100644
index 0000000..cecbf9b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-075.html
@@ -0,0 +1,41 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + scrollIntoView when size estimate is off</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-075-ref.html">
+<meta name="assert" content="With content-visibility: auto, scrollIntoView targets the right element">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.auto {
+  content-visibility: auto;
+  contain-intrinsic-size: 1px 500px;
+}
+.child {
+  height: 5000px;
+  position: relative;
+}
+#target {
+  position: absolute;
+  bottom: 0;
+}
+</style>
+
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child><div id=target>target</div></div></div>
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child></div></div>
+
+<script>
+function runTest() {
+  target.scrollIntoView();
+  // Double rAF to ensure that rendering has "settled".
+  requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+}
+
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-076-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-076-ref.html
new file mode 100644
index 0000000..6ea5fcf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-076-ref.html
@@ -0,0 +1,37 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + scorllIntoView when size estimate is off (reference)</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.small_child {
+  height: 500px;
+}
+.large_child {
+  height: 5000px;
+  position: relative;
+}
+#target {
+  position: absolute;
+  bottom: 0;
+}
+</style>
+
+<div class=auto><div class=small_child></div></div>
+<div class=auto><div class=small_child></div></div>
+<div class=auto><div class=large_child><div id=target>target</div></div></div>
+<div class=auto><div class=large_child></div></div>
+<div class=auto><div class=small_child></div></div>
+
+<script>
+function runReference() {
+  target.scrollIntoView();
+  takeScreenshot();
+}
+
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runReference));
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-076.html b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-076.html
new file mode 100644
index 0000000..8ba2bbe
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/content-visibility/content-visibility-076.html
@@ -0,0 +1,41 @@
+<!doctype HTML>
+<html class="reftest-wait">
+<meta charset="utf8">
+<title>CSS Content Visibility: auto + fragment nav when size estimate is off</title>
+<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-contain/#content-visibility">
+<link rel="match" href="content-visibility-075-ref.html">
+<meta name="assert" content="With content-visibility: auto, scrollIntoView targets the right element">
+
+<script src="/common/reftest-wait.js"></script>
+
+<style>
+.auto {
+  content-visibility: auto;
+  contain-intrinsic-size: 1px 500px;
+}
+.child {
+  height: 5000px;
+  position: relative;
+}
+#target {
+  position: absolute;
+  bottom: 0;
+}
+</style>
+
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child><div id=target>target</div></div></div>
+<div class=auto><div class=child></div></div>
+<div class=auto><div class=child></div></div>
+
+<script>
+function runTest() {
+  window.location.href += "#target";
+  // Double rAF to ensure that rendering has "settled".
+  requestAnimationFrame(() => requestAnimationFrame(takeScreenshot));
+}
+
+window.onload = () => requestAnimationFrame(() => requestAnimationFrame(runTest));
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-applyConstraints-reject.html b/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-applyConstraints-reject.html
index 45599c0..02ba251f 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-applyConstraints-reject.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-image/MediaStreamTrack-applyConstraints-reject.html
@@ -72,6 +72,10 @@
   capabilities => ({ saturation: capabilities.saturation.min - 1 }),
   capabilities => ({ sharpness: capabilities.sharpness.max + 1 }),
   capabilities => ({ sharpness: capabilities.sharpness.min - 1 }),
+  capabilities => ({ pan: capabilities.pan.max + 1 }),
+  capabilities => ({ pan: capabilities.pan.min - 1 }),
+  capabilities => ({ tilt: capabilities.tilt.max + 1 }),
+  capabilities => ({ tilt: capabilities.tilt.min - 1 }),
   capabilities => ({ zoom: capabilities.zoom.max + 1 }),
   capabilities => ({ zoom: capabilities.zoom.min - 1 }),
   capabilities => ({ torch: true }),
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/WorkerGlobalScope-eval.html b/third_party/blink/web_tests/external/wpt/trusted-types/WorkerGlobalScope-eval.html
new file mode 100644
index 0000000..92487849
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/WorkerGlobalScope-eval.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<html>
+<head>
+  <meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script';">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<script>
+
+// To test workers, we need to importScripts source files in the workers.
+// Since the point of this test is to test blocking of importScripts, we need
+// to set up one policy that will blindly pass through URLs for use in the test
+// setup, and then have additional policies for the actual test cases.
+//
+// For the same reason we cannot use the otherwise preferred 'META: workers'
+// tag, since that test setup would be blocked as soon as trusted types
+// enforcement is enabled.
+const test_setup_policy = trustedTypes.createPolicy("hurrayanythinggoes", {
+  createScriptURL: x => x});
+const test_url =
+  test_setup_policy.createScriptURL("support/WorkerGlobalScope-eval.https.js");
+
+fetch_tests_from_worker(new Worker(test_url));
+
+fetch_tests_from_worker(new SharedWorker(test_url));
+
+// Cargo-culted from code generated from "META: worker".
+if ('serviceWorker' in navigator) {
+  (async function() {
+      const scope = 'support/some/scope/for/this/test';
+      let reg = await navigator.serviceWorker.getRegistration(scope);
+      if (reg) await reg.unregister();
+      reg = await navigator.serviceWorker.register(test_url, {scope});
+      fetch_tests_from_worker(reg.installing);
+  })();
+}
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-eval.https.js b/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-eval.https.js
new file mode 100644
index 0000000..be0a430
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-eval.https.js
@@ -0,0 +1,37 @@
+let test_setup_policy = trustedTypes.createPolicy("hurrayanythinggoes", {
+  createScriptURL: x => x
+});
+importScripts(test_setup_policy.createScriptURL("/resources/testharness.js"));
+
+// Determine worker type (for better logging)
+let worker_type = "unknown";
+if (this.DedicatedWorkerGlobalScope !== undefined) {
+  worker_type = "dedicated worker";
+} else if (this.SharedWorkerGlobalScope !== undefined) {
+  worker_type = "shared worker";
+} else if (this.ServiceWorkerGlobalScope !== undefined) {
+  worker_type = "service worker";
+}
+
+// Test eval(string)
+test(t => {
+  assert_throws_js(EvalError, _ => eval("2"));
+}, "eval(string) in " + worker_type);
+
+// Test eval(TrustedScript)
+let test_policy = trustedTypes.createPolicy("xxx", {
+  createScript: x => x.replace("2", "7")
+});
+test(t => {
+  assert_equals(eval(test_policy.createScript("2")), 7);
+}, "eval(TrustedScript) in " + worker_type);
+
+// Test eval(String) with default policy
+trustedTypes.createPolicy("default", {
+  createScript: x => x.replace("2", "5")
+});
+test(t => {
+  assert_equals(eval("2"), 5);
+}, "eval(string) with default policy in " + worker_type);
+
+done();
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-eval.https.js.headers b/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-eval.https.js.headers
new file mode 100644
index 0000000..604e765
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/WorkerGlobalScope-eval.https.js.headers
@@ -0,0 +1 @@
+Content-Security-Policy: require-trusted-types-for 'script';
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/network-not-modified-images-mime-type-expected.txt b/third_party/blink/web_tests/http/tests/devtools/network/network-not-modified-images-mime-type-expected.txt
new file mode 100644
index 0000000..12197f7
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/network/network-not-modified-images-mime-type-expected.txt
@@ -0,0 +1,6 @@
+Tests that if an image is cached and the server responds with 304, the image MIME type is shown correctly.
+
+http://127.0.0.1:8000/devtools/network/resources/resource.php?type=image&cached=1 200 image/png
+Page reloaded.
+http://127.0.0.1:8000/devtools/network/resources/resource.php?type=image&cached=1 304 image/png
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/network-not-modified-images-mime-type.js b/third_party/blink/web_tests/http/tests/devtools/network/network-not-modified-images-mime-type.js
new file mode 100644
index 0000000..fe49efa
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/network/network-not-modified-images-mime-type.js
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Tests that if an image is cached and the server responds with 304, the image MIME type is shown correctly.\n`);
+  await TestRunner.loadModule('network_test_runner');
+  await TestRunner.loadModule('console_test_runner');
+  await TestRunner.showPanel('network');
+  NetworkTestRunner.recordNetwork();
+  await TestRunner.navigatePromise('resources/cached-image.html');
+  const requests = NetworkTestRunner.networkRequests();
+  const imageRequest = requests[requests.length - 1];
+  TestRunner.addResult(`${imageRequest.url()} ${imageRequest.statusCode} ${imageRequest.mimeType}`);
+  TestRunner.reloadPage(function () {
+    const requests = NetworkTestRunner.networkRequests();
+    const imageRequest = requests[requests.length - 1];
+    TestRunner.addResult(`${imageRequest.url()} ${imageRequest.statusCode} ${imageRequest.mimeType}`);
+    TestRunner.completeTest();
+  });
+})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/resources/cached-image.html b/third_party/blink/web_tests/http/tests/devtools/network/resources/cached-image.html
new file mode 100644
index 0000000..cd8ec68
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/network/resources/cached-image.html
@@ -0,0 +1 @@
+<img src="resource.php?type=image&cached=1" />
\ No newline at end of file
diff --git a/third_party/blink/web_tests/inspector-protocol/overlay/overlay-persistent-overlays.js b/third_party/blink/web_tests/inspector-protocol/overlay/overlay-persistent-overlays.js
index 468bda9..2e1319b 100644
--- a/third_party/blink/web_tests/inspector-protocol/overlay/overlay-persistent-overlays.js
+++ b/third_party/blink/web_tests/inspector-protocol/overlay/overlay-persistent-overlays.js
@@ -42,6 +42,11 @@
     }]
   });
 
+  // Wait for overlay rendering to finish by requesting an animation frame.
+  await session.evaluate(() => {
+    return new Promise(resolve => requestAnimationFrame(resolve));
+  });
+
   testRunner.log('Expected 3 track size labels; actual: ' + await getTrackSizeLabels());
 
   testRunner.completeTest();
diff --git a/third_party/usrsctp/OWNERS b/third_party/usrsctp/OWNERS
index f1ba0bb..aae538b0 100644
--- a/third_party/usrsctp/OWNERS
+++ b/third_party/usrsctp/OWNERS
@@ -1,4 +1,4 @@
 hta@chromium.org
 orphis@chromium.org
 
-# COMPONENT: Internals>Networking
+# COMPONENT: Blink>WebRTC>Network
diff --git a/third_party/zlib/contrib/tests/fuzzers/deflate_fuzzer.cc b/third_party/zlib/contrib/tests/fuzzers/deflate_fuzzer.cc
index 6098ff1..c00e7155 100644
--- a/third_party/zlib/contrib/tests/fuzzers/deflate_fuzzer.cc
+++ b/third_party/zlib/contrib/tests/fuzzers/deflate_fuzzer.cc
@@ -2,46 +2,73 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <fuzzer/FuzzedDataProvider.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <cassert>
 #include <vector>
 
 #include "third_party/zlib/zlib.h"
 
-static Bytef buffer[256 * 1024] = {0};
+// Fuzzer builds often have NDEBUG set, so roll our own assert macro.
+#define ASSERT(cond)                                                           \
+  do {                                                                         \
+    if (!(cond)) {                                                             \
+      fprintf(stderr, "%s:%d Assert failed: %s\n", __FILE__, __LINE__, #cond); \
+      exit(1);                                                                 \
+    }                                                                          \
+  } while (0)
 
-// Entry point for LibFuzzer.
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  // zlib's deflate requires non-zero input sizes
-  if (!size)
-    return 0;
-
-  // We need to strip the 'const' for zlib.
-  std::vector<unsigned char> input_buffer{data, data+size};
-
-  uLongf buffer_length = static_cast<uLongf>(sizeof(buffer));
+  FuzzedDataProvider fdp(data, size);
+  int level = fdp.PickValueInArray({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
+  int windowBits = fdp.PickValueInArray({9, 10, 11, 12, 13, 14, 15});
+  int memLevel = fdp.PickValueInArray({1, 2, 3, 4, 5, 6, 7, 8, 9});
+  int strategy = fdp.PickValueInArray(
+      {Z_DEFAULT_STRATEGY, Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED});
+  std::vector<uint8_t> src = fdp.ConsumeRemainingBytes<uint8_t>();
 
   z_stream stream;
-  stream.next_in = input_buffer.data();
-  stream.avail_in = size;
-  stream.total_in = size;
-  stream.next_out = buffer;
-  stream.avail_out = buffer_length;
-  stream.total_out = buffer_length;
   stream.zalloc = Z_NULL;
   stream.zfree = Z_NULL;
 
-  if (Z_OK != deflateInit(&stream, Z_DEFAULT_COMPRESSION)) {
-    deflateEnd(&stream);
-    assert(false);
+  // Compress the data one byte at a time to exercise the streaming code.
+  int ret =
+      deflateInit2(&stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
+  ASSERT(ret == Z_OK);
+  std::vector<uint8_t> compressed(src.size() * 2 + 1000);
+  stream.next_out = compressed.data();
+  stream.avail_out = compressed.size();
+  for (uint8_t b : src) {
+    stream.next_in = &b;
+    stream.avail_in = 1;
+    ret = deflate(&stream, Z_NO_FLUSH);
+    ASSERT(ret == Z_OK);
   }
-
-  auto deflate_result = deflate(&stream, Z_NO_FLUSH);
+  stream.next_in = Z_NULL;
+  stream.avail_in = 0;
+  ret = deflate(&stream, Z_FINISH);
+  ASSERT(ret == Z_STREAM_END);
+  compressed.resize(compressed.size() - stream.avail_out);
   deflateEnd(&stream);
-  if (Z_OK != deflate_result)
-    assert(false);
+
+  // Verify that the data decompresses correctly.
+  ret = inflateInit2(&stream, windowBits);
+  ASSERT(ret == Z_OK);
+  // Make room for at least one byte so it's never empty.
+  std::vector<uint8_t> decompressed(src.size() + 1);
+  stream.next_in = compressed.data();
+  stream.avail_in = compressed.size();
+  stream.next_out = decompressed.data();
+  stream.avail_out = decompressed.size();
+  ret = inflate(&stream, Z_FINISH);
+  ASSERT(ret == Z_STREAM_END);
+  decompressed.resize(decompressed.size() - stream.avail_out);
+  inflateEnd(&stream);
+
+  ASSERT(decompressed == src);
 
   return 0;
 }
diff --git a/tools/android/instant_start/.style.yapf b/tools/android/instant_start/.style.yapf
new file mode 100644
index 0000000..557fa7b
--- /dev/null
+++ b/tools/android/instant_start/.style.yapf
@@ -0,0 +1,2 @@
+[style]
+based_on_style = pep8
diff --git a/tools/android/instant_start/.vpython b/tools/android/instant_start/.vpython
new file mode 100644
index 0000000..06dc729
--- /dev/null
+++ b/tools/android/instant_start/.vpython
@@ -0,0 +1,61 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# //.vpython doesn't have scipy, so we have to use our own .vpython file.
+# The wheel specs are from //v8/tools/callstats.py.vpython and //.vpython.
+
+# pandas for python3 is not yet available in cipd.
+# TODO(crbug.com/1130251): update to python3
+python_version: "2.7"
+
+wheel: <
+  name: "infra/python/wheels/scipy/${vpython_platform}"
+  version: "version:0.19.0"
+  match_tag: <
+    abi: "cp27mu"
+    platform: "manylinux1_i686"
+  >
+  match_tag: <
+    abi: "cp27mu"
+    platform: "manylinux1_x86_64"
+  >
+>
+wheel: <
+  name: "infra/python/wheels/numpy/${vpython_platform}"
+  version: "version:1.11.3"
+>
+wheel: <
+  name: "infra/python/wheels/six-py2_py3"
+  version: "version:1.15.0"
+>
+wheel: <
+  name: "infra/python/wheels/pandas/${vpython_platform}"
+  version: "version:0.23.4"
+  match_tag: <
+    platform: "win32"
+  >
+  match_tag: <
+    platform: "win_amd64"
+  >
+  match_tag: <
+    abi: "cp27mu"
+    platform: "manylinux1_i686"
+  >
+  match_tag: <
+    abi: "cp27mu"
+    platform: "manylinux1_x86_64"
+  >
+  match_tag: <
+    platform: "macosx_10_6_intel"
+  >
+>
+wheel: <
+  name: "infra/python/wheels/pytz-py2_py3"
+  version: "version:2018.4"
+>
+wheel: <
+  name: "infra/python/wheels/python-dateutil-py2_py3"
+  version: "version:2.7.3"
+>
+
diff --git a/tools/android/instant_start/OWNERS b/tools/android/instant_start/OWNERS
new file mode 100644
index 0000000..39230171
--- /dev/null
+++ b/tools/android/instant_start/OWNERS
@@ -0,0 +1 @@
+wychen@chromium.org
diff --git a/tools/android/instant_start/README.md b/tools/android/instant_start/README.md
new file mode 100644
index 0000000..5448990
--- /dev/null
+++ b/tools/android/instant_start/README.md
@@ -0,0 +1,52 @@
+# Benchmarking and analyzing scripts for Instant Start
+
+## Introduction
+
+In order to understand the performance implication of a CL, we can do a local
+benchmark to compare the before/after metrics.
+
+## Usage
+
+Build two APKs for before and after a CL, on gn target `monochrome_apk`, and
+make sure they are on different Chrome channels, like Canary (gn args
+`android_channel = "canary"`) and default (unspecified) because they will be
+installed side by side. Depending on your preferred workflow, you can use two
+separate workspaces like `~/code/clankium/src` and `~/code/clankium2/src`, or
+use the same workspace but two different output directories like `./out/Release`
+and `./out/Release2`, or simply use the same output directory but rename the APK
+like `out/Release/bin/monochrome_before_apk` and
+`out/Release/bin/monochrome_after_apk`.
+
+On the device, uninstall Chrome of these two channels to make sure the
+environment is clean. Otherwise, chrome://flags changes and Finch trials could
+introduce undesirable differences. You can use the `--reinstall` option to
+automate this.  When running benchmark.py, first-run experience (FRE) would be
+skipped, but you'll need to manually create one tab, make sure Feed is loaded,
+and swipe away the login prompt in the dry-run step. Follow the instructions of
+the script.
+
+The command line looks like this:
+
+```bash
+./tools/android/instant_start/benchmark.py --control-apk out/Release/bin/monochrome_before_apk --experiment-apk out/Release/bin/monochrome_after_apk -v --repeat 100 --reinstall
+```
+
+The metrics are persisted to `runs.pickle` by default, and the filename can be
+specified by `--data-output` option. This can later be analyzed like this:
+
+```bash
+./tools/android/instant_start/analyze.py runs.pickle
+```
+
+The output looks like:
+
+```
+Reading runs-pixel3xl.pickle with {'model': 'Pixel 3 XL', 'start_time': datetime.datetime(2020, 9, 19, 14, 55, 34, 596731)}
+100 samples on Pixel 3 XL
+                               Median  Diff with control   p-value
+FirstDrawCompletedTime        155.0ms   -13.5ms (-8.71%)  0.000000
+SingleTabTitleAvailableTime   117.0ms  -13.0ms (-11.11%)  0.000000
+FeedStreamCreatedTime         356.0ms   -35.5ms (-9.97%)  0.000001
+FeedsLoadingPlaceholderShown   94.5ms    -2.0ms (-2.12%)  0.007312
+FeedContentFirstLoadedTime    924.0ms    -6.5ms (-0.70%)  0.034100
+```
diff --git a/tools/android/instant_start/analyze.py b/tools/android/instant_start/analyze.py
new file mode 100755
index 0000000..2590747
--- /dev/null
+++ b/tools/android/instant_start/analyze.py
@@ -0,0 +1,37 @@
+#!/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.
+"""Analyze benchmark results for Instant start."""
+
+from __future__ import print_function
+
+import argparse
+import pickle
+import sys
+
+import stats.analyze
+
+
+def main():
+    """Main program"""
+    parser = argparse.ArgumentParser(
+        description=__doc__,
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    parser.add_argument('pickles',
+                        nargs='+',
+                        help='The pickle files saved by benchmark.py.')
+    args = parser.parse_args()
+
+    runs = []
+    for filename in args.pickles:
+        with open(filename, 'rb') as file:
+            metadata = pickle.load(file)
+            print('Reading "%s" with %s' % (filename, metadata))
+            runs.extend(pickle.load(file))
+    stats.analyze.print_report(runs, metadata['model'])
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/tools/android/instant_start/benchmark.py b/tools/android/instant_start/benchmark.py
new file mode 100755
index 0000000..6e0b11d
--- /dev/null
+++ b/tools/android/instant_start/benchmark.py
@@ -0,0 +1,205 @@
+#!/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.
+"""Run benchmark for Instant start."""
+
+from __future__ import print_function
+
+import argparse
+from datetime import datetime
+import logging
+import os
+import pickle
+import random
+import re
+import subprocess
+import sys
+import time
+
+import stats.analyze
+
+
+def get_timestamp(adb_log_line):
+    """Parse the timestamp in the adb log"""
+    # adb log doesn't have the year field printed out.
+    parsed = datetime.strptime(adb_log_line[0:18], '%m-%d %H:%M:%S.%f')
+    return parsed.replace(year=datetime.now().year)
+
+
+def keep_awake():
+    """Keep the device awake. This works for non-rooted devices as well."""
+    os.system("adb shell svc power stayon true")
+    os.system("adb shell input keyevent mouse")
+
+
+def get_model():
+    """Get the device model."""
+    return subprocess.check_output(
+        ['adb', 'shell', 'getprop', 'ro.product.model']).rstrip()
+
+
+def run_apk(variant, dry_run=False, reinstall=False, check_state=False):
+    """Run Chrome and return metrics"""
+
+    keep_awake()
+
+    variant_name, apk_script, extra_cmd = variant
+    logging.warning('Running variant "%s"', variant_name)
+    assert os.path.exists(apk_script), "Script '%s' doesn't exist" % apk_script
+
+    features = '--enable-features=' + ','.join([
+        'TabGroupsAndroid<Study', 'TabSwitcherOnReturn<Study',
+        'StartSurfaceAndroid<Study', 'InstantStart<Study'
+    ])
+
+    args = '--args=' + ' '.join([
+        '--disable-fre', '--disable-field-trial-config', features,
+        '--force-fieldtrials=Study/Group',
+        '--force-fieldtrial-params=Study.Group:'
+        'tab_switcher_on_return_time_ms/0'
+        '/start_surface_variation/single'
+        '/show_last_active_tab_only/true'
+        '/open_ntp_instead_of_start/true'
+        '/exclude_mv_tiles/true'
+    ] + extra_cmd)
+
+    if reinstall:
+        logging.warning('Uninstalling')
+        cmd = [apk_script, 'uninstall']
+        logging.info('Running %s', cmd)
+        logging.info(subprocess.check_output(cmd, stderr=subprocess.STDOUT))
+
+    # Use "unbuffer" to force flushing the output of |apk_script|.
+    cmd = ['unbuffer', apk_script, 'run', '-vvv', args]
+    logging.info('Running %s', cmd)
+    # Use unbuffered pipe to avoid blocking.
+    proc = subprocess.Popen(cmd,
+                            stdout=subprocess.PIPE,
+                            stderr=subprocess.STDOUT,
+                            bufsize=0)
+    latencies = []
+    events_re = re.compile(
+        r"Startup.Android.(?P<name>[0-9a-zA-Z_]+)[^ ]* = (?P<value>[0-9.]+)")
+
+    # Avoid buffering in proc.stdout.next().
+    # "for line in prod.stdout" might block.
+    # See https://stackoverflow.com/questions/1183643/
+    for line in iter(proc.stdout.readline, b''):
+        if isinstance(line, bytes):
+            line = line.decode(encoding='utf8')
+        logging.debug(line.rstrip())
+        if ('ActivityTaskManager' in line
+                or 'ActivityManager' in line) and 'START' in line:
+            start_timestamp = get_timestamp(line)
+            logging.info('Chrome started at %s', start_timestamp)
+            if dry_run:
+                time.sleep(5)
+                if check_state:
+                    logging.warning('Make sure there is at least one tab, '
+                                    'and the Feed is loaded. '
+                                    'Press Enter to continue.')
+                    sys.stdin.readline()
+                break
+        groups = events_re.search(line)
+        if groups:
+            latency = {}
+            latency['variant_name'] = variant_name
+            latency['metric_name'] = groups.group('name')
+            latency['value'] = groups.group('value')
+            latencies.append(latency)
+            logging.info(line.rstrip())
+            logging.info('Got %s = %s', groups.group('name'),
+                         groups.group('value'))
+        if len(latencies) >= 5:
+            break
+
+    proc.kill()
+    return latencies
+
+
+def main():
+    """Entry point of the benchmark script"""
+    parser = argparse.ArgumentParser(
+        description=__doc__,
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    parser.add_argument('--control-apk',
+                        default='out/Release/bin/monochrome_apk',
+                        help='The APK script file for control behavior.')
+    parser.add_argument('--experiment-apk',
+                        default='out/Release/bin/monochrome_apk',
+                        help='The APK script file for experiment behavior.')
+    parser.add_argument('--reinstall',
+                        action='store_true',
+                        help='Uninstall before installing the APKs.')
+    parser.add_argument('--repeat',
+                        type=int,
+                        default=3,
+                        help='How many times to repeat running.')
+    parser.add_argument('--data-output',
+                        default='runs.pickle',
+                        help='The output file for benchmark data.')
+    parser.add_argument('-v',
+                        '--verbose',
+                        action='count',
+                        default=0,
+                        help='Be more verbose.')
+    args, _ = parser.parse_known_args()
+
+    level = logging.WARNING
+    if args.verbose == 1:
+        level = logging.INFO
+    elif args.verbose >= 2:
+        level = logging.DEBUG
+    logging.basicConfig(level=level,
+                        format='%(asctime)-2s %(levelname)-8s %(message)s')
+    logging.addLevelName(
+        logging.WARNING,
+        "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.WARNING))
+    logging.addLevelName(
+        logging.ERROR,
+        "\033[1;41m%s\033[1;0m" % logging.getLevelName(logging.ERROR))
+
+    try:
+        subprocess.check_output('which unbuffer', shell=True)
+    except subprocess.CalledProcessError:
+        sys.exit('ERROR: "unbuffer" not found. ' +
+                 'Install by running "sudo apt install expect".')
+
+    logging.warning('Make sure the device screen is unlocked. '
+                    'Otherwise the benchmark might get stuck.')
+
+    # List control/experiment APKs for side-by-side comparison.
+    variants = []
+    variants.append(('control', args.control_apk, []))
+    variants.append(('experiment', args.experiment_apk, []))
+
+    metadata = {'model': get_model(), 'start_time': datetime.now()}
+
+    logging.warning('Pre-run for flag caching.')
+    for variant in variants:
+        run_apk(variant, dry_run=True, reinstall=args.reinstall)
+
+    logging.warning('Dry-run for manual state checking.')
+    for variant in variants:
+        run_apk(variant, dry_run=True, check_state=True)
+
+    runs = []
+    for i in range(args.repeat):
+        logging.warning('Run %d/%d', i + 1, args.repeat)
+        random.shuffle(variants)
+        for variant in variants:
+            result = run_apk(variant)
+            logging.info('Results: %s', result)
+            runs.extend(result)
+            time.sleep(10)  # try to avoid overloading the device.
+        with open(args.data_output, 'wb') as pickle_file:
+            pickle.dump(metadata, pickle_file)
+            pickle.dump(runs, pickle_file)
+            logging.info('Saved "%s"', args.data_output)
+        stats.analyze.print_report(runs, metadata['model'])
+
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/tools/android/instant_start/stats/__init__.py b/tools/android/instant_start/stats/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/android/instant_start/stats/__init__.py
diff --git a/tools/android/instant_start/stats/analyze.py b/tools/android/instant_start/stats/analyze.py
new file mode 100644
index 0000000..a0ba8ee
--- /dev/null
+++ b/tools/android/instant_start/stats/analyze.py
@@ -0,0 +1,34 @@
+# 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.
+"""Library for analyzing benchmark results for Instant start."""
+
+import pandas
+from scipy import stats
+
+
+def print_report(runs, model, control='control', experiment='experiment'):
+    """Print stats of A/B testing"""
+    all_df = pandas.DataFrame(runs, dtype=float)
+    report = pandas.DataFrame(
+        columns=['Median', 'Diff with control', 'p-value'])
+    for metric in sorted(set(all_df['metric_name'])):
+        mdf = all_df[all_df['metric_name'] == metric]
+        df = pandas.DataFrame()
+        for variant in sorted(set(all_df['variant_name'])):
+            df[variant] = mdf[mdf['variant_name'] == variant]\
+                .value.reset_index(drop=True)
+
+        diff_df = pandas.DataFrame()
+        diff_df = df[experiment] - df[control]
+        n = len(diff_df)
+
+        row = {}
+        row['Median'] = '%.1fms' % df[experiment].median()
+        row['Diff with control'] = '%.1fms (%.2f%%)' % (
+            diff_df.median(), diff_df.median() / df[experiment].median() * 100)
+        row['p-value'] = '%f' % (stats.ttest_rel(df[experiment],
+                                                 df[control])[1])
+        report = report.append(pandas.Series(data=row, name=metric))
+    print('%d samples on %s' % (n, model))
+    print(report.sort_values(by='p-value'))
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 3ea5e383..a411c2a 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -195,7 +195,10 @@
     "includes": [1830],
     "structures": [1840],
   },
-  "chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd": {
+  "chrome/browser/resources/signin/profile_picker/profile_picker_resources_vulcanized.grd": {
+    "includes": [1850],
+  },
+ "chrome/browser/resources/signin/profile_picker/profile_picker_resources.grd": {
     "includes": [1860],
     "structures": [1870],
   },
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 25f69a4f..f617667 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -16089,6 +16089,13 @@
   </description>
 </action>
 
+<action name="NewTabPage_Promos_SafetyCheck">
+  <owner>msramek@chromium.org</owner>
+  <description>
+    Recorded when the user clicks a Safety Check promotion on the New Tab Page.
+  </description>
+</action>
+
 <action name="NewTabPage_ReopenTab">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a55f662..c7fc4b17 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -21829,6 +21829,7 @@
   <int value="784" label="QuickUnlockModeAllowlist"/>
   <int value="785" label="AttestationExtensionAllowlist"/>
   <int value="786" label="DataLeakPreventionRulesList"/>
+  <int value="787" label="WebRtcAllowLegacyTLSProtocols"/>
 </enum>
 
 <enum name="EnterprisePolicyDeviceIdValidity">
@@ -54918,6 +54919,13 @@
   <int value="1" label="Passwords and generate new password"/>
 </enum>
 
+<enum name="PasswordEditUpdatedValues">
+  <int value="0" label="None"/>
+  <int value="1" label="Username"/>
+  <int value="2" label="Password"/>
+  <int value="3" label="Both"/>
+</enum>
+
 <enum name="PasswordFormQueryVolume">
   <int value="0" label="New password query"/>
   <int value="1" label="Current query"/>
diff --git a/tools/metrics/histograms/histograms_xml/content/histograms.xml b/tools/metrics/histograms/histograms_xml/content/histograms.xml
index c8e6fc8..937d515d97 100644
--- a/tools/metrics/histograms/histograms_xml/content/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/content/histograms.xml
@@ -264,8 +264,9 @@
 </histogram>
 
 <histogram name="ContentSettings.EphemeralFlashPermission"
-    enum="ContentSettings.EphemeralFlashPermission" expires_after="M87">
+    enum="ContentSettings.EphemeralFlashPermission" expires_after="M89">
   <owner>engedy@chromium.org</owner>
+  <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
     Records the number of times Flash permission is granted for a host.
   </summary>
diff --git a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
index 70823b44..6115181 100644
--- a/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/cryptohome/histograms.xml
@@ -266,6 +266,16 @@
   </summary>
 </histogram>
 
+<histogram name="Cryptohome.InvalidateDirCryptoKeyResult" enum="BooleanSuccess"
+    expires_after="2021-09-26">
+  <owner>yich@google.com</owner>
+  <owner>cros-hwsec+uma@chromium.org</owner>
+  <summary>
+    The errors resulting from interacting with the InvalidateDirCryptoKey
+    operation.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Cryptohome.LECredential"
     enum="CryptohomeLECredError" expires_after="2021-02-28">
 <!-- Name completed by histogram_suffixes name="LECredentialOps" -->
diff --git a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
index 953f78d8..1f616844 100644
--- a/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/enterprise/histograms.xml
@@ -170,6 +170,18 @@
   <summary>URL fetcher status for auto-enrollment requests.</summary>
 </histogram>
 
+<histogram base="true" name="Enterprise.CachedDevicePolicyDeviceIdValidity"
+    enum="EnterprisePolicyDeviceIdValidity" expires_after="M95">
+  <owner>emaxx@chromium.org</owner>
+  <owner>rodmartin@chromium.org</owner>
+  <summary>
+    Result of the device ID validation in the device policy blob for those which
+    were loaded from disk. This validation happens on enrolled devices on
+    startup, on scheduled policy reloads that happen every few hours, and on
+    forced policy reloads.
+  </summary>
+</histogram>
+
 <histogram name="Enterprise.CBCMPolicyInvalidations"
     enum="EnterprisePolicyInvalidations" expires_after="2021-06-16">
   <owner>anthonyvd@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/file/histograms.xml b/tools/metrics/histograms/histograms_xml/file/histograms.xml
index 0b626ed3..adb51da 100644
--- a/tools/metrics/histograms/histograms_xml/file/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/file/histograms.xml
@@ -129,6 +129,20 @@
   </summary>
 </histogram>
 
+<histogram name="FileBrowser.DriveHostedFilePinSuccess" enum="BooleanSuccess"
+    expires_after="M92">
+  <owner>austinct@chromium.org</owner>
+  <owner>dats@chromium.org</owner>
+  <summary>Tracks success rate of pinning hosted files in Drive.</summary>
+</histogram>
+
+<histogram name="FileBrowser.DrivePinSuccess" enum="BooleanSuccess"
+    expires_after="M92">
+  <owner>austinct@chromium.org</owner>
+  <owner>dats@chromium.org</owner>
+  <summary>Tracks success rate of pinning files in Drive.</summary>
+</histogram>
+
 <histogram name="FileBrowser.FileSystemProviderMounted"
     enum="FileSystemProviderMountType" expires_after="M89">
   <owner>slangley@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml b/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml
index 8b3bbd6..fe051f9b 100644
--- a/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/geolocation/histograms.xml
@@ -136,7 +136,7 @@
 </histogram>
 
 <histogram base="true" name="Geolocation.SettingsDialog.AcceptEvent"
-    enum="GeolocationSettingsDialogBackOff" expires_after="M87">
+    enum="GeolocationSettingsDialogBackOff" expires_after="M89">
   <owner>engedy@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -146,7 +146,7 @@
 </histogram>
 
 <histogram base="true" name="Geolocation.SettingsDialog.DenyEvent"
-    enum="GeolocationSettingsDialogBackOff" expires_after="M87">
+    enum="GeolocationSettingsDialogBackOff" expires_after="M89">
   <owner>engedy@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -156,7 +156,7 @@
 </histogram>
 
 <histogram base="true" name="Geolocation.SettingsDialog.ShowEvent"
-    enum="GeolocationSettingsDialogBackOff" expires_after="M87">
+    enum="GeolocationSettingsDialogBackOff" expires_after="M89">
   <owner>engedy@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
@@ -166,7 +166,7 @@
 </histogram>
 
 <histogram base="true" name="Geolocation.SettingsDialog.SuppressEvent"
-    enum="GeolocationSettingsDialogBackOff" expires_after="M87">
+    enum="GeolocationSettingsDialogBackOff" expires_after="M89">
   <owner>engedy@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index ba10b33..d90974c 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -7956,10 +7956,9 @@
 </histogram>
 
 <histogram name="ManagedUsers.SafetyFilter"
-    enum="SupervisedUserSafetyFilterResult" expires_after="M85">
-  <owner>treib@chromium.org</owner>
-  <owner>escordeiro@chromium.org</owner>
-  <owner>menegola@chromium.org</owner>
+    enum="SupervisedUserSafetyFilterResult" expires_after="2021-09-27">
+  <owner>agawronska@chromium.org</owner>
+  <owner>cros-families-eng@google.com</owner>
   <summary>
     The counts of results from the supervised user safety filter. Each entry
     includes the outcome of the filter (i.e. allowed, blocked, or unknown) and
diff --git a/tools/metrics/histograms/histograms_xml/password/histograms.xml b/tools/metrics/histograms/histograms_xml/password/histograms.xml
index d24e4a4..e65cf0d6 100644
--- a/tools/metrics/histograms/histograms_xml/password/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/password/histograms.xml
@@ -1572,6 +1572,16 @@
   <summary>Logs the state of the password dropdown when it's shown.</summary>
 </histogram>
 
+<histogram name="PasswordManager.PasswordEditUpdatedValues"
+    enum="PasswordEditUpdatedValues" expires_after="M92">
+  <owner>vsemeniuk@google.com</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    This metric shows what exactly users change in the password edit dialog:
+    nothing, username, password or both.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.PasswordReuse.NumberOfMatches"
     units="credentials" expires_after="2021-01-30">
   <owner>vakh@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/settings/histograms.xml b/tools/metrics/histograms/histograms_xml/settings/histograms.xml
index 3c364db..16df0e2 100644
--- a/tools/metrics/histograms/histograms_xml/settings/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/settings/histograms.xml
@@ -482,8 +482,9 @@
 </histogram>
 
 <histogram name="SettingsResetPrompt.PromptAccepted" enum="BooleanAccepted"
-    expires_after="M85">
-  <owner>alito@chromium.org</owner>
+    expires_after="M90">
+  <owner>proberge@chromium.org</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
     Indicates whether the user accepted the settings reset prompt.
   </summary>
diff --git a/ui/base/clipboard/clipboard_data_endpoint.h b/ui/base/clipboard/clipboard_data_endpoint.h
index 6ec606b..9e6f12d 100644
--- a/ui/base/clipboard/clipboard_data_endpoint.h
+++ b/ui/base/clipboard/clipboard_data_endpoint.h
@@ -16,11 +16,14 @@
 // Whenever a new format is supported, a new enum should be added.
 enum class EndpointType {
 #if defined(OS_CHROMEOS) || (OS_LINUX) || (OS_FUCHSIA)
-  kGuestOs = 0,  // Guest OS: ARC++, PluginVM, Crostini.
-#endif
-  kUrl = 1,  // Website URL e.g. www.example.com.
-  kClipboardHistory =
-      2,  // Clipboard History UI has privileged access to any clipboard data.
+  kGuestOs = 0,  // Guest OS: PluginVM, Crostini.
+#endif           // defined(OS_CHROMEOS) || (OS_LINUX) || (OS_FUCHSIA)
+#if defined(OS_CHROMEOS)
+  kArc = 1,               // ARC.
+#endif                    // defined(OS_CHROMEOS)
+  kUrl = 2,               // Website URL e.g. www.example.com.
+  kClipboardHistory = 3,  // Clipboard History UI has privileged access to any
+                          // clipboard data.
   kMaxValue = kClipboardHistory
 };
 
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index b2b35588..3c035508 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -768,7 +768,7 @@
     Copy operation failed, unexpected error: <ph name="ERROR_MESSAGE">$1<ex>Could not copy</ex></ph>
   </message>
   <message name="IDS_FILE_BROWSER_FILE_COPIED" desc="File Manager status message. 'Item' is used here as a generic term for file or directory.">
-    <ph name="NUMBER_OF_ITEMS">$1<ex>3</ex></ph> copied.
+    <ph name="FILE_NAME">$1<ex>big.xz</ex></ph> copied.
   </message>
   <message name="IDS_FILE_BROWSER_FILE_ITEMS" desc="File Manager status message. 'Item' is used here as a generic term for file or directory.">
     <ph name="NUMBER_OF_ITEMS">$1<ex>3</ex></ph> items
@@ -780,7 +780,7 @@
     <ph name="NUMBER_OF_ITEMS">$1<ex>3</ex></ph> items moved.
   </message>
   <message name="IDS_FILE_BROWSER_FILE_MOVED" desc="File Manager status message. 'Item' is used here as a generic term for file or directory.">
-    <ph name="NUMBER_OF_ITEMS">$1<ex>3</ex></ph> moved.
+    <ph name="FILE_NAME">$1<ex>big.xz</ex></ph> moved.
   </message>
    <!-- TODO (crbug/1093603): Clean up after FilesTransferDetails launch. -->
   <message name="IDS_FILE_BROWSER_MOVE_FILE_NAME" desc="File Manager status message.">
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FILE_COPIED.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FILE_COPIED.png.sha1
index 99fbde2..b315822 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FILE_COPIED.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FILE_COPIED.png.sha1
@@ -1 +1 @@
-d0218c6981c069857eba06ad3f94bf373dc40573
\ No newline at end of file
+82c96c11c0634040463a9670fa9ab31af88bf927
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FILE_MOVED.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FILE_MOVED.png.sha1
index 502f68e..149d18f 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FILE_MOVED.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_FILE_MOVED.png.sha1
@@ -1 +1 @@
-6cb05b5c6046c76d4cec2360f28df27c93c37c66
\ No newline at end of file
+5d5c3b153e7bc697e43b9546acc4b15499f54553
\ No newline at end of file
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.js b/ui/file_manager/file_manager/foreground/js/actions_model.js
index 89a95d9..b829f94 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model.js
@@ -254,6 +254,11 @@
       // Check the result of pinning.
       entryPinned: () => {
         error = !!chrome.runtime.lastError;
+        metrics.recordBoolean('DrivePinSuccess', !error);
+        if (this.metadataModel_.getCache([currentEntry], ['hosted'])[0]
+                .hosted) {
+          metrics.recordBoolean('DriveHostedFilePinSuccess', !error);
+        }
         if (error && this.value_) {
           this.metadataModel_.get([currentEntry], ['size']).then(results => {
             steps.showError(results[0].size);
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
index ece9076..dde8567 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
@@ -109,6 +109,17 @@
   installMockChrome(mockChrome);
   new MockCommandLinePrivate();
 
+  // Mock metrics.
+  window.metrics = {
+    calls: {
+      DrivePinSuccess: 0,
+      DriveHostedFilePinSuccess: 0,
+    },
+    recordBoolean: function(name) {
+      window.metrics.calls[name]++;
+    },
+  };
+
   // Setup Drive file system.
   volumeManager = new MockVolumeManager();
   let type = VolumeManagerCommon.VolumeType.DRIVE;
@@ -265,6 +276,9 @@
             assertTrue(metadataModel.properties.pinned);
             assertEquals(1, invalidated);
 
+            assertEquals(1, window.metrics.calls['DrivePinSuccess']);
+            assertEquals(0, window.metrics.calls['DriveHostedFilePinSuccess']);
+
             // The model is invalidated, as list of actions have changed.
             // Recreated the model and check that the actions are updated.
             model = new ActionsModel(
@@ -382,6 +396,9 @@
             assertTrue(!!metadataModel.getCache([testDocument])[0].pinned);
             assertTrue(!!metadataModel.getCache([testFile])[0].pinned);
 
+            assertEquals(2, window.metrics.calls['DrivePinSuccess']);
+            assertEquals(1, window.metrics.calls['DriveHostedFilePinSuccess']);
+
             model = new ActionsModel(
                 volumeManager, metadataModel, shortcutsModel, driveSyncHandler,
                 ui, [testDocument, testFile]);
@@ -489,6 +506,9 @@
             assertFalse(!!metadataModel.getCache([testDocument])[0].pinned);
             assertTrue(!!metadataModel.getCache([testFile])[0].pinned);
 
+            assertEquals(1, window.metrics.calls['DrivePinSuccess']);
+            assertEquals(0, window.metrics.calls['DriveHostedFilePinSuccess']);
+
             model = new ActionsModel(
                 volumeManager, metadataModel, shortcutsModel, driveSyncHandler,
                 ui, [testDocument, testFile]);
diff --git a/ui/file_manager/image_loader/BUILD.gn b/ui/file_manager/image_loader/BUILD.gn
index 82e3096..f369640 100644
--- a/ui/file_manager/image_loader/BUILD.gn
+++ b/ui/file_manager/image_loader/BUILD.gn
@@ -41,7 +41,6 @@
     ":cache",
     ":image_request_task",
     ":load_image_request",
-    ":piex_loader",
     ":scheduler",
     "//ui/file_manager/externs:file_manager_private",
   ]
diff --git a/ui/file_manager/image_loader/image_loader.js b/ui/file_manager/image_loader/image_loader.js
index c79c95d0..3a7dc1d 100644
--- a/ui/file_manager/image_loader/image_loader.js
+++ b/ui/file_manager/image_loader/image_loader.js
@@ -21,12 +21,6 @@
    */
   this.scheduler_ = new Scheduler();
 
-  /**
-   * Piex loader for RAW images.
-   * @private {!PiexLoader}
-   */
-  this.piexLoader_ = new PiexLoader();
-
   // Grant permissions to all volumes, initialize the cache and then start the
   // scheduler.
   chrome.fileManagerPrivate.getVolumeMetadataList(function(volumeMetadataList) {
@@ -155,8 +149,8 @@
     return false;  // No callback calls.
   } else {
     // Create a request task and add it to the scheduler (queue).
-    const requestTask = new ImageRequestTask(
-        requestId, this.cache_, this.piexLoader_, request, callback);
+    const requestTask =
+        new ImageRequestTask(requestId, this.cache_, request, callback);
     this.scheduler_.add(requestTask);
     return true;  // Request will call the callback.
   }
diff --git a/ui/file_manager/image_loader/image_request_task.js b/ui/file_manager/image_loader/image_request_task.js
index cc39051..e9eba78 100644
--- a/ui/file_manager/image_loader/image_request_task.js
+++ b/ui/file_manager/image_loader/image_request_task.js
@@ -8,12 +8,11 @@
  *
  * @param {string} id Request ID.
  * @param {ImageCache} cache Cache object.
- * @param {!PiexLoader} piexLoader Piex loader for RAW file.
  * @param {!LoadImageRequest} request Request message as a hash array.
  * @param {function(!LoadImageResponse)} callback Response handler.
  * @constructor
  */
-function ImageRequestTask(id, cache, piexLoader, request, callback) {
+function ImageRequestTask(id, cache, request, callback) {
   /**
    * Global ID (concatenated client ID and client request ID).
    * @type {string}
@@ -28,12 +27,6 @@
   this.cache_ = cache;
 
   /**
-   * @type {!PiexLoader}
-   * @private
-   */
-  this.piexLoader_ = piexLoader;
-
-  /**
    * @type {!LoadImageRequest}
    * @private
    */
@@ -339,7 +332,8 @@
 
   // Load RAW image source thumbnail.
   if (fileType.type === 'raw') {
-    this.piexLoader_.load(this.request_.url, chrome.runtime.reload)
+    const piexLoader = ImageRequestTask.getPiexLoaderInstance();
+    piexLoader.load(this.request_.url, chrome.runtime.reload)
         .then(
             function(data) {
               this.request_.orientation =
@@ -636,3 +630,14 @@
   this.canvas_.width = 0;
   this.canvas_.height = 0;
 };
+
+/**
+ * Returns the singleton instance of the PiexLoader RAW image loader.
+ * @return {!PiexLoader} PiexLoader object.
+ */
+ImageRequestTask.getPiexLoaderInstance = function() {
+  if (!ImageRequestTask.piexLoaderInstance_) {
+    ImageRequestTask.piexLoaderInstance_ = new PiexLoader();
+  }
+  return ImageRequestTask.piexLoaderInstance_;
+};
diff --git a/ui/gtk/native_theme_gtk.cc b/ui/gtk/native_theme_gtk.cc
index e4b9c5e5..a77c571 100644
--- a/ui/gtk/native_theme_gtk.cc
+++ b/ui/gtk/native_theme_gtk.cc
@@ -77,6 +77,8 @@
     // Dialogs
     case ui::NativeTheme::kColorId_DialogBackground:
     case ui::NativeTheme::kColorId_BubbleBackground:
+    // Notifications
+    case ui::NativeTheme::kColorId_NotificationDefaultBackground:
       return GetBgColor("");
     case ui::NativeTheme::kColorId_DialogForeground:
     case ui::NativeTheme::kColorId_BubbleForeground:
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc
index a32dd95..4a0e6ba 100644
--- a/ui/message_center/views/message_view.cc
+++ b/ui/message_center/views/message_view.cc
@@ -173,9 +173,7 @@
 
 void MessageView::UpdateCornerRadius(int top_radius, int bottom_radius) {
   SetCornerRadius(top_radius, bottom_radius);
-  SetBackground(views::CreateBackgroundFromPainter(
-      std::make_unique<NotificationBackgroundPainter>(top_radius,
-                                                      bottom_radius)));
+  UpdateBackgroundPainter();
   SchedulePaint();
 }
 
@@ -251,7 +249,7 @@
 }
 
 bool MessageView::OnKeyReleased(const ui::KeyEvent& event) {
-  // Space key handling is triggerred at key-release timing. See
+  // Space key handling is triggered at key-release timing. See
   // ui/views/controls/buttons/button.cc for why.
   if (event.flags() != ui::EF_NONE || event.key_code() != ui::VKEY_SPACE)
     return false;
@@ -327,6 +325,7 @@
 
 void MessageView::OnThemeChanged() {
   InkDropHostView::OnThemeChanged();
+  UpdateBackgroundPainter();
   SetNestedBorderIfNecessary();
 }
 
@@ -472,6 +471,14 @@
   }
 }
 
+void MessageView::UpdateBackgroundPainter() {
+  SkColor background_color = GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_NotificationDefaultBackground);
+  SetBackground(views::CreateBackgroundFromPainter(
+      std::make_unique<NotificationBackgroundPainter>(
+          top_radius_, bottom_radius_, background_color)));
+}
+
 void MessageView::UpdateControlButtonsVisibility() {
   auto* control_buttons_view = GetControlButtonsView();
   if (control_buttons_view)
diff --git a/ui/message_center/views/message_view.h b/ui/message_center/views/message_view.h
index af921ef..4cd34fce 100644
--- a/ui/message_center/views/message_view.h
+++ b/ui/message_center/views/message_view.h
@@ -209,6 +209,9 @@
   // Sets the border if |is_nested_| is true.
   void SetNestedBorderIfNecessary();
 
+  // Updates the background painter using the themed background color and radii.
+  void UpdateBackgroundPainter();
+
   std::string notification_id_;
   views::ScrollView* scroller_ = nullptr;
 
diff --git a/ui/message_center/views/notification_background_painter.h b/ui/message_center/views/notification_background_painter.h
index a31dd1f..33f8de47 100644
--- a/ui/message_center/views/notification_background_painter.h
+++ b/ui/message_center/views/notification_background_painter.h
@@ -6,7 +6,6 @@
 #define UI_MESSAGE_CENTER_VIEWS_NOTIFICATION_BACKGROUND_PAINTER_H_
 
 #include "ui/message_center/message_center_export.h"
-#include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/views/painter.h"
 
 namespace message_center {
@@ -19,7 +18,7 @@
  public:
   NotificationBackgroundPainter(int top_radius,
                                 int bottom_radius,
-                                SkColor color = kNotificationBackgroundColor);
+                                SkColor color);
   ~NotificationBackgroundPainter() override;
 
   // views::Painter
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc
index 977cefd..35301a2f 100644
--- a/ui/native_theme/common_theme.cc
+++ b/ui/native_theme/common_theme.cc
@@ -70,6 +70,7 @@
     case NativeTheme::kColorId_ButtonColor:
     case NativeTheme::kColorId_DialogBackground:
     case NativeTheme::kColorId_BubbleBackground:
+    case NativeTheme::kColorId_NotificationDefaultBackground:
       return color_utils::AlphaBlend(SK_ColorWHITE, gfx::kGoogleGrey900, 0.04f);
     case NativeTheme::kColorId_DialogForeground:
       return gfx::kGoogleGrey500;
@@ -246,6 +247,7 @@
     case NativeTheme::kColorId_ButtonColor:
     case NativeTheme::kColorId_DialogBackground:
     case NativeTheme::kColorId_BubbleBackground:
+    case NativeTheme::kColorId_NotificationDefaultBackground:
       return SK_ColorWHITE;
     case NativeTheme::kColorId_DialogForeground:
       return gfx::kGoogleGrey700;
@@ -422,15 +424,21 @@
       return gfx::kGoogleBlue600;
 
     // Notification view
-    // TODO(crbug.com/1065604): Add support for dark mode.
-    case NativeTheme::kColorId_NotificationDefaultBackground:
     case NativeTheme::kColorId_NotificationPlaceholderIconColor:
       return SK_ColorWHITE;
     case NativeTheme::kColorId_NotificationActionsRowBackground:
-    case NativeTheme::kColorId_NotificationInlineSettingsBackground:
-      return SkColorSetRGB(0xee, 0xee, 0xee);
-    case NativeTheme::kColorId_NotificationLargeImageBackground:
-      return SkColorSetRGB(0xf5, 0xf5, 0xf5);
+    case NativeTheme::kColorId_NotificationInlineSettingsBackground: {
+      const SkColor bg = base_theme->GetSystemColor(
+          NativeTheme::kColorId_NotificationDefaultBackground, color_scheme);
+      // The alpha value here (0x14) is chosen to generate 0xEEE from 0xFFF.
+      return color_utils::BlendTowardMaxContrast(bg, 0x14);
+    }
+    case NativeTheme::kColorId_NotificationLargeImageBackground: {
+      const SkColor bg = base_theme->GetSystemColor(
+          NativeTheme::kColorId_NotificationDefaultBackground, color_scheme);
+      // The alpha value here (0x0C) is chosen to generate 0xF5F5F5 from 0xFFF.
+      return color_utils::BlendTowardMaxContrast(bg, 0x0C);
+    }
     case NativeTheme::kColorId_NotificationEmptyPlaceholderIconColor:
       return SkColorSetA(SK_ColorWHITE, 0x60);
     case NativeTheme::kColorId_NotificationEmptyPlaceholderTextColor:
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index d6fa761f..95095614 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -611,6 +611,7 @@
     case kColorId_TableBackgroundAlternate:
     case kColorId_TooltipBackground:
     case kColorId_ProminentButtonDisabledColor:
+    case kColorId_NotificationDefaultBackground:
       return system_colors_[SystemThemeColor::kWindow];
 
     // Window Text
diff --git a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
index ad0f3bb..1c5062651 100644
--- a/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
+++ b/ui/ozone/platform/wayland/gpu/wayland_surface_factory_unittest.cc
@@ -255,7 +255,7 @@
 
     // Prepare overlay plane.
     gl_surface->ScheduleOverlayPlane(
-        INT32_MIN, gfx::OverlayTransform::OVERLAY_TRANSFORM_FLIP_VERTICAL,
+        0, gfx::OverlayTransform::OVERLAY_TRANSFORM_FLIP_VERTICAL,
         gl_image.get(), window_->GetBounds(), {}, false, nullptr);
 
     std::vector<scoped_refptr<FakeGLImageNativePixmap>> gl_images;
@@ -452,10 +452,8 @@
     Sync();
   }
 
-  auto* root_surface = server_.GetObject<wl::MockSurface>(
-      window_->root_surface()->GetSurfaceId());
   auto* mock_primary_surface = server_.GetObject<wl::MockSurface>(
-      window_->primary_subsurface()->wayland_surface()->GetSurfaceId());
+      window_->root_surface()->GetSurfaceId());
 
   CallbacksHelper cbs_helper;
   // Submit a frame with only primary plane
@@ -490,11 +488,9 @@
 
   // Also, we expect only one buffer to be committed.
   EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
-  EXPECT_CALL(*root_surface, Commit()).Times(1);
 
   Sync();
 
@@ -550,15 +546,13 @@
 
   // Expect one buffer to be committed.
   EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
-  EXPECT_CALL(*root_surface, Commit()).Times(1);
 
   // Send the frame callback so that pending buffer for swap id=1u is processed
   // and swapped.
-  root_surface->SendFrameCallback();
+  mock_primary_surface->SendFrameCallback();
 
   Sync();
 
@@ -610,19 +604,15 @@
         base::BindOnce(&CallbacksHelper::BufferPresented,
                        base::Unretained(&cbs_helper), swap_id));
   }
-
-  // Do not expect parent surface to be committed.
+  // Expect parent surface to be committed without a buffer.
   EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(0);
-  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(0);
-  EXPECT_CALL(*mock_primary_surface, Commit()).Times(0);
-  // Expect root surface to be committed.
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
-  EXPECT_CALL(*root_surface, Commit()).Times(1);
+  EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
 
   // Send the frame callback so that pending buffer for swap id=2u is processed
   // and swapped.
-  root_surface->SendFrameCallback();
+  mock_primary_surface->SendFrameCallback();
 
   Sync();
 
@@ -701,10 +691,8 @@
     Sync();
   }
 
-  auto* root_surface = server_.GetObject<wl::MockSurface>(
-      window_->root_surface()->GetSurfaceId());
   auto* mock_primary_surface = server_.GetObject<wl::MockSurface>(
-      window_->primary_subsurface()->wayland_surface()->GetSurfaceId());
+      window_->root_surface()->GetSurfaceId());
 
   CallbacksHelper cbs_helper;
   // Submit a frame with 1 primary plane and 1 overlay
@@ -749,13 +737,11 @@
   // Let's sync so that 1) GbmSurfacelessWayland submits the buffer according to
   // internal queue and fake server processes the request.
 
-  // Also, we expect primary buffer to be committed.
+  // Also, we expect only one buffer to be committed.
   EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
-  EXPECT_CALL(*root_surface, Commit()).Times(1);
 
   Sync();
 
@@ -824,25 +810,21 @@
                        base::Unretained(&cbs_helper), swap_id));
   }
 
-  // Expect primary buffer to be committed.
+  // Expect one buffer to be committed.
   EXPECT_CALL(*mock_primary_surface, Attach(_, _, _)).Times(1);
-  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(0);
+  EXPECT_CALL(*mock_primary_surface, Frame(_)).Times(1);
   EXPECT_CALL(*mock_primary_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_primary_surface, Commit()).Times(1);
 
-  // Expect overlay buffer to be committed.
+  // Expect one buffer to be committed.
   EXPECT_CALL(*mock_overlay_surface, Attach(_, _, _)).Times(1);
   EXPECT_CALL(*mock_overlay_surface, Frame(_)).Times(0);
   EXPECT_CALL(*mock_overlay_surface, DamageBuffer(_, _, _, _)).Times(1);
   EXPECT_CALL(*mock_overlay_surface, Commit()).Times(1);
 
-  // Expect root surface to be committed without buffer.
-  EXPECT_CALL(*root_surface, Frame(_)).Times(1);
-  EXPECT_CALL(*root_surface, Commit()).Times(1);
-
   // Send the frame callback so that pending buffer for swap id=1u is processed
   // and swapped.
-  root_surface->SendFrameCallback();
+  mock_primary_surface->SendFrameCallback();
 
   Sync();
 
diff --git a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
index 954fb5b..5fa747f3 100644
--- a/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
+++ b/ui/ozone/platform/wayland/host/wayland_buffer_manager_host.cc
@@ -234,11 +234,9 @@
 
     // If the same buffer has been submitted again right after the client
     // received OnSubmission for that buffer, just damage the buffer and
-    // commit the surface again. However, if the buffer is released, it's safe
-    // to reattach the buffer.
+    // commit the surface again.
     if (submitted_buffers_.empty() ||
-        submitted_buffers_.back().buffer_id != buffer->buffer_id ||
-        buffer->released) {
+        submitted_buffers_.back().buffer_id != buffer->buffer_id) {
       // Once the BufferRelease is called, the buffer will be released.
       DCHECK(buffer->released);
       buffer->released = false;
@@ -925,21 +923,11 @@
       if (!surface->HasBuffers() && !surface->HasSurface())
         surfaces_.erase(window->root_surface());
     }
-    if (!destroyed_count) {
-      surface = GetSurface(window->primary_subsurface()->wayland_surface());
-      if (surface) {
-        destroyed_count = surface->DestroyBuffer(buffer_id);
-        if (!surface->HasBuffers() && !surface->HasSurface())
-          surfaces_.erase(window->root_surface());
-      }
-    }
-    if (!destroyed_count) {
-      const auto& subsurfaces = window->wayland_subsurfaces();
-      for (const auto& it : subsurfaces) {
-        Surface* subsurface = GetSurface((*it).wayland_surface());
-        if (subsurface)
-          destroyed_count += subsurface->DestroyBuffer(buffer_id);
-      }
+    const auto& subsurfaces = window->wayland_subsurfaces();
+    for (const auto& it : subsurfaces) {
+      Surface* subsurface = GetSurface((*it).wayland_surface());
+      if (subsurface)
+        destroyed_count += subsurface->DestroyBuffer(buffer_id);
     }
   } else {
     // Case 3)
diff --git a/ui/ozone/platform/wayland/host/wayland_subsurface.cc b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
index b2bee41..9b27f617 100644
--- a/ui/ozone/platform/wayland/host/wayland_subsurface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_subsurface.cc
@@ -19,11 +19,13 @@
                                  int32_t parent_buffer_scale) {
   // TODO(fangzhoug): Verify the correctness of using ui_scale here, and in
   // other ozone wayland files.
-  // Currently, the subsurface tree is at most 1 depth, gpu already sees buffer
-  // bounds in the root_surface-local coordinates. So translation is not
-  // needed for now.
+  const auto parent_bounds_dip =
+      gfx::ScaleToRoundedRect(parent_bounds_px, 1.0 / ui_scale);
   const auto bounds_dip = gfx::ScaleToRoundedRect(bounds_px, 1.0 / ui_scale);
-  return gfx::ScaleToRoundedRect(bounds_dip, ui_scale / parent_buffer_scale);
+  auto new_bounds_dip =
+      wl::TranslateBoundsToParentCoordinates(bounds_dip, parent_bounds_dip);
+  return gfx::ScaleToRoundedRect(new_bounds_dip,
+                                 ui_scale / parent_buffer_scale);
 }
 
 }  // namespace
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.cc b/ui/ozone/platform/wayland/host/wayland_surface.cc
index f3092c43..3cfccaa 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.cc
+++ b/ui/ozone/platform/wayland/host/wayland_surface.cc
@@ -7,7 +7,6 @@
 #include <viewporter-client-protocol.h>
 
 #include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/ozone/platform/wayland/common/wayland_util.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -97,6 +96,8 @@
   if (!display_size_px_.IsEmpty()) {
     viewport_dst =
         gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
+    wp_viewport_set_destination(viewport(), viewport_dst.width(),
+                                viewport_dst.height());
   }
 
   if (connection_->compositor_version() >=
@@ -158,14 +159,6 @@
 
   buffer_scale_ = new_scale;
   wl_surface_set_buffer_scale(surface_.get(), buffer_scale_);
-
-  if (!display_size_px_.IsEmpty()) {
-    gfx::Size viewport_dst =
-        gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
-    wp_viewport_set_destination(viewport(), viewport_dst.width(),
-                                viewport_dst.height());
-  }
-
   connection_->ScheduleFlush();
 }
 
@@ -207,10 +200,6 @@
     wp_viewport_set_destination(viewport(), -1, -1);
   }
   display_size_px_ = dest_size_px;
-  gfx::Size viewport_dst =
-      gfx::ScaleToCeiledSize(display_size_px_, 1.f / buffer_scale_);
-  wp_viewport_set_destination(viewport(), viewport_dst.width(),
-                              viewport_dst.height());
 }
 
 wl::Object<wl_subsurface> WaylandSurface::CreateSubsurface(
diff --git a/ui/ozone/platform/wayland/host/wayland_surface.h b/ui/ozone/platform/wayland/host/wayland_surface.h
index c026bc22..7747c6e 100644
--- a/ui/ozone/platform/wayland/host/wayland_surface.h
+++ b/ui/ozone/platform/wayland/host/wayland_surface.h
@@ -74,14 +74,10 @@
   // See:
   // https://cgit.freedesktop.org/wayland/wayland-protocols/tree/stable/viewporter/viewporter.xml
   // If |src_rect| is empty, the source rectangle is unset.
-  // Note this method does not send corresponding wayland requests until
-  // attaching the next buffer.
   void SetViewportSource(const gfx::RectF& src_rect);
 
   // Set the destination size of the associated wl_surface according to
   // |dest_size_px|, which should be in physical pixels.
-  // Note this method sends corresponding wayland requests immediately because
-  // it does not need a new buffer attach to take effect.
   void SetViewportDestination(const gfx::Size& dest_size_px);
 
   // Creates a wl_subsurface relating this surface and a parent surface,
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index ec28f73..567ff7f 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -47,8 +47,6 @@
 
   PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
 
-  connection_->wayland_window_manager()->RemoveSubsurface(
-      GetWidget(), primary_subsurface_.get());
   for (const auto& widget_subsurface : wayland_subsurfaces()) {
     connection_->wayland_window_manager()->RemoveSubsurface(
         GetWidget(), widget_subsurface.get());
@@ -353,12 +351,6 @@
   if (!OnInitialize(std::move(properties)))
     return false;
 
-  primary_subsurface_ = std::make_unique<WaylandSubsurface>(connection_, this);
-  if (!primary_subsurface_->surface())
-    return false;
-  connection_->wayland_window_manager()->AddSubsurface(
-      GetWidget(), primary_subsurface_.get());
-
   connection_->ScheduleFlush();
 
   PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
@@ -555,10 +547,6 @@
 
   size_t above = (overlays.end() - split) - num_primary_planes;
   size_t below = split - overlays.begin();
-
-  if (overlays.front()->z_order == INT32_MIN)
-    --below;
-
   // Re-arrange the list of subsurfaces to fit the |overlays|. Request extra
   // subsurfaces if needed.
   if (!ArrangeSubsurfaceStack(above, below))
@@ -571,14 +559,12 @@
     auto overlay_iter = split - 1;
     for (auto iter = subsurface_stack_below_.begin();
          iter != subsurface_stack_below_.end(); ++iter, --overlay_iter) {
-      if (overlays.front()->z_order == INT32_MIN
-              ? overlay_iter >= ++overlays.begin()
-              : overlay_iter >= overlays.begin()) {
+      if (overlay_iter >= overlays.begin()) {
         WaylandSurface* reference_above = nullptr;
         if (overlay_iter == split - 1) {
           // It's possible that |overlays| does not contain primary plane, we
           // still want to place relative to the surface with z_order=0.
-          reference_above = primary_subsurface_->wayland_surface();
+          reference_above = root_surface();
         } else {
           reference_above = (*std::next(iter))->wayland_surface();
         }
@@ -607,7 +593,7 @@
         if (overlay_iter == split + num_primary_planes) {
           // It's possible that |overlays| does not contain primary plane, we
           // still want to place relative to the surface with z_order=0.
-          reference_below = primary_subsurface_->wayland_surface();
+          reference_below = root_surface();
         } else {
           reference_below = (*std::prev(iter))->wayland_surface();
         }
@@ -627,22 +613,11 @@
   }
 
   if (num_primary_planes) {
-    primary_subsurface_->ConfigureAndShowSurface(
-        (*split)->transform, (*split)->crop_rect, (*split)->bounds_rect,
-        (*split)->enable_blend, nullptr, nullptr);
     connection_->buffer_manager_host()->CommitBufferInternal(
-        primary_subsurface_->wayland_surface(), (*split)->buffer_id,
-        (*split)->damage_region, /*wait_for_frame_callback=*/false);
-  }
-
-  root_surface_->SetViewportDestination(bounds_px_.size());
-  if (overlays.front()->z_order == INT32_MIN) {
-    connection_->buffer_manager_host()->CommitBufferInternal(
-        root_surface(), overlays.front()->buffer_id,
-        /*damage_region=*/gfx::Rect(0, 0, 1, 1),
+        root_surface(), (*split)->buffer_id, (*split)->damage_region,
         /*wait_for_frame_callback=*/true);
   } else {
-    // Subsurfaces are set to sync, above surface configs will only take effect
+    // Subsurfaces are set to sync, above operations will only take effects
     // when root_surface is committed.
     connection_->buffer_manager_host()->CommitWithoutBufferInternal(
         root_surface(), /*wait_for_frame_callback=*/true);
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 69ac955..cd9f1e9f 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -59,9 +59,6 @@
   void UpdateBufferScale(bool update_bounds);
 
   WaylandSurface* root_surface() const { return root_surface_.get(); }
-  WaylandSubsurface* primary_subsurface() const {
-    return primary_subsurface_.get();
-  }
   const WidgetSubsurfaceSet& wayland_subsurfaces() const {
     return wayland_subsurfaces_;
   }
@@ -230,18 +227,13 @@
   WaylandWindow* parent_window_ = nullptr;
   WaylandWindow* child_window_ = nullptr;
 
-  // |root_surface_| is a surface for the opaque background. Its z-order is
-  // INT32_MIN.
   std::unique_ptr<WaylandSurface> root_surface_;
-  // |primary_subsurface| is the primary that shows the widget content.
-  std::unique_ptr<WaylandSubsurface> primary_subsurface_;
-  // Subsurfaces excluding the primary_subsurface
   WidgetSubsurfaceSet wayland_subsurfaces_;
 
   // The stack of sub-surfaces to take effect when Commit() is called.
   // |subsurface_stack_above_| refers to subsurfaces that are stacked above the
-  // primary.
-  // Subsurface at the front of the list is the closest to the primary.
+  // parent.
+  // Subsurface at the front of the list is the closest to the parent.
   std::list<WaylandSubsurface*> subsurface_stack_above_;
   std::list<WaylandSubsurface*> subsurface_stack_below_;
 
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 44c0299..e4968f1 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -235,12 +235,6 @@
       properties->ignore_screen_bounds_for_menus = true;
       properties->app_modal_dialogs_use_event_blocker = true;
 
-      // Primary planes can be transluscent due to underlay strategy. As a
-      // result Wayland server draws contents occluded by an accelerated widget.
-      // To prevent this, an opaque background image is stacked below the
-      // accelerated widget to occlude contents below.
-      properties->needs_background_image = true;
-
       initialised = true;
     }
 
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h
index fd59031..764945e 100644
--- a/ui/ozone/public/ozone_platform.h
+++ b/ui/ozone/public/ozone_platform.h
@@ -104,10 +104,6 @@
     // calculating bounds of menu windows.
     bool ignore_screen_bounds_for_menus = false;
 
-    // Wayland only: determines whether BufferQueue needs a background image to
-    // be stacked below an AcceleratedWidget to make a widget opaque.
-    bool needs_background_image = false;
-
     // If true, the platform shows and updates the drag image.
     bool platform_shows_drag_image = true;
 
diff --git a/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html b/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html
index 11763c5..373e581 100644
--- a/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html
+++ b/ui/webui/resources/cr_elements/cr_search_field/cr_search_field.html
@@ -14,31 +14,39 @@
       :host {
         display: flex;
         user-select: none;
+        --cr-search-field-input-border-bottom: 1px solid var(--cr-secondary-text-color);
       }
 
       #searchIcon {
         align-self: center;
+        display: var(--cr-search-field-search-icon-display, inherit);
         height: 16px;
         padding: 4px;
         vertical-align: middle;
         width: 16px;
       }
 
+      #searchIconInline {
+        --iron-icon-fill-color: var(--cr-search-field-search-icon-fill, inherit);
+        display: var(--cr-search-field-search-icon-inline-display, none);
+        margin-inline-start: var(--cr-search-field-search-icon-inline-margin-start, 0);
+      }
+
       #searchInput {
         --cr-input-background-color: transparent;
-        --cr-input-border-bottom: 1px solid var(--cr-secondary-text-color);
+        --cr-input-border-bottom: var(--cr-search-field-input-border-bottom);
         --cr-input-border-radius: 0;
         --cr-input-error-display: none;
-        --cr-input-min-height: 24px;
+        --cr-input-min-height: var(--cr-search-field-input-min-height, 24px);
         --cr-input-padding-end: 0;
-        --cr-input-padding-start: 0;
-        --cr-input-padding-bottom: 2px;
-        --cr-input-padding-top: 2px;
+        --cr-input-padding-start: var(--cr-search-field-input-padding-start, 0);
+        --cr-input-padding-bottom: var(--cr-search-field-input-padding-bottom, 2px);
+        --cr-input-padding-top: var(--cr-search-field-input-padding-top, 2px);
         align-self: stretch;
         color: var(--cr-primary-text-color);
         display: block;
         font-size: 92.3076923%;  /* To 12px from 13px. */
-        width: var(--cr-search-field-search-input-width, 160px);
+        width: var(--cr-search-field-input-width, 160px);
       }
 
       :host([has-search-text]) #searchInput {
@@ -47,9 +55,10 @@
 
       #clearSearch {
         /* A 16px icon that fits on the input line. */
-        --cr-icon-button-icon-size: 16px;
+        --cr-icon-button-fill-color: var(--cr-search-field-clear-icon-fill, inherit);
+        --cr-icon-button-icon-size: var(--cr-search-field-clear-icon-size, 16px);
         --cr-icon-button-size: 24px;
-        margin-inline-end: -4px;
+        margin-inline-end: var(--cr-search-field-clear-icon-margin-end, -4px);
         margin-inline-start: 4px;
         position: absolute;
         right: 0;
@@ -64,6 +73,7 @@
     <cr-input id="searchInput" on-search="onSearchTermSearch"
         on-input="onSearchTermInput" aria-label$="[[label]]" type="search"
         autofocus="[[autofocus]]" placeholder="[[label]]" spellcheck="false">
+      <iron-icon id="searchIconInline" slot="inline-prefix" icon="cr:search"></iron-icon>
       <cr-icon-button id="clearSearch" class="icon-cancel"
           hidden$="[[!hasSearchText]]" slot="suffix" on-click="onTapClear_"
           title="[[clearLabel]]">